Android SystemUI 启动流程

SystemServer中启动

SystemServer启动后,会在Main Thread启动ActivityManagerService,当ActivityManagerService systemReady后,会去启动SystemUIService。

/frameworks/base/services/java/com/android/server/SystemServer.java

①main
    /**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }
②run
    private void run() {
        t.traceBegin("InitBeforeStartServices");
        ....
       // Create the system service manager.
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
        ....
       }
③mActivityManagerService.systemReady
mActivityManagerService.systemReady(() -> {
    //准备好服务
    Slog.i(TAG, "Making services ready");
    ....
            //跟踪开启系统界面
            t.traceBegin("StartSystemUI");
            try {
                //开启系统界面
                startSystemUi(context, windowManagerF);
            } catch (Throwable e) {
                reportWtf("starting System UI", e);
            }
            t.traceEnd();
    ....
}
④startSystemUi
    private static void startSystemUi(Context context, WindowManagerService windowManager) {
        PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
        Intent intent = new Intent();
        intent.setComponent(pm.getSystemUiServiceComponent());
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        //Slog.d(TAG, "Starting service: " + intent);
        //通过startServiceAsUser,SystemUIService就启动了,即SystemUI进程开机启动
        context.startServiceAsUser(intent, UserHandle.SYSTEM);
        windowManager.onSystemUiStarted();
    }

SystemUIService

在SystemUIService的onCreate方法中会调用SystemUIApplication的startServicesIfNeeded方法,这个方法会调用 startServicesIfNeeded(SERVICES)方法启动一系列服务.

@Override
    public void onCreate() {
        super.onCreate();
        // Start all of SystemUI
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();
  }

SystemUIApplication

/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java

①startServicesIfNeeded()
public void startServicesIfNeeded() {
    //获取所有的服务的路径,所有SERVICES统一继承了SystemUI类:
    String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
    startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
}
②startServicesIfNeeded(String metricsPrefix, String[] services)
在重载方法中将每一个名称通过反射来得到实例对象,然后依次调用每一个SystemUI的子类的start方法启动每一个模块。

private void startServicesIfNeeded(String metricsPrefix, String[] services) {
    if (mServicesStarted) {
        return;
    }
    mServices = new SystemUI[services.length];

    //检查一下,也许在我们开始之前很久它就已经完成了
    if (!mBootCompleteCache.isBootComplete()) {
        // check to see if maybe it was already completed long before we began
        // see ActivityManagerService.finishBooting()
        if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
            mBootCompleteCache.setBootComplete();
            if (DEBUG) {
                Log.v(TAG, "BOOT_COMPLETED was already sent");
            }
        }
    }

    final DumpManager dumpManager = mRootComponent.createDumpManager();

    Log.v(TAG, "Starting SystemUI services for user " +
            Process.myUserHandle().getIdentifier() + ".");
    TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
            Trace.TRACE_TAG_APP);
    //开始追踪
    log.traceBegin(metricsPrefix);
    final int N = services.length;
    //遍历services这个数组
    for (int i = 0; i < N; i++) {
        String clsName = services[i];
        if (DEBUG) Log.d(TAG, "loading: " + clsName);
        log.traceBegin(metricsPrefix + clsName);
        long ti = System.currentTimeMillis();
        try {
            SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
            if (obj == null) {
                Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
                obj = (SystemUI) constructor.newInstance(this);
            }
            mServices[i] = obj;
        } catch (ClassNotFoundException
                | NoSuchMethodException
                | IllegalAccessException
                | InstantiationException
                | InvocationTargetException ex) {
            throw new RuntimeException(ex);
        }

        if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
        //依次调用service的start方法启动服务
        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 " + clsName + " took " + ti + " ms");
        }
        if (mBootCompleteCache.isBootComplete()) {
            mServices[i].onBootCompleted();
        }

        dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
    }
    mRootComponent.getInitController().executePostInitTasks();
    //结束追踪
    log.traceEnd();

    mServicesStarted = true;
}

状态栏

StatusBar.start()

①createAndAddWindows
    public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
        //创建状态栏
        makeStatusBarView(result);
        mNotificationShadeWindowController.attach();
        //创建状态栏的窗口
        mStatusBarWindowController.attach();
    }
②makeStatusBarView
protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
    final Context context = mContext;
    .....
    FragmentHostManager.get(mPhoneStatusBarWindow)
            .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                //CollapsedStatusBarFragment 替换 status_bar_container(状态栏通知显示区域)
                CollapsedStatusBarFragment statusBarFragment =
                        (CollapsedStatusBarFragment) fragment;

                PhoneStatusBarView oldStatusBarView = mStatusBarView;
                mStatusBarView = (PhoneStatusBarView) statusBarFragment.getView();
                //传递statusBar处理下拉事件
                mStatusBarView.setBar(this);
                //传递 NotificationPanelView 显示下拉UI控制
                mStatusBarView.setPanel(mNotificationPanelViewController);
                mStatusBarView.setScrimController(mScrimController);
                //初始化通知栏区域
                statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
                ......
                    
            }).getFragmentManager()
            .beginTransaction()
            .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
                    CollapsedStatusBarFragment.TAG)
            .commit();
    .....

CollapsedStatusBarFragment

①createAndAddWindows
    public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
        //创建状态栏
        makeStatusBarView(result);
        mNotificationShadeWindowController.attach();
        //创建状态栏的窗口
        mStatusBarWindowController.attach();
    }
②makeStatusBarView
protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
    final Context context = mContext;
    .....
    FragmentHostManager.get(mPhoneStatusBarWindow)
            .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                //CollapsedStatusBarFragment 替换 status_bar_container(状态栏通知显示区域)
                CollapsedStatusBarFragment statusBarFragment =
                        (CollapsedStatusBarFragment) fragment;

                PhoneStatusBarView oldStatusBarView = mStatusBarView;
                mStatusBarView = (PhoneStatusBarView) statusBarFragment.getView();
                //传递statusBar处理下拉事件
                mStatusBarView.setBar(this);
                //传递 NotificationPanelView 显示下拉UI控制
                mStatusBarView.setPanel(mNotificationPanelViewController);
                mStatusBarView.setScrimController(mScrimController);
                //初始化通知栏区域
                statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
                ......
                    
            }).getFragmentManager()
            .beginTransaction()
            .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
                    CollapsedStatusBarFragment.TAG)
            .commit();
    .....
2、CollapsedStatusBarFragment
①onCreateView
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            Bundle savedInstanceState) {
        return inflater.inflate(R.layout.status_bar, container, false);
    }
②initNotificationIconArea
public void initNotificationIconArea(NotificationIconAreaController
        notificationIconAreaController) {
    //notification_icon_area是在status_bar.xml的布局,它是属于通知Notification    
    //获取到 notification_icon_area,FrameLayout转为ViewGroup,
    ViewGroup notificationIconArea = mStatusBar.findViewById(R.id.notification_icon_area);
    //调用 notificationIconAreaController 获取通知要显示的view(LinearLayout)
    //在4中跟进
    mNotificationIconAreaInner =
            notificationIconAreaController.getNotificationInnerAreaView();
    //如果已经有显示的view,通过 view 父布局将其自身remove,然后再重新addView。
    //最后将 mNotificationIconAreaInner 显示出来(设置透明度为1,visibility为VISIBLE)
    if (mNotificationIconAreaInner.getParent() != null) {
        ((ViewGroup) mNotificationIconAreaInner.getParent())
                .removeView(mNotificationIconAreaInner);
    }
    notificationIconArea.addView(mNotificationIconAreaInner);

    //与上面一样
    ViewGroup statusBarCenteredIconArea = mStatusBar.findViewById(R.id.centered_icon_area);
    mCenteredIconArea = notificationIconAreaController.getCenteredNotificationAreaView();
    if (mCenteredIconArea.getParent() != null) {
        ((ViewGroup) mCenteredIconArea.getParent())
                .removeView(mCenteredIconArea);
    }
    statusBarCenteredIconArea.addView(mCenteredIconArea);

    //默认为显示,直到我们知道其他情况
    // Default to showing until we know otherwise.
    showNotificationIconArea(false);
}
③showNotificationIconArea
当状态栏下拉时,状态栏中的图标icon会慢慢的变成透明和不可见,就是通过hideSystemIconArea(true), hideNotificationIconArea(true)

//当状态栏下拉时,设置状态栏中的图标icon会慢慢的变成透明和不可见    
public void hideNotificationIconArea(boolean animate) {
        animateHide(mNotificationIconAreaInner, animate);
        animateHide(mCenteredIconArea, animate);
    }
//设置状态栏图标透明度为1,visibility为VISIBLE
    public void showNotificationIconArea(boolean animate) {
        animateShow(mNotificationIconAreaInner, animate);
        animateShow(mCenteredIconArea, animate);
    }

    public void hideOperatorName(boolean animate) {
        if (mOperatorNameFrame != null) {
            animateHide(mOperatorNameFrame, animate);
        }
    }

    public void showOperatorName(boolean animate) {
        if (mOperatorNameFrame != null) {
            animateShow(mOperatorNameFrame, animate);
        }
④animateShow
    private void animateShow(View v, boolean animate) {
        v.animate().cancel();
        //(设置透明度为1,visibility为VISIBLE)
        v.setVisibility(View.VISIBLE);
        if (!animate) {
            v.setAlpha(1f);
            return;
        }
        .....
    }
⑤animateHiddenState
//将视图动画化为 INVISIBLE 或 GONE    
private void animateHiddenState(final View v, int state, boolean animate) {
        v.animate().cancel();
        if (!animate) {
            v.setAlpha(0f);
            v.setVisibility(state);
            return;
        }

        v.animate()
                .alpha(0f)
                .setDuration(160)
                .setStartDelay(0)
                .setInterpolator(Interpolators.ALPHA_OUT)
                .withEndAction(() -> v.setVisibility(state));
    }

status_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->

<!--    android:background="@drawable/status_bar_closed_default_background" -->
<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:orientation="vertical"
    android:focusable="false"
    android:descendantFocusability="afterDescendants"
    android:accessibilityPaneTitle="@string/status_bar"
    >

    <!-- add for KGDAANWIKFRA-135 -->
    <View
        android:layout_width="match_parent"
        android:layout_height="@dimen/status_bar_height"
        android:id="@+id/status_bar_dark_view"
        android:background="#ff000000"
        android:visibility="gone" />
    //<!--通知灯,默认gone-->
    <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:paddingTop="@dimen/status_bar_padding_top"
        android:orientation="horizontal"
        >
        <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"
            >
                <ViewStub
                    android:id="@+id/operator_name"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:layout="@layout/operator_name" />

                <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"
        />

        //居中的图标区域        
        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
            android:id="@+id/centered_icon_area"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            android:clipChildren="false"
            android:gravity="center_horizontal|center_vertical"/>

        <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>

NotificationIconAreaController

getNotificationInnerAreaView
    /**
     * Returns the view that represents the notification area.+
     * 返回表示通知区域的视图。
     */
    public View getNotificationInnerAreaView() {
        return mNotificationIconArea;
    }
