我們知道當Android系統啟動的時候會啟動SystemServer,其中系統的主要服務都是通過它來啟動的,本文就從這里開始一步一步研究系統狀態欄和導航欄是怎么啟動的。
首先我們先定位到SystemServer.run()方法中來,如下是方法的定義。
private void run() {
try {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitBeforeStartServices");
? ? ? ? .......
? ? ? ?........
? ? ? ?..........
? ? ? ? // Initialize the system context.
//創建系統上下文
? ? ? ? createSystemContext();
? ? ? ? // Create the system service manager.
? ? ? ? mSystemServiceManager =new SystemServiceManager(mSystemContext);
? ? ? ? LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
? ? }finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
? ? }
// Start services.
? ? try {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
? ? ? ? startBootstrapServices();
? ? ? ? startCoreServices();
? ? ? ? startOtherServices();
? ? .......
? ? ........
}
方法里面的內容比較多,我就列出主要的幾個地方.
startBootstrapServices,startCoreServices,startOtherServices這個三個方法都是啟動系統服務的,我們的系統狀態欄和導航欄就是通過startOtherServices這個方法來間接啟動的。
如下是方法的定義,當然也是列出我們主要關注的部分
private void startOtherServices() {
......
......
.......
//系統啟動時候調用ActivityManagerService的systemReady方法
mActivityManagerService.systemReady(new Runnable() {
@Override
? ? public void run() {
Slog.i(TAG, "Making services ready");
? ? ? ? mSystemServiceManager.startBootPhase(
SystemService.PHASE_ACTIVITY_MANAGER_READY);
? ? ? ? Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PhaseActivityManagerReady");
? ? ? ? Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartObservingNativeCrashes");
? ? ? ? try {
mActivityManagerService.startObservingNativeCrashes();
? ? ? ? }catch (Throwable e) {
reportWtf("observing native crashes", e);
? ? ? ? }
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
? ? ? ? if (!mOnlyCore) {
Slog.i(TAG, "WebViewFactory preparation");
? ? ? ? ? ? Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WebViewFactoryPreparation");
? ? ? ? ? ? mWebViewUpdateService.prepareWebViewInSystemServer();
? ? ? ? ? ? Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
? ? ? ? }
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartSystemUI");
? ? ? ? try {
startSystemUi(context);
? ? ? ? }catch (Throwable e) {
reportWtf("starting System UI", e);
? ? ? ? }
.......
......
.......
}
上面我們可以看到mActivityManagerService.systemReady,該方法里面會調用這個方法,這個是ActivityManagerService的方法,有名字就可以知道他是做一些系統啟動的操作,在方法定義里面我們可以看到startSystemUi這個方法,點進去看看,方法的定義如下。
static final void startSystemUi(Context context) {
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);
}
我們看到他是通過Intent啟動SystemUIService這個類,看名字就可以知道他是一個服務。
我們進入這個類的onCreate方法看看,
@Override
public void onCreate() {
super.onCreate();
? ? ((SystemUIApplication) getApplication()).startServicesIfNeeded();
}
我們看到他只調用了一個方法,我們接著點進去看看,
public void startServicesIfNeeded() {
startServicesIfNeeded(SERVICES);
}
SERVICES變量是個static,final類型的變量,
我們接著點進去看看
private void startServicesIfNeeded(Class[] services) {
if (mServicesStarted) {
return;
? ? }
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() +".");
? ? final int N = services.length;
? ? for (int i=0; i
Class cl = services[i];
? ? ? ? if (DEBUG) Log.d(TAG, "loading: " + cl);
? ? ? ? try {
Object newService = SystemUIFactory.getInstance().createInstance(cl);
? ? ? ? ? ? mServices[i] = (SystemUI) ((newService ==null) ? cl.newInstance() : newService);
? ? ? ? }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;
}
他的主要作用就是遍歷SERVICES數組,啟動里面的所有服務,如下是SERVICES數組的定義。
/**
* 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,
? ? ? ? Divider.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,
? ? ? ? com.android.systemui.keyboard.KeyboardUI.class,
? ? ? ? com.android.systemui.tv.pip.PipUI.class,
? ? ? ? com.android.systemui.shortcut.ShortcutKeyDispatcher.class,
? ? ? ? com.android.systemui.VendorServices.class
};
我們看到這個數組里面定義了很多的服務(其實它們都不是服務,全是SystemUI),其中SystemBars就是我們今天要關注的服務,因為Android系統的狀態欄和導航欄就是在這里面啟動的。
從上面我們可以知道,在遍歷初始化數組里面的類后,先調用了他們的start(),,如果系統啟動完成了就會調用onBootCompleted()方法。我們先看看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
}
我們可以看到它是實例化了一個對象并且調用的它的start方法。
我們先看看它的構造方法
public ServiceMonitor(String ownerTag, boolean debug,
? ? ? ? Context context, String settingKey, Callbacks callbacks) {
mTag = ownerTag +".ServiceMonitor";
mDebug = debug;
mContext = context;
mSettingKey = settingKey;
mCallbacks = callbacks;
}
我們看到構造方法只是做了一個初始化操作,我們接著進入它的start方法。
public void start() {
// listen for setting changes
? ? ContentResolver cr =mContext.getContentResolver();
? ? cr.registerContentObserver(Settings.Secure.getUriFor(mSettingKey),
? ? ? ? ? ? false /*notifyForDescendents*/, mSettingObserver, UserHandle.USER_ALL);
? ? // listen for package/component changes
? ? IntentFilter filter =new IntentFilter();
? ? filter.addAction(Intent.ACTION_PACKAGE_ADDED);
? ? filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
? ? filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
? ? filter.addDataScheme("package");
? ? mContext.registerReceiver(mBroadcastReceiver, filter);
? ? mHandler.sendEmptyMessage(MSG_START_SERVICE);
}
我們看到這個方法里面主要做了兩件事情,一個就是注冊廣播監聽安裝包的添加,改變,移除,另外一件事情就是發送消息。所以我們進入handler去看看,它是怎么處理這條空消息的,
case MSG_START_SERVICE:
startService();
? ? break;
我們看到它調用了startService方法,我們接著點進去看看
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);
? ? }
}
我們看到當mServiceName為null的時候會執行這個mCallbacks.onNoService()方法,由上面介紹的該類初始化我們知道這個回掉接口是從SystemBars傳過來的,我們回到SystemBars類找到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");
//從xml文件獲取到類名
? ? 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;
//調用它的start方法
? ? mStatusBar.start();
? ? if (DEBUG) Log.d(TAG, "started " +mStatusBar.getClass().getSimpleName());
}
這里xml定義的類名是PhoneStatusBar,我們直接進入它的start方法
@Override
public void start() {
//獲取屏幕信息Display對象,里面保存了和屏幕有關的所有信息
mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
//這個方法的作用是將屏幕的信息置為默認值。
.getDefaultDisplay();
//更新屏幕信息
? ? updateDisplaySize();
? ? mScrimSrcModeEnabled = mContext.getResources().getBoolean(
R.bool.config_status_bar_scrim_behind_use_src);
//這里面主要做了兩件事,一個是初始化,一個是注冊廣播監聽器
? ? super.start(); // calls createAndAddWindows()
? ? 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.
//這是PhoneStatusBar的代理對象,一看就知道這里采用了代理模式
? ? mIconPolicy =new PhoneStatusBarPolicy(mContext, mIconController, mCastController,
? ? ? ? ? ? mHotspotController, mUserInfoController, mBluetoothController,
? ? ? ? ? ? mRotationLockController, mNetworkController.getDataSaverController());
? ? 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();
? ? KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
? ? mDozeServiceHost =new DozeServiceHost();
? ? putComponent(DozeHost.class, mDozeServiceHost);
? ? putComponent(PhoneStatusBar.class, this);
? ? setControllerUsers();
? ? notifyUserAboutHiddenNotifications();
? ? mScreenPinningRequest =new ScreenPinningRequest(mContext);
? ? mFalsingManager = FalsingManager.getInstance(mContext);
}
,我們看到上面調用了super.start()方法,我們的狀態欄就是在這里初始化的,我們進入這個方法定義
public void start() {?
?mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);?
?mWindowManagerService = WindowManagerGlobal.getWindowManagerService();?
?mDisplay = mWindowManager.getDefaultDisplay();?
?mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService( Context.DEVICE_POLICY_SERVICE);?
?mNotificationData = new NotificationData(this);?
.........
.........
.......
? ? ? ? createAndAddWindows();
.........
.........
.......
? ? }
中間省略了大部分代碼,我們主要看createAndAddWindows這個方法,看方法名稱就可以知道,這個類是的功能是創建視圖并且添加到window窗口,一下是方法的定義
@Override
? ? public void createAndAddWindows() {
? ? ? ? addStatusBarWindow();
? ? }
接著我們進入addStatusBarWindow這個方法,
private void addStatusBarWindow() {
//這個類主要是創建了系統狀態欄,并且設置了一些監聽器,比如狀態欄的手勢事件,電池電量改變監聽器,sim卡狀態改變監聽器等等。
? ? ? ? makeStatusBarView();
? ? ? ? mStatusBarWindowManager = new StatusBarWindowManager(mContext);
? ? ? ? mRemoteInputController = new RemoteInputController(mStatusBarWindowManager,
? ? ? ? ? ? ? ? mHeadsUpManager);
//getStatusBarHeight這個方法是從xml中獲取已經定義好的狀態欄高度值,mStatusBarWindowManager.add這個方法的作用是將狀態欄添加到Window中
? ? ? ? mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
? ? }
到此系統狀態欄的創建流程就結束了,但是狀態欄的手勢事件是在哪里監聽的呢,下面就來研究下手勢狀態欄手勢事件的監聽流程
由上面我們可以知道在添加狀態欄的方法addStatusBarWindow中有個創建狀態欄的方法makeStatusBarView,我們進入這個方法查看下,方法定義如下
protected PhoneStatusBarView makeStatusBarView() {
? ? ? ? final Context context = mContext;
? ? ? ? updateDisplaySize(); // populates mDisplayMetrics
? ? ? ? updateResources();
? ? ? ? inflateStatusBarWindow(context);
? ? ? ? mStatusBarWindow.setService(this);
? ? ? ? mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public boolean onTouch(View v, MotionEvent event) {
? ? ? ? ? ? ? ? checkUserAutohide(v, event);
//如果手勢是剛點擊狀態欄(沒有事件攔截)并且狀態欄是展開的情況下,動畫回收狀態欄,否則跳到mStatusBarWindow的
onTouchEvent方法
? ? ? ? ? ? ? ? if (event.getAction() == MotionEvent.ACTION_DOWN) {
? ? ? ? ? ? ? ? ? ? if (mExpandedVisible) {
? ? ? ? ? ? ? ? ? ? ? ? animateCollapsePanels();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return mStatusBarWindow.onTouchEvent(event);
? ? ? ? ? ? }
? ? ? ? });
...
...
...
}
從這個方法中我們看到系統在創建狀態欄的時候一道給它設置了觸摸事件。如果狀態欄實在展開的情況下,當用戶點擊了狀態欄的沒有事件攔截區域,此時狀態欄會收縮并且帶有動畫效果。否則會進入StatusBarWindowView的onTouchEvent處理,那我們進入這個方法查看,如下是方法的定義
@Override
? ? public boolean onTouchEvent(MotionEvent ev) {
? ? ? ? boolean handled = false;
? ? ? ? if (mService.getBarState() == StatusBarState.KEYGUARD) {
? ? ? ? ? ? handled = mDragDownHelper.onTouchEvent(ev);
? ? ? ? }
? ? ? ? if (!handled) {
? ? ? ? ? ? handled = super.onTouchEvent(ev);
? ? ? ? }
? ? ? ? final int action = ev.getAction();
? ? ? ? if (!handled && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) {
? ? ? ? ? ? mService.setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
? ? ? ? }
? ? ? ? return handled;
? ? }
我們先進入mDragDownHelper.onTouchEvent(ev)這個方法查看,方法定義如下
@Override
? ? public boolean onTouchEvent(MotionEvent event) {
? ? ? ? if (!mDraggingDown) {
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? final float x = event.getX();
? ? ? ? final float y = event.getY();
? ? ? ? switch (event.getActionMasked()) {
? ? ? ? ? ? case MotionEvent.ACTION_MOVE:
? ? ? ? ? ? ? ? mLastHeight = y - mInitialTouchY;
? ? ? ? ? ? ? ? captureStartingChild(mInitialTouchX, mInitialTouchY);
? ? ? ? ? ? ? ? if (mStartingChild != null) {
? ? ? ? ? ? ? ? ? ? handleExpansion(mLastHeight, mStartingChild);
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? mDragDownCallback.setEmptyDragAmount(mLastHeight);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (mLastHeight > mMinDragDistance) {
? ? ? ? ? ? ? ? ? ? if (!mDraggedFarEnough) {
? ? ? ? ? ? ? ? ? ? ? ? mDraggedFarEnough = true;
? ? ? ? ? ? ? ? ? ? ? ? mDragDownCallback.onCrossedThreshold(true);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? if (mDraggedFarEnough) {
? ? ? ? ? ? ? ? ? ? ? ? mDraggedFarEnough = false;
? ? ? ? ? ? ? ? ? ? ? ? mDragDownCallback.onCrossedThreshold(false);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? case MotionEvent.ACTION_UP:
? ? ? ? ? ? ? ? if (!isFalseTouch() && mDragDownCallback.onDraggedDown(mStartingChild,
? ? ? ? ? ? ? ? ? ? ? ? (int) (y - mInitialTouchY))) {
? ? ? ? ? ? ? ? ? ? if (mStartingChild == null) {
? ? ? ? ? ? ? ? ? ? ? ? mDragDownCallback.setEmptyDragAmount(0f);
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? mCallback.setUserLockedChild(mStartingChild, false);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? mDraggingDown = false;
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? stopDragging();
? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_CANCEL:
? ? ? ? ? ? ? ? stopDragging();
? ? ? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? return false;
? ? }
當手勢移動的時候會進入handleExpansion這個方法,它的定義如下
private void handleExpansion(float heightDelta, ExpandableView child) {
? ? ? ? if (heightDelta < 0) {
? ? ? ? ? ? heightDelta = 0;
? ? ? ? }
? ? ? ? boolean expandable = child.isContentExpandable();
? ? ? ? float rubberbandFactor = expandable
? ? ? ? ? ? ? ? ? RUBBERBAND_FACTOR_EXPANDABLE
? ? ? ? ? ? ? ? : RUBBERBAND_FACTOR_STATIC;
? ? ? ? float rubberband = heightDelta * rubberbandFactor;
? ? ? ? if (expandable
? ? ? ? ? ? ? ? && (rubberband + child.getCollapsedHeight()) > child.getMaxContentHeight()) {
? ? ? ? ? ? float overshoot =
? ? ? ? ? ? ? ? ? ? (rubberband + child.getCollapsedHeight()) - child.getMaxContentHeight();
? ? ? ? ? ? overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
? ? ? ? ? ? rubberband -= overshoot;
? ? ? ? }
? ? ? ? child.setActualHeight((int) (child.getCollapsedHeight() + rubberband));
? ? }
我們看到了經過計算最終調用child.setActualHeight這個方法,設置狀態欄的高度,來動態改變狀態欄的顯示高度,而松開手會調用接口回調這里就不深入研究了。到此系統狀態欄的創建添加手勢監聽流程就徹底結束了。
接下來繼續研究系統導航欄的創建添加過程。
接著上面我們看如下定義
public void start() {
.
.
createAndAddWindows();
.
.
.
}
此處省略了大部分代碼,我們只關心和我們今天主題有關系的即可。
createAndAddWindows的實現實在PhoneStatusBar里
我們新進入addNavigationBar這個方法
// For small-screen devices (read: phones) that lack hardware navigation buttons
protected void addNavigationBar() {
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
? ? if (mNavigationBarView ==null)return;
? ? try {
WindowManagerGlobal.getWindowManagerService()
.watchRotation(new IRotationWatcher.Stub() {
@Override
? ? ? ? ? ? public void onRotationChanged(int rotation)throws RemoteException {
// We need this to be scheduled as early as possible to beat the redrawing of
// window in response to the orientation change.
? ? ? ? ? ? ? ? Message msg = Message.obtain(mHandler, () -> {
if (mNavigationBarView !=null
? ? ? ? ? ? ? ? ? ? ? ? ? ? && mNavigationBarView.needsReorient(rotation)) {
repositionNavigationBar();
? ? ? ? ? ? ? ? ? ? }
});
? ? ? ? ? ? ? ? msg.setAsynchronous(true);
? ? ? ? ? ? ? ? mHandler.sendMessageAtFrontOfQueue(msg);
? ? ? ? ? ? }
});
? ? }catch (RemoteException e) {
throw e.rethrowFromSystemServer();
? ? }
//
prepareNavigationBarView();
? ? mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
}
我們接著看prepareNavigationBarView這個方法,定義如下
private void prepareNavigationBarView() {
? ? ? ? mNavigationBarView.reorient();
? ? ? ? ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
? ? ? ? recentsButton.setOnClickListener(mRecentsClickListener);
? ? ? ? recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
? ? ? ? recentsButton.setLongClickable(true);
? ? ? ? recentsButton.setOnLongClickListener(mRecentsLongClickListener);
? ? ? ? ButtonDispatcher backButton = mNavigationBarView.getBackButton();
? ? ? ? backButton.setLongClickable(true);
? ? ? ? backButton.setOnLongClickListener(mLongPressBackListener);
? ? ? ? ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
? ? ? ? homeButton.setOnTouchListener(mHomeActionListener);
? ? ? ? homeButton.setOnLongClickListener(mLongPressHomeListener);
? ? ? ? mAssistManager.onConfigurationChanged();
? ? }
從這里我們看到它設置了系統狀態欄的點擊事件,長按事件,觸摸事件等。
到此系統狀態欄,導航欄的創建到事件監聽大致流程分析完畢了,今天就到此結束吧。