SystemUI

       SystemUI是Android为用户提供系统级别的信息显示与交互的一套UI组件,它包含屏幕顶端的状态栏,底部的导航栏,图片壁纸及RecentPanel(近期使用的APP).SystemUI的表现形式与普通应用类似,也是以一个APK的形式存在于系统之中。其中比较特殊的是状态栏和导航栏的启动方式,它们运行在一个SystemUIService中。现以导航栏的启动方式为例。 如下:

SystemServer.javastatic final void startSystemUi(Context context) {    Intent intent = new Intent();    intent.setComponent(new ComponentName("com.android.systemui",                "com.android.systemui.SystemUIService"));    //Slog.d(TAG, "Starting service: " + intent);    context.startServiceAsUser(intent, UserHandle.OWNER);}
public class SystemUIService extends Service {    @Override    public void onCreate() {        super.onCreate();        ((SystemUIApplication) getApplication()).startServicesIfNeeded();        //获取Application调用startServicesIfNeeded    }/*打印堆栈信息*/    @Override    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {        SystemUI[] services = ((SystemUIApplication) getApplication()).getServices();        if (args == null || args.length == 0) {            for (SystemUI ui: services) {                pw.println("dumping service: " + ui.getClass().getName());                ui.dump(fd, pw, args);            }        } else {            String svc = args[0];            for (SystemUI ui: services) {                String name = ui.getClass().getName();                if (name.endsWith(svc)) {                    ui.dump(fd, pw, args);                }            }        }    }}

分析:1 是启动SystemUIApplication 2 是打印堆栈信息

SystemUIApplication.java@Overridepublic void onCreate() {    super.onCreate();    // Set the application theme that is inherited by all services. Note that setting the    // application theme in the manifest does only work for activities. Keep this in sync with    // the theme set there.    setTheme(R.style.systemui_theme);    //注释广播    IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);    filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);    registerReceiver(new BroadcastReceiver() {        @Override        public void onReceive(Context context, Intent intent) {            //开启直接返回            if (mBootCompleted) return;            if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");            unregisterReceiver(this);            //标记启动            mBootCompleted = true;            //服务是否启动            if (mServicesStarted) {                final int N = mServices.length;                for (int i = 0; i < N; i++) {                    //回调各服务的onBootCompleted函数                    mServices[i].onBootCompleted();                }            }        }    }, filter);}

分析: 1设置主题  2 注册开机广播,及设置标志位

SystemUIApplication.javapublic void startServicesIfNeeded() {    if (mServicesStarted) {        return;    }    if (!mBootCompleted) {        // check to see if maybe it was already completed long before we began        // see ActivityManagerService.finishBooting()        //获取系统文件中的sys.boot_completed的值        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.");    final int N = SERVICES.length;    for (int i=0; i cl = SERVICES[i];        if (DEBUG) Log.d(TAG, "loading: " + cl);        //实例化各个类实例,放入mServices数组中        try {            mServices[i] = (SystemUI)cl.newInstance();        } 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();        if (mBootCompleted) {            mServices[i].onBootCompleted();        }    }    //服务启动标志    mServicesStarted = true;}

     分析:这个方法中,首先判断mServicesStarted标志为来判断SystemUI相关的服务是否启动,同时根据系统配置文件来检查ActivityManagerService是否finishBooting,然后通过类加载机制来初始化SERVICES数组里面相关的类加入mServices中,然后start。

SystemUIApplication.java /** * The classes of the stuff to start. */private final Class<?>[] SERVICES = new Class[] {        com.android.systemui.tuner.TunerService.class,//定制状态栏服务        com.android.systemui.keyguard.KeyguardViewMediator.class,//锁屏相关        com.android.systemui.recents.Recents.class,//近期任务        com.android.systemui.volume.VolumeUI.class,//音量条        com.android.systemui.statusbar.SystemBars.class,//状态栏        com.android.systemui.usb.StorageNotification.class,//通知栏        com.android.systemui.power.PowerUI.class,//电源相关        com.android.systemui.media.RingtonePlayer.class,//铃声播放相关};/** * Hold a reference on the stuff we start. */private final SystemUI[] mServices = new SystemUI[SERVICES.length];

     分析:从mServices和SERVICES的定义可以发现SERVICES是一组包含全路径的相关的类,这些类包含一些我们常见的TunerService(定制状态栏服务)、 KeyguardViewMediator(锁屏相关)、Recents(近期任务)、VolumeUI(音量条)、SystemBars(状态栏)、StorageNotification(通知栏)、PowerUI(电源相关)、RingtonePlayer(铃声播放相关)类,它们都是继承与SystemUI抽象类,现在只分析StatusBar相关的SystemBars类。

com.android.systemui.statusbarSystemBars.javapublic class SystemBars extends SystemUI implements ServiceMonitor.Callbacks {    private static final String TAG = "SystemBars";    private static final boolean DEBUG = false;    private static final int WAIT_FOR_BARS_TO_DIE = 500;    // manages the implementation coming from the remote process    private ServiceMonitor mServiceMonitor;    // in-process fallback implementation, per the product config    private BaseStatusBar mStatusBar;    @Override    public void start() {        if (DEBUG) Log.d(TAG, "start");        //实例化ServiceMonitor        mServiceMonitor = new ServiceMonitor(TAG, DEBUG,                mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);        //start        mServiceMonitor.start();  // will call onNoService if no remote service is found    }    /*服务没启动时,ServiceMonitor会回调onNoService*/    @Override    public void onNoService() {        if (DEBUG) Log.d(TAG, "onNoService");        createStatusBarFromConfig();  // fallback to using an in-process implementation    }    /*服务已经启动的回调*/    @Override    public long onServiceStartAttempt() {        if (DEBUG) Log.d(TAG, "onServiceStartAttempt mStatusBar="+mStatusBar);        if (mStatusBar != null) {            // tear down the in-process version, we'll recreate it again if needed            mStatusBar.destroy();            mStatusBar = null;            return WAIT_FOR_BARS_TO_DIE;        }        return 0;    }    /*系统配置改变*/    @Override    protected void onConfigurationChanged(Configuration newConfig) {        if (mStatusBar != null) {            mStatusBar.onConfigurationChanged(newConfig);        }    }    /*打印堆栈*/    @Override    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {        if (mStatusBar != null) {            mStatusBar.dump(fd, pw, args);        }    }    /*从xml文件中获取PhoneStatusBar全路径,通过类加载器实例化类,调用其start*/    private void createStatusBarFromConfig() {        if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");        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 {            cls = mContext.getClassLoader().loadClass(clsName);        } catch (Throwable t) {            throw andLog("Error loading status bar component: " + clsName, t);        }        try {            mStatusBar = (BaseStatusBar) 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());    }    private RuntimeException andLog(String msg, Throwable t) {        Log.w(TAG, msg, t);        throw new RuntimeException(msg, t);    }}

我们先从start方法开始分析

 @Override    public void start() {        if (DEBUG) Log.d(TAG, "start");        mServiceMonitor = new ServiceMonitor(TAG, DEBUG,                mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);        mServiceMonitor.start();  // will call onNoService if no remote service is found    }

这里实例化ServiceMonitor类start,继续分析ServiceMonitor

ServiceMonitor.java    ...    public ServiceMonitor(String ownerTag, boolean debug,            Context context, String settingKey, Callbacks callbacks) {        mTag = ownerTag + ".ServiceMonitor";        mDebug = debug;        mContext = context;        mSettingKey = settingKey; // Settings.Secure.BAR_SERVICE_COMPONENT        mCallbacks = callbacks;    }    public void start() {        // listen for setting changes        /*Settings.Secure.BAR_SERVICE_COMPONENT改变时回调*/        ContentResolver cr = mContext.getContentResolver();        cr.registerContentObserver(Settings.Secure.getUriFor(mSettingKey),                false /*notifyForDescendents*/, mSettingObserver, UserHandle.USER_ALL);        // listen for package/component changes        //应用安装,改变,卸载会触发mBroadcastReceiver广播        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);        mHandler.sendEmptyMessage(MSG_START_SERVICE);    }    ...

     ServiceMOnitor是一个监听Settings.Secure.BAR_SERVICE_COMPONENT是否改变的类,在start中通过监听系统系统时应用的变化来启动服务。

private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {    public void onReceive(Context context, Intent intent) {        String pkg = intent.getData().getSchemeSpecificPart();        if (mServiceName != null && mServiceName.getPackageName().equals(pkg)) {            mHandler.sendMessage(mHandler.obtainMessage(MSG_PACKAGE_INTENT, intent));        }    }};

 

ServiceMOnitor.java应用装载时,通过Handler发送MSG_PACKAGE_INTENT消息事件,我们查看Handler消息回调    // internal handler + messages used to serialize access to internal state    public static final int MSG_START_SERVICE = 1; //启动服务,并非真正启动,会根据ServiceName进行判断    public static final int MSG_CONTINUE_START_SERVICE = 2; //启动服务    public static final int MSG_STOP_SERVICE = 3;//停止服务消息    public static final int MSG_PACKAGE_INTENT = 4;//包安装事件消息    public static final int MSG_CHECK_BOUND = 5;//包改变或者卸载时,重新启动服务消息    public static final int MSG_SERVICE_DISCONNECTED = 6;//服务断开消息    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 packageIntent(Intent intent) {        if (mDebug) Log.d(mTag, "packageIntent intent=" + intent                + " extras=" + bundleToString(intent.getExtras()));        if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {            mHandler.sendEmptyMessage(MSG_START_SERVICE);//发送启动服务消息        } else if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())                || Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {            final PackageManager pm = mContext.getPackageManager();            final boolean serviceEnabled = isPackageAvailable()                    && pm.getApplicationEnabledSetting(mServiceName.getPackageName())                            != PackageManager.COMPONENT_ENABLED_STATE_DISABLED                    && pm.getComponentEnabledSetting(mServiceName)                            != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;            if (mBound && !serviceEnabled) {                stopService();                scheduleCheckBound();            } else if (!mBound && serviceEnabled) {                startService();            }        }    }

分析:当我们SystemUI应用检测到有新应用装载时,会发送MSG_START_SERVICE消息来启动服务,我们接着分析Handler的回调MSG_START_SERVICE消息。

 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);        }    }    /*从ContentProvider数据库中取得包名*/    private ComponentName getComponentNameFromSetting() {        String cn = Settings.Secure.getStringForUser(mContext.getContentResolver(),                mSettingKey, UserHandle.USER_CURRENT);        return cn == null ? null : ComponentName.unflattenFromString(cn);    }

分析:首先从ContentProvider数据库中取得包名,如果没有启动,则回调CallBaback的onNoService服务,否则发送MSG_CONTINUE_START_SERVICE消息启动服务.

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();        }    }

分析:到此可以知道,当远程服务没有启动时,会回调SystemBar的onNoService函数,我们回到SystemBar,分析onNoService函数

...     @Override        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");        final String clsName = mContext.getString(R.string.config_statusBarComponent);//从xml文件读取类名        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 = (BaseStatusBar) cls.newInstance();        } catch (Throwable t) {            throw andLog("Error creating status bar component: " + clsName, t);        }        mStatusBar.mContext = mContext;        mStatusBar.mComponents = mComponents;        mStatusBar.start();//调用类的start方法        if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());    }

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

res\values\config.xml        com.android.systemui.statusbar.phone.PhoneStatusBar

分析:从上面分析得知,当实例化PhoneStatusBar类后会调用start方法,我们就从PhoneStatusBar的start方法开始.

  @Override    public void start() {        //获取WindowManager,初始化当前显示界面大小        mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))                .getDefaultDisplay();        updateDisplaySize();        //src绘图模式        mScrimSrcModeEnabled = mContext.getResources().getBoolean(                R.bool.config_status_bar_scrim_behind_use_src);        //调用父类start方法        super.start(); // calls createAndAddWindows()        //MediaSession相关        mMediaSessionManager                = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);        // TODO: use MediaSessionManager.SessionListener to hook us up to future updates        // in session state        //添加导航栏        addNavigationBar();        // Lastly, call to the icon policy to install/update all the icons.        //更新状态栏图标        mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController,                mUserInfoController, mBluetoothController);        mIconPolicy.setCurrentUserSetup(mUserSetup);        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();        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost);        putComponent(DozeHost.class, mDozeServiceHost);        putComponent(PhoneStatusBar.class, this);        /// M:add for multi window @{        if(MultiWindowProxy.isSupported()) {            registerMWProxyAgain();        }        /// @}        setControllerUsers();        notifyUserAboutHiddenNotifications();        mScreenPinningRequest = new ScreenPinningRequest(mContext);    }    ...

接着分析PhoneStatusBar父类的BaseStatusBar的start方法

public abstract class BaseStatusBar extends SystemUI implements        CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,        RecentsComponent.Callbacks, ExpandableNotificationRow.ExpansionLogger,        NotificationData.Environment {public void start() {    Log.d(TAG, "[*zxDebug*] BaseStatusBar start()");        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);      mBarService = IStatusBarService.Stub.asInterface(                ServiceManager.getService(Context.STATUS_BAR_SERVICE));        mRecents = getComponent(RecentsComponent.class);        mRecents.setCallback(this);        final Configuration currentConfig = mContext.getResources().getConfiguration(); StatusBarIconList iconList = new StatusBarIconList();        mCommandQueue = new CommandQueue(this, iconList);        int[] switches = new int[8];        ArrayList binders = new ArrayList();        try {            mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders);        } catch (RemoteException ex) {            // If the system process isn't there we're doomed anyway.        }                Log.d(TAG, "[*zxDebug*] BaseStatusBar start() begin createAndAddWindows");        createAndAddWindows();        Log.d(TAG, "[*zxDebug*] BaseStatusBar start() over createAndAddWindows");        disable(switches[0], false /* animate */);        setSystemUiVisibility(switches[1], 0xffffffff);        topAppWindowChanged(switches[2] != 0);        // StatusBarManagerService has a back up of IME token and it's restored here.        setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);...}}

分析:BaseStatusBar关于StatusBar相关的最主要是调用了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();

     分析:这是一个抽象方法,也就是说,它会回调到子类的createAndAddWindows的实现方法中,我们重新回到PhoneStatusBar中,找到createAndAddWindows的方法实现

@Override    public void createAndAddWindows() {        addStatusBarWindow();    }    private void addStatusBarWindow() {        makeStatusBarView();//创建statusbar视图        mStatusBarWindowManager = new StatusBarWindowManager(mContext);        //通过StatusBarWindowManager类的add方法加载到Window窗体中        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());    }    ...    protected PhoneStatusBarView makeStatusBarView() {        final Context context = mContext;        //通过Resources更新显示大小和一些资源文件        Resources res = context.getResources();        updateDisplaySize(); // populates mDisplayMetrics        updateResources();        //加载StartBarWindowView视图        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,                R.layout.super_status_bar, null);        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);            }        });        //状态栏        mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);        mStatusBarView.setBar(this);        //        PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);        mStatusBarView.setPanelHolder(holder);        //通知栏        mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(                R.id.notification_panel);        mNotificationPanel.setStatusBar(this);        //  M: setBackground in 512 low ram device        if (!ActivityManager.isHighEndGfx() && !FeatureOptions.LOW_RAM_SUPPORT) {            mStatusBarWindow.setBackground(null);            mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(                    R.color.notification_panel_solid_background)));        }  try {            //是否显示导航栏            boolean showNav = mWindowManagerService.hasNavigationBar();             Log.v(TAG, "hasNavigationBar=" + showNav);            if (showNav) {                /// M: add for multi window @{                //加载导航栏布局                int layoutId = R.layout.navigation_bar;                if(MultiWindowProxy.isSupported()) {                    layoutId = R.layout.navigation_bar_float_window;                }                mNavigationBarView = (NavigationBarView) View.inflate(context,                        /*R.layout.navigation_bar*/layoutId, null);                /// @}                mNavigationBarView.setDisabledFlags(mDisabled1);                mNavigationBarView.setBar(this);                mNavigationBarView.setOnVerticalChangedListener(                        new NavigationBarView.OnVerticalChangedListener() {                    @Override                    public void onVerticalChanged(boolean isVertical) {                        if (mAssistManager != null) {                            mAssistManager.onConfigurationChanged();                        }                        mNotificationPanel.setQsScrimEnabled(!isVertical);                    }                });                //设置导航栏触摸事件                mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {                    @Override                    public boolean onTouch(View v, MotionEvent event) {                        checkUserAutohide(v, event);                        return false;                    }});            }        } catch (RemoteException ex) {            // no window manager? good luck with that        }        mAssistManager = new AssistManager(this, context);        // figure out which pixel-format to use for the status bar.        mPixelFormat = PixelFormat.OPAQUE;.....

       分析:关键部分是在判断导航栏是否显示那一块。由mWindowManagerService的hasNavigationBar来决定是否显示导航栏,同时通过加载navigation_bar(多窗口加载navigation_bar_float_window)布局来显示导航栏,我们来查看hasNavigationBar方法,因为mWidnwoManagerService是IWindowManagerService由PhoneWindowManager进行调用: 

frameworks\base\service\core\java\com\android\server\PhoneWindowManager.javaPhoneWindowManager    ...    // Use this instead of checking config_showNavigationBar so that it can be consistently    // overridden by qemu.hw.mainkeys in the emulator.    @Override    public boolean hasNavigationBar() {        return mHasNavigationBar;    }    ...    mHasNavigationBar = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);    // Allow a system property to override this. Used by the emulator.    // See also hasNavigationBar().    String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");    if ("1".equals(navBarOverride)) {         mHasNavigationBar = false;     } else if ("0".equals(navBarOverride)) {         mHasNavigationBar = true;    }    ...从framework\base\core\res\res\valuse\config.xml中获取mHashNavigationBar的值        ture

分析:这里给我们提供一个方法去控制导航栏是否显示。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

更多相关文章

  1. [Android] ListView (普通列表控件) 的基本使用方法
  2. Google Cloud Messaging (Android 消息推送技术) (一)
  3. JS调用Android里面的方法,Android调用JS里面的方法
  4. Android App多个入口的实现方法
  5. Android 项目导入eclipse中报错但找不到错误地方的解决方法
  6. Linux ubuntu repo安装方法

随机推荐

  1. Android(安卓)资源加载机制详解
  2. Android之ListActivity:布局与数据绑定
  3. Android(安卓)KTX举例
  4. android 支付宝支付
  5. Vitamio简要介绍
  6. android串口通信
  7. Android中解析XML
  8. Android(安卓)button原理 转载
  9. Android图片异步加载之Android-Universal
  10. Android(安卓)之 Looper Handler Message