initializeNotificationAreaViews
/**
 * Initializes the views that will represent the notification area.
 * 初始化将表示通知区域的视图。
 */
protected void initializeNotificationAreaViews(Context context) {
    reloadDimens(context);
    
    LayoutInflater layoutInflater = LayoutInflater.from(context);
    //通知图标区域布局
    mNotificationIconArea = inflateIconArea(layoutInflater);
    //通知图标
    mNotificationIcons = mNotificationIconArea.findViewById(R.id.notificationIcons);
    //获取通知滚动布局
    mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout();
    //中心图标区域布局
    mCenteredIconArea = layoutInflater.inflate(R.layout.center_icon_area, null);
    //居中的图标
    mCenteredIcon = mCenteredIconArea.findViewById(R.id.centeredIcon);

    initAodIcons();
}
inflateIconArea

    protected View inflateIconArea(LayoutInflater inflater) {
        return inflater.inflate(R.layout.notification_icon_area, null);
    }

status icon加载流程

1、 status_bar.xml

 <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
            android:id="@+id/centered_icon_area"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            android:clipChildren="false"
            android:gravity="center_horizontal|center_vertical"/>

        <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>

2、system_icons.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:systemui="http://schemas.android.com/apk/res-auto"
    android:id="@+id/system_icons"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical">
    //StatusIconContainer继承AlphaOptimizedLinearLayout
    <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"
        systemui:textAppearance="@style/TextAppearance.StatusBar.Clock" />
</LinearLayout>

3、AlphaOptimizedLinearLayout

 //该方法用来标记当前view是否存在过度绘制,存在返回ture,不存在返回false,
    //api里面默认返回为true,status icon不存在过度绘制。
    @Override
    public boolean hasOverlappingRendering() {
        return false;
    }

4、CollapsedStatusBarFragment

 @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mStatusBar = (PhoneStatusBarView) view;
        if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) {
            mStatusBar.restoreHierarchyState(
                    savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE));
        }
......
    }

5、StatusBarIconController

①DarkIconManager
    /**
     * Version of ViewGroup that observes state from the DarkIconDispatcher.
     */
    public static class DarkIconManager extends IconManager {
        private final DarkIconDispatcher mDarkIconDispatcher;
        private int mIconHPadding;

        public DarkIconManager(LinearLayout linearLayout, CommandQueue commandQueue) {
            super(linearLayout, commandQueue);
            mIconHPadding = mContext.getResources().getDimensionPixelSize(
                    R.dimen.status_bar_icon_padding);
            mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
        }
        //每个icon应该就是对应着代表顺序的index和数据类型为String的slot
        @Override
        protected void onIconAdded(int index, String slot, boolean blocked,
                StatusBarIconHolder holder) {
            StatusIconDisplayable view = addHolder(index, slot, blocked, holder);
            mDarkIconDispatcher.addDarkReceiver((DarkReceiver) view);
        }
        .....

        //onSetIcon可能就是刷新icon状态的
        @Override
        public void onSetIcon(int viewIndex, StatusBarIcon icon) {
            super.onSetIcon(viewIndex, icon);
            mDarkIconDispatcher.applyDark((DarkReceiver) mGroup.getChildAt(viewIndex));
        }
        .....

    }
②IconManager
public static class IconManager implements DemoMode {
    .....
    protected void onIconAdded(int index, String slot, boolean blocked,
        StatusBarIconHolder holder) {
        
        addHolder(index, slot, blocked, holder);
    }    
    
    protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked,
        StatusBarIconHolder holder) {
        switch (holder.getType()) {
            case TYPE_ICON:
                return addIcon(index, slot, blocked, holder.getIcon());
    
            case TYPE_WIFI:
                return addSignalIcon(index, slot, holder.getWifiState());
    
            case TYPE_MOBILE:
                return addMobileIcon(index, slot, holder.getMobileState());
        }
        return null;
    }
    
    @VisibleForTesting
    protected StatusBarIconView addIcon(int index, String slot, boolean blocked,
            StatusBarIcon icon) {
        
            StatusBarIconView view = onCreateStatusBarIconView(slot, blocked);
            view.set(icon);
            mGroup.addView(view, index, onCreateLayoutParams());
            return view;
    }
        .....
}

6、StatusBarIconControllerImpl

//继承StatusBarIconList
public class StatusBarIconControllerImpl extends StatusBarIconList implements Tunable,
        ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController {   
    ......        
    @Inject
    public StatusBarIconControllerImpl(Context context, CommandQueue commandQueue) {
        //config_statusBarIcons
        super(context.getResources().getStringArray(
                com.android.internal.R.array.config_statusBarIcons));
        Dependency.get(ConfigurationController.class).addCallback(this);
     .....
    }
}

7、StatusBarIconList

在初始化的时候就已经定义好了所有的slots,然后从framework中加载出来,index就是string-array中的顺序。

public class StatusBarIconList {
    private ArrayList<Slot> mSlots = new ArrayList<>();

    public StatusBarIconList(String[] slots) {
        final int N = slots.length;
        for (int i=0; i < N; i++) {
            mSlots.add(new Slot(slots[i], null));
        }
    }

8、config_statusBarIcons

<string-array name="config_statusBarIcons">
        <item><xliff:g id="id">@string/status_bar_rotate</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_headset</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_data_saver</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_ime</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_sync_failing</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_sync_active</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_location</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_nfc</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_tty</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_speakerphone</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_zen</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_mute</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_volume</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_ethernet</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_wifi</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_cdma_eri</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_data_connection</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_phone_evdo_signal</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_phone_signal</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_alarm_clock</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_secure</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_clock</xliff:g></item>
    </string-array>
 
    <string translatable="false" name="status_bar_rotate">rotate</string>
    <string translatable="false" name="status_bar_headset">headset</string>
    <string translatable="false" name="status_bar_data_saver">data_saver</string>
    <string translatable="false" name="status_bar_managed_profile">managed_profile</string>
    <string translatable="false" name="status_bar_ime">ime</string>
    <string translatable="false" name="status_bar_sync_failing">sync_failing</string>
    <string translatable="false" name="status_bar_sync_active">sync_active</string>
    <string translatable="false" name="status_bar_cast">cast</string>
    <string translatable="false" name="status_bar_hotspot">hotspot</string>
    <string translatable="false" name="status_bar_location">location</string>
    <string translatable="false" name="status_bar_bluetooth">bluetooth</string>
    <string translatable="false" name="status_bar_nfc">nfc</string>
    <string translatable="false" name="status_bar_tty">tty</string>
    <string translatable="false" name="status_bar_speakerphone">speakerphone</string>
    <string translatable="false" name="status_bar_zen">zen</string>
    <string translatable="false" name="status_bar_mute">mute</string>
    <string translatable="false" name="status_bar_volume">volume</string>
    <string translatable="false" name="status_bar_wifi">wifi</string>
    <string translatable="false" name="status_bar_cdma_eri">cdma_eri</string>
    <string translatable="false" name="status_bar_data_connection">data_connection</string>
    <string translatable="false" name="status_bar_phone_evdo_signal">phone_evdo_signal</string>
    <string translatable="false" name="status_bar_phone_signal">phone_signal</string>
    <string translatable="false" name="status_bar_battery">battery</string>
    <string translatable="false" name="status_bar_alarm_clock">alarm_clock</string>
    <string translatable="false" name="status_bar_secure">secure</string>
    <string translatable="false" name="status_bar_clock">clock</string>
    <string translatable="false" name="status_bar_mobile">mobile</string>
    <string translatable="false" name="status_bar_vpn">vpn</string>
    <string translatable="false" name="status_bar_ethernet">ethernet</string>
    <string translatable="false" name="status_bar_airplane">airplane</string>
滚动至顶部