平台
RK3288 + Android 5.1
SystemUI 启动:
|-- frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() { ... mActivityManagerService.systemReady(new Runnable() { @Override public void run() { Slog.i(TAG, "Making services ready"); .... try { startSystemUi(context); } catch (Throwable e) { reportWtf("starting System UI", e); } ... } } static 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); }
启动的时间, 是在系统服务ready时候, 这时个WindowManagerService, ActivityManagerService, PackageManagerService等关键的服务已经就绪.
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
public class SystemUIService extends Service { @Override public void onCreate() { super.onCreate(); //关键代码: ((SystemUIApplication) getApplication()).startServicesIfNeeded(); } @Override public IBinder onBind(Intent intent) { return null; } @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); } } } } }
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
/** * The classes of the stuff to start. */ private final Class<?>[] SERVICES = new Class[] { com.android.systemui.keyguard.KeyguardViewMediator.class, com.android.systemui.recent.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 }; public void startServicesIfNeeded() { 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"); } } /**----启动 SERVICES 所有的组件:----**/ Log.v(TAG, "Starting SystemUI services."); final int N = SERVICES.length; for (int i=0; i<N; i++) { Class<?> cl = SERVICES[i]; if (DEBUG) Log.d(TAG, "loading: " + cl); 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; }
重点关注 com.android.systemui.statusbar.SystemBars.class, 聚焦后面我们研究状态栏.
状态栏 + 导航栏的核心 PhoneStatusBar
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
@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 }
因为在公版代码中, 并未设置 BAR_SERVICE_COMPONENT 所以, ServiceMonitor执行start后, 会回调
@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"); String clsName = mContext.getString(R.string.config_statusBarComponent); /** frameworks/base/packages/SystemUI/res/values/config.xml: <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string> **/ if ("box".equals(SystemProperties.get("ro.target.product", "tablet"))&&!mContext.getResources().getConfiguration().enableMultiWindow()){ clsName = "com.android.systemui.statusbar.tv.TvStatusBar"; } 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()); }
到此, 终于进入主角: PhoneStatusBar
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
public void start() {//父类BaseStatusBar的函数 ... mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); mRecents = getComponent(RecentsComponent.class); mRecents.setCallback(this); final Configuration currentConfig = mContext.getResources().getConfiguration(); mLocale = currentConfig.locale; mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale); mFontScale = currentConfig.fontScale; mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext, android.R.interpolator.linear_out_slow_in); mFastOutLinearIn = AnimationUtils.loadInterpolator(mContext, android.R.interpolator.fast_out_linear_in); // Connect in to the status bar manager service StatusBarIconList iconList = new StatusBarIconList(); mCommandQueue = new CommandQueue(this, iconList); ... /** ----添加状态栏----**/ createAndAddWindows(); ... }
@Override public void start() { 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() ... // TODO: use MediaSessionManager.SessionListener to hook us up to future updates // in session state /** ----添加导航栏(BACK, HOME, RECENT)----**/ addNavigationBar(); ... } // For small-screen devices (read: phones) that lack hardware navigation buttons private void addNavigationBar() { if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView); if (mNavigationBarView == null) return; prepareNavigationBarView(); mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams()); }
@Override public void createAndAddWindows() { wm = (WindowManager) mContext.getSystemService( Context.WINDOW_SERVICE); mWallpaperManager = (WallpaperManager) mContext.getSystemService(Context.WALLPAPER_SERVICE); addMultiModeWindow(); addStatusBarWindow(); addHalfScreenWindowController(); if(IS_USE_WHCONTROLS){ addFourScreenWindowController(); } addCenterBtnWindow(); if(ONE_LEVEL_MENU){ addCircleMenuWindow(); } if(IS_USE_BACK_WINDOW){ if(mFourScreenBackWindow == null){ mFourScreenBackWindow = new FourScreenBackWindow(mContext, wm); } } if(mMinWindow == null){ mMinWindow = new MinWindow(mContext, wm); } } private void addStatusBarWindow() { makeStatusBarView(); mStatusBarWindowManager = new StatusBarWindowManager(mContext); mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); } // ================================================================================ // Constructing the view // ================================================================================ protected PhoneStatusBarView makeStatusBarView() { final Context context = mContext; IntentFilter intentfilter=new IntentFilter(); intentfilter.addAction("rk.android.screenshot.SHOW"); intentfilter.addAction("rk.android.screenshot.ACTION"); context.registerReceiver(receiver, intentfilter); IntentFilter winintentfilter=new IntentFilter(); winintentfilter.addAction("rk.android.wintask.SHOW"); winintentfilter.addAction("rk.android.wintask.FINISH"); context.registerReceiver(winreceiver, winintentfilter); IntentFilter packagefilter=new IntentFilter(); packagefilter.addAction(Intent.ACTION_PACKAGE_ADDED); packagefilter.addAction(Intent.ACTION_PACKAGE_REMOVED); packagefilter.addDataScheme("package"); context.registerReceiver(packagereceiver, packagefilter); mContext.registerReceiver(wallpaperReceiver, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED)); Resources res = context.getResources(); updateDisplaySize(); // populates mDisplayMetrics updateResources(); mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size); if(mContext.getResources().getConfiguration().enableMultiWindow()){ mStatusBarWindow = (StatusBarWindowView) View.inflate(context, R.layout.super_status_bar_win, null); }else{ mStatusBarWindow = (StatusBarWindowView) View.inflate(context, R.layout.super_status_bar, null); } mStatusBarWindow.mService = 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); mAppBarPanel = (AppBarPanelView)mStatusBarWindow.findViewById(R.id.appbar_panel); mAppBarPanel.setStatusBar(this); mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(R.id.notification_panel); mNotificationPanel.setStatusBar(this); if (!ActivityManager.isHighEndGfx()) { mStatusBarWindow.setBackground(null); mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor( R.color.notification_panel_solid_background))); mAppBarPanel.setBackground(new FastColorDrawable(context.getResources().getColor( R.color.notification_panel_solid_background))); } if (ENABLE_HEADS_UP) { if(mContext.getResources().getConfiguration().enableMultiWindow()){ mHeadsUpNotificationView = (HeadsUpNotificationView) View.inflate(context, R.layout.heads_up_win, null); } else { mHeadsUpNotificationView = (HeadsUpNotificationView) View.inflate(context, R.layout.heads_up, null); } mHeadsUpNotificationView.setVisibility(View.GONE); mHeadsUpNotificationView.setBar(this); } if (MULTIUSER_DEBUG) { mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById( R.id.header_debug_info); mNotificationPanelDebugText.setVisibility(View.VISIBLE); } updateShowSearchHoldoff(); try { boolean showNav = mWindowManagerService.hasNavigationBar(); if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav); if (showNav) { //haungjc:win bar if(mContext.getResources().getConfiguration().enableMultiWindow()){ mNavigationBarView = (NavigationBarView) View.inflate(mContext, R.layout.navigation_bar_win, null); }else{ mNavigationBarView = (NavigationBarView) View.inflate(mContext, R.layout.navigation_bar, null); } mNavigationBarView.setDisabledFlags(mDisabled); mNavigationBarView.setBar(this); mNavigationBarView.setOnVerticalChangedListener( new NavigationBarView.OnVerticalChangedListener() { @Override public void onVerticalChanged(boolean isVertical) { if (mSearchPanelView != null) { mSearchPanelView.setHorizontal(isVertical); } mNotificationPanel.setQsScrimEnabled(!isVertical); } }); mNavigationBarView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { checkUserAutohide(v, event); return false; }}); if(mContext.getResources().getConfiguration().enableMultiWindow()){ mNotificationLite = null;//new NotificationCenterLite(mContext); mCalendarDialog = new CalendarDialog(mContext); } } } catch (RemoteException ex) { // no window manager? good luck with that } // figure out which pixel-format to use for the status bar. mPixelFormat = PixelFormat.OPAQUE; mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area); mSystemIcons = (LinearLayout) mStatusBarView.findViewById(R.id.system_icons); mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons); mNotificationIconArea = mStatusBarView.findViewById(R.id.notification_icon_area_inner); mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons); mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon); mNotificationIcons.setOverflowIndicator(mMoreIcon); mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents); mSimSwitchNotification = (LinearLayout) mStatusBarView.findViewById( R.id.simSwitchNotification); mSimSwitchNotificationText = (TextView) mStatusBarView.findViewById( R.id.simSwitchNotificationText); mSimSwitchContainer = (LinearLayout) mStatusBarWindow.findViewById( R.id.sim_switch_container); mSim1Container = (LinearLayout)mStatusBarWindow.findViewById(R.id.sim1_container); mSim2Container = (LinearLayout)mStatusBarWindow.findViewById(R.id.sim2_container); mAskContainer = (LinearLayout)mStatusBarWindow.findViewById(R.id.ask_container); mSwitchSim1Button = (ImageView)mStatusBarWindow.findViewById(R.id.sim1_switch_button); mSwitchSim2Button = (ImageView)mStatusBarWindow.findViewById(R.id.sim2_switch_button); mSwitchAskButton = (ImageView)mStatusBarWindow.findViewById(R.id.ask_switch_button); mSwitchSim1Button.setOnClickListener(mSimSwitchListener); mSwitchSim2Button.setOnClickListener(mSimSwitchListener); mSwitchAskButton.setOnClickListener(mSimSwitchListener); mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( R.id.notification_stack_scroller); mStackScroller.setLongPressListener(getNotificationLongClicker()); mStackScroller.setPhoneStatusBar(this); mKeyguardIconOverflowContainer = (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false); mKeyguardIconOverflowContainer.setOnActivatedListener(this); mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener); mStackScroller.addView(mKeyguardIconOverflowContainer); SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_speed_bump, mStackScroller, false); mStackScroller.setSpeedBumpView(speedBump); mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate( R.layout.status_bar_no_notifications, mStackScroller, false); mStackScroller.setEmptyShadeView(mEmptyShadeView); mDismissView = (DismissView) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_dismiss_all, mStackScroller, false); mDismissView.setOnButtonClickListener(new View.OnClickListener() { @Override public void onClick(View v) { clearAllNotifications(); } }); mStackScroller.setDismissView(mDismissView); mExpandedContents = mStackScroller; mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop); mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front); mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back); ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind); ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front); mScrimController = new ScrimController(scrimBehind, scrimInFront, mScrimSrcModeEnabled); mScrimController.setBackDropView(mBackdrop); mStatusBarView.setScrimController(mScrimController); mDozeScrimController = new DozeScrimController(mScrimController, context); mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header); mHeader.setActivityStarter(this); mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header); mStatusIconsKeyguard = (LinearLayout) mKeyguardStatusBar.findViewById(R.id.statusIcons); mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view); mKeyguardBottomArea = (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area); mKeyguardBottomArea.setActivityStarter(this); mKeyguardIndicationController = new KeyguardIndicationController(mContext, (KeyguardIndicationTextView) mStatusBarWindow.findViewById( R.id.keyguard_indication_text)); mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController); mTickerEnabled = res.getBoolean(R.bool.enable_ticker); if (mTickerEnabled) { final ViewStub tickerStub = (ViewStub) mStatusBarView.findViewById(R.id.ticker_stub); if (tickerStub != null) { mTickerView = tickerStub.inflate(); mTicker = new MyTicker(context, mStatusBarView); TickerView tickerView = (TickerView) mStatusBarView.findViewById(R.id.tickerText); tickerView.mTicker = mTicker; } } mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); // set the inital view visibility setAreThereNotifications(); // Background thread for any controllers that need it. mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); mHandlerThread.start(); // Other icons mLocationController = new LocationControllerImpl(mContext); // will post a notification mBatteryController = new BatteryController(mContext); mBatteryController.setPercentageView((TextView) mStatusBarWindow.findViewById(R.id.battery_percentage)); mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() { @Override public void onPowerSaveChanged() { mHandler.post(mCheckBarModes); if (mDozeServiceHost != null) { mDozeServiceHost.firePowerSaveChanged(mBatteryController.isPowerSave()); } } @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { // noop } }); mNetworkController = new NetworkControllerImpl(mContext); mHotspotController = new HotspotControllerImpl(mContext); mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper()); mSecurityController = new SecurityControllerImpl(mContext); if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) { mRotationLockController = new RotationLockControllerImpl(mContext); } mUserInfoController = new UserInfoController(mContext); mVolumeComponent = getComponent(VolumeComponent.class); if (mVolumeComponent != null) { mZenModeController = mVolumeComponent.getZenController(); } mCastController = new CastControllerImpl(mContext); final SignalClusterView signalCluster = (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster); final SignalClusterView signalClusterKeyguard = (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster); final SignalClusterView signalClusterQs = (SignalClusterView) mHeader.findViewById(R.id.signal_cluster); mNetworkController.addSignalCluster(signalCluster); mNetworkController.addSignalCluster(signalClusterKeyguard); mNetworkController.addSignalCluster(signalClusterQs); signalCluster.setSecurityController(mSecurityController); signalCluster.setNetworkController(mNetworkController); signalClusterKeyguard.setSecurityController(mSecurityController); signalClusterKeyguard.setNetworkController(mNetworkController); signalClusterQs.setSecurityController(mSecurityController); signalClusterQs.setNetworkController(mNetworkController); if(mContext.getResources().getConfiguration().enableMultiWindow()){ if(signalCluster_win==null&&mNavigationBarView!=null){ mStatusIcons_win = mNavigationBarView.getStatusIcons_win(); signalCluster_win = (SignalClusterView) mNavigationBarView.findViewById(R.id.signal_cluster); mNetworkController.addSignalCluster(signalCluster_win); signalCluster_win.setSecurityController(mSecurityController); signalCluster_win.setNetworkController(mNetworkController); } } final boolean isAPhone = mNetworkController.hasVoiceCallingFeature(); if (isAPhone) { mNetworkController.addEmergencyListener(new NetworkControllerImpl.EmergencyListener() { @Override public void setEmergencyCallsOnly(boolean emergencyOnly) { mHeader.setShowEmergencyCallsOnly(emergencyOnly); } }); } mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label); mShowCarrierInPanel = (mCarrierLabel != null); if (DEBUG) Log.v(TAG, "carrierlabel=" + mCarrierLabel + " show=" + mShowCarrierInPanel); if (mShowCarrierInPanel) { mCarrierLabel.setVisibility(mCarrierLabelVisible ? View.VISIBLE : View.INVISIBLE); mNetworkController.addCarrierLabel(new NetworkControllerImpl.CarrierLabelListener() { @Override public void setCarrierLabel(String label) { mCarrierLabel.setText(label); if (mNetworkController.hasMobileDataFeature()) { if (TextUtils.isEmpty(label)) { mCarrierLabel.setVisibility(View.GONE); } else { mCarrierLabel.setVisibility(View.VISIBLE); } } } }); } mFlashlightController = new FlashlightController(mContext); mKeyguardBottomArea.setFlashlightController(mFlashlightController); mKeyguardBottomArea.setPhoneStatusBar(this); mAccessibilityController = new AccessibilityController(mContext); mKeyguardBottomArea.setAccessibilityController(mAccessibilityController); mNextAlarmController = new NextAlarmController(mContext); mKeyguardMonitor = new KeyguardMonitor(); if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) { mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor); } mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController); // Set up the quick settings tile panel mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel); if (mQSPanel != null) { final QSTileHost qsh = new QSTileHost(mContext, this, mBluetoothController, mLocationController, mRotationLockController, mNetworkController, mZenModeController, mHotspotController, mCastController, mFlashlightController, mUserSwitcherController, mKeyguardMonitor, mSecurityController); mQSPanel.setHost(qsh); mQSPanel.setTiles(qsh.getTiles()); mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow); mQSPanel.setBrightnessMirror(mBrightnessMirrorController); mHeader.setQSPanel(mQSPanel); qsh.setCallback(new QSTileHost.Callback() { @Override public void onTilesChanged() { mQSPanel.setTiles(qsh.getTiles()); } }); } // User info. Trigger first load. mHeader.setUserInfoController(mUserInfoController); mKeyguardStatusBar.setUserInfoController(mUserInfoController); mUserInfoController.reloadUserInfo(); mHeader.setBatteryController(mBatteryController); ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController( mBatteryController); //AnsonCode hide battery if(!mContext.getResources().getBoolean(R.bool.config_has_battery)){ mStatusBarView.findViewById(R.id.battery).setVisibility(View.GONE); } mKeyguardStatusBar.setBatteryController(mBatteryController); mHeader.setNextAlarmController(mNextAlarmController); PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mBroadcastReceiver.onReceive(mContext, new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF)); // receive broadcasts IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); if (DEBUG_MEDIA_FAKE_ARTWORK) { filter.addAction("fake_artwork"); } filter.addAction(ACTION_DEMO); context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); // listen for USER_SETUP_COMPLETE setting (per-user) resetUserSetupObserver(); startGlyphRasterizeHack(); return mStatusBarView; }
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
/** * Adds the status bar view to the window manager. * * @param statusBarView The view to add. * @param barHeight The height of the status bar in collapsed state. */ 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.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; mLp.gravity = Gravity.TOP; mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; mLp.setTitle("StatusBar"); mLp.packageName = mContext.getPackageName(); mStatusBarView = statusBarView; mBarHeight = barHeight; /**----注释即可不显示 ----**/ mWindowManager.addView(mStatusBarView, mLp); mLpChanged = new WindowManager.LayoutParams(); mLpChanged.copyFrom(mLp); }
状态栏 和导航栏, 通过WindowManager.addView添加并显示.
[扩展]
去除状态栏的方式有
1. 把状态栏高度设置为0;
2. 删除 mWindowManager.addView(mStatusBarView, mLp);
去除HEADS-UP通知显示
在5.0后, android 增加了新的通知提示方式(HEADS-UP), 让用户能在任何界面(即使全屏)不会错过重要通知.
Notification.Builder builder = new Notification.Builder(this); builder.setContentTitle("通知"); builder.setContentText("横幅提醒"); builder.setDefaults(Notification.DEFAULT_ALL); builder.setSmallIcon(R.mipmap.ic_launcher); builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)); Intent intent = new Intent(this, EntranceActivity.class); PendingIntent pIntent = PendingIntent.getActivity(this, 1, intent, 0); builder.setContentIntent(pIntent); /**----重点----***/ builder.setFullScreenIntent(pIntent, true); builder.setAutoCancel(true);
setFullScreenIntent 干了什么:
|-- frameworks/base/core/java/android/app/Notification.java
public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) { /**---- mFullScreenIntent赋了非空 ----**/ mFullScreenIntent = intent; setFlag(FLAG_HIGH_PRIORITY, highPriority); return this; }
发送通知:
|-- frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
@Override public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, Notification notification, int[] idOut, int userId) throws RemoteException { enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), Binder.getCallingPid(), tag, id, notification, idOut, userId); } void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, final int callingPid, final String tag, final int id, final Notification notification, int[] idOut, int incomingUserId) { if (DBG) { Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification); } checkCallerIsSystemOrSameApp(pkg); final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); final int userId = ActivityManager.handleIncomingUser(callingPid, callingUid, incomingUserId, true, false, "enqueueNotification", pkg); final UserHandle user = new UserHandle(userId); // Limit the number of notifications that any given package except the android // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. if (!isSystemNotification && !isNotificationFromListener) { synchronized (mNotificationList) { int count = 0; final int N = mNotificationList.size(); for (int i=0; i<N; i++) { final NotificationRecord r = mNotificationList.get(i); if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) { count++; if (count >= MAX_PACKAGE_NOTIFICATIONS) { Slog.e(TAG, "Package has already posted " + count + " notifications. Not showing more. package=" + pkg); return; } } } } } if (pkg == null || notification == null) { throw new IllegalArgumentException("null not allowed: pkg=" + pkg + " id=" + id + " notification=" + notification); } if (notification.icon != 0) { if (!notification.isValid()) { throw new IllegalArgumentException("Invalid notification (): pkg=" + pkg + " id=" + id + " notification=" + notification); } } mHandler.post(new Runnable() { @Override public void run() { synchronized (mNotificationList) { // === Scoring === // 0. Sanitize inputs notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, Notification.PRIORITY_MAX); // Migrate notification flags to scores if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) { if (notification.priority < Notification.PRIORITY_MAX) { notification.priority = Notification.PRIORITY_MAX; } } else if (SCORE_ONGOING_HIGHER && 0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) { if (notification.priority < Notification.PRIORITY_HIGH) { notification.priority = Notification.PRIORITY_HIGH; } } // 1. initial score: buckets of 10, around the app [-20..20] final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; // 2. extract ranking signals from the notification data final StatusBarNotification n = new StatusBarNotification( pkg, opPkg, id, tag, callingUid, callingPid, score, notification, user); NotificationRecord r = new NotificationRecord(n, score); NotificationRecord old = mNotificationsByKey.get(n.getKey()); if (old != null) { // Retain ranking information from previous record r.copyRankingInformation(old); } // Handle grouped notifications and bail out early if we // can to avoid extracting signals. handleGroupedNotificationLocked(r, old, callingUid, callingPid); boolean ignoreNotification = removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid); // This conditional is a dirty hack to limit the logging done on // behalf of the download manager without affecting other apps. if (!pkg.equals("com.android.providers.downloads") || Log.isLoggable("DownloadManager", Log.VERBOSE)) { int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; if (ignoreNotification) { enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED; } else if (old != null) { enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; } EventLogTags.writeNotificationEnqueue(callingUid, callingPid, pkg, id, tag, userId, notification.toString(), enqueueStatus); } if (ignoreNotification) { return; } mRankingHelper.extractSignals(r); // 3. Apply local rules // blocked apps if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) { if (!isSystemNotification) { r.score = JUNK_SCORE; Slog.e(TAG, "Suppressing notification from package " + pkg + " by user request."); } } if (r.score < SCORE_DISPLAY_THRESHOLD) { // Notification will be blocked because the score is too low. return; } int index = indexOfNotificationLocked(n.getKey()); if (index < 0) { mNotificationList.add(r); mUsageStats.registerPostedByApp(r); } else { old = mNotificationList.get(index); mNotificationList.set(index, r); mUsageStats.registerUpdatedByApp(r, old); // Make sure we don't lose the foreground service state. notification.flags |= old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; r.isUpdate = true; } mNotificationsByKey.put(n.getKey(), r); // Ensure if this is a foreground service that the proper additional // flags are set. if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { notification.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR; } applyZenModeLocked(r); mRankingHelper.sort(mNotificationList); if (notification.icon != 0) { StatusBarNotification oldSbn = (old != null) ? old.sbn : null; mListeners.notifyPostedLocked(n, oldSbn); } else { Slog.e(TAG, "Not posting notification with icon==0: " + notification); if (old != null && !old.isCanceled) { mListeners.notifyRemovedLocked(n); } // ATTENTION: in a future release we will bail out here // so that we do not play sounds, show lights, etc. for invalid // notifications Slog.e(TAG, "WARNING: In a future release this will crash the app: " + n.getPackageName()); } buzzBeepBlinkLocked(r); } } }); idOut[0] = id; } /** * asynchronously notify all listeners about a new notification * * <p> * Also takes care of removing a notification that has been visible to a listener before, * but isn't anymore. */ public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) { // Lazily initialized snapshots of the notification. StatusBarNotification sbnClone = null; StatusBarNotification sbnCloneLight = null; for (final ManagedServiceInfo info : mServices) { boolean sbnVisible = isVisibleToListener(sbn, info); boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false; // This notification hasn't been and still isn't visible -> ignore. if (!oldSbnVisible && !sbnVisible) { continue; } final NotificationRankingUpdate update = makeRankingUpdateLocked(info); // This notification became invisible -> remove the old one. if (oldSbnVisible && !sbnVisible) { final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); mHandler.post(new Runnable() { @Override public void run() { notifyRemoved(info, oldSbnLightClone, update); } }); continue; } final int trim = mListeners.getOnNotificationPostedTrim(info); if (trim == TRIM_LIGHT && sbnCloneLight == null) { sbnCloneLight = sbn.cloneLight(); } else if (trim == TRIM_FULL && sbnClone == null) { sbnClone = sbn.clone(); } final StatusBarNotification sbnToPost = (trim == TRIM_FULL) ? sbnClone : sbnCloneLight; mHandler.post(new Runnable() { @Override public void run() { notifyPosted(info, sbnToPost, update); } }); } } private void notifyPosted(final ManagedServiceInfo info, final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { final INotificationListener listener = (INotificationListener)info.service; StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); try { listener.onNotificationPosted(sbnHolder, rankingUpdate); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (posted): " + listener, ex); } }
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
/**---- 注册监听通知服务 ----**/ public void start() { // Set up the initial notification state. try { mNotificationListener.registerAsSystemService(mContext, new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()), UserHandle.USER_ALL); } catch (RemoteException e) { Log.e(TAG, "Unable to register notification listener", e); } } |-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java ```java /**---- 注册监听通知服务 ----**/ public void start() { // Set up the initial notification state. try { mNotificationListener.registerAsSystemService(mContext, new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()), UserHandle.USER_ALL); } catch (RemoteException e) { Log.e(TAG, "Unable to register notification listener", e); } } private final NotificationListenerService mNotificationListener = new NotificationListenerService() { @Override public void onListenerConnected() { if (DEBUG) Log.d(TAG, "onListenerConnected"); final StatusBarNotification[] notifications = getActiveNotifications(); final RankingMap currentRanking = getCurrentRanking(); mHandler.post(new Runnable() { @Override public void run() { for (StatusBarNotification sbn : notifications) { addNotification(sbn, currentRanking); } } }); } /**---- 由 NotificationManagerService 调用 ----**/ @Override public void onNotificationPosted(final StatusBarNotification sbn, final RankingMap rankingMap) { if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn); mHandler.post(new Runnable() { @Override public void run() { Notification n = sbn.getNotification(); boolean isUpdate = mNotificationData.get(sbn.getKey()) != null || isHeadsUp(sbn.getKey()); // Ignore children of notifications that have a summary, since we're not // going to show them anyway. This is true also when the summary is canceled, // because children are automatically canceled by NoMan in that case. if (n.isGroupChild() && mNotificationData.isGroupWithSummary(sbn.getGroupKey())) { if (DEBUG) { Log.d(TAG, "Ignoring group child due to existing summary: " + sbn); } // Remove existing notification to avoid stale data. if (isUpdate) { removeNotification(sbn.getKey(), rankingMap); } else { mNotificationData.updateRanking(rankingMap); } return; } if (isUpdate) { updateNotification(sbn, rankingMap); } else { addNotification(sbn, rankingMap); } } }); } @Override public void onNotificationRemoved(final StatusBarNotification sbn, final RankingMap rankingMap) { if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn); mHandler.post(new Runnable() { @Override public void run() { removeNotification(sbn.getKey(), rankingMap); } }); } @Override public void onNotificationRankingUpdate(final RankingMap rankingMap) { if (DEBUG) Log.d(TAG, "onRankingUpdate"); mHandler.post(new Runnable() { @Override public void run() { updateNotificationRanking(rankingMap); } }); } };
|-- frameworks/base/core/java/android/service/notification/NotificationListenerService.java
/** * Directly register this service with the Notification Manager. * * <p>Only system services may use this call. It will fail for non-system callers. * Apps should ask the user to add their listener in Settings. * * @param context Context required for accessing resources. Since this service isn't * launched as a real Service when using this method, a context has to be passed in. * @param componentName the component that will consume the notification information * @param currentUser the user to use as the stream filter * @hide */ @SystemApi public void registerAsSystemService(Context context, ComponentName componentName, int currentUser) throws RemoteException { mSystemContext = context; if (mWrapper == null) { mWrapper = new INotificationListenerWrapper(); } INotificationManager noMan = getNotificationInterface(); noMan.registerListener(mWrapper, componentName, currentUser); mCurrentUser = currentUser; }
|-- frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
/** * Register a listener binder directly with the notification manager. * * Only works with system callers. Apps should extend * {@link android.service.notification.NotificationListenerService}. */ @Override public void registerListener(final INotificationListener listener, final ComponentName component, final int userid) { enforceSystemOrSystemUI("INotificationManager.registerListener"); mListeners.registerService(listener, component, userid); }
收到通知后的处理:
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@Override public void addNotification(StatusBarNotification notification, RankingMap ranking) { if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey()); if (mUseHeadsUp && shouldInterrupt(notification)) { if (DEBUG) Log.d(TAG, "launching notification in heads up mode"); Entry interruptionCandidate = new Entry(notification, null); ViewGroup holder = mHeadsUpNotificationView.getHolder(); if (inflateViewsForHeadsUp(interruptionCandidate, holder)) { /**---- 只需注释掉, 即可阻止显示HEADS-UP 通知 ---- **/ // 1. Populate mHeadsUpNotificationView mHeadsUpNotificationView.showNotification(interruptionCandidate); // do not show the notification in the shade, yet. return; } } Entry shadeEntry = createNotificationViews(notification); if (shadeEntry == null) { return; } if (notification.getNotification().fullScreenIntent != null) { // Stop screensaver if the notification has a full-screen intent. // (like an incoming phone call) awakenDreams(); // not immersive & a full-screen alert should be shown if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); try { EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, notification.getKey()); notification.getNotification().fullScreenIntent.send(); } catch (PendingIntent.CanceledException e) { } } else { // usual case: status bar visible & not immersive // show the ticker if there isn't already a heads up if (mHeadsUpNotificationView.getEntry() == null) { tick(notification, true); } } addNotificationViews(shadeEntry, ranking); // Recalculate the position of the sliding windows and the titles. setAreThereNotifications(); updateExpandedViewPos(EXPANDED_LEAVE_ALONE); }
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
protected boolean shouldInterrupt(StatusBarNotification sbn) { if (mNotificationData.shouldFilterOut(sbn)) { if (DEBUG) { Log.d(TAG, "Skipping HUN check for " + sbn.getKey() + " since it's filtered out."); } return false; } if ((null!=mHeadsUpNotificationView)&&mHeadsUpNotificationView.isSnoozed(sbn.getPackageName())) { return false; } Notification notification = sbn.getNotification(); // some predicates to make the boolean logic legible boolean isNoisy = (notification.defaults & Notification.DEFAULT_SOUND) != 0 || (notification.defaults & Notification.DEFAULT_VIBRATE) != 0 || notification.sound != null || notification.vibrate != null; boolean isHighPriority = sbn.getScore() >= INTERRUPTION_THRESHOLD; /**---- 前面已设置非空 ----**/ boolean isFullscreen = notification.fullScreenIntent != null; boolean hasTicker = mHeadsUpTicker && !TextUtils.isEmpty(notification.tickerText); boolean isAllowed = notification.extras.getInt(Notification.EXTRA_AS_HEADS_UP, Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER; boolean accessibilityForcesLaunch = isFullscreen && mAccessibilityManager.isTouchExplorationEnabled(); if(mContext.getResources().getConfiguration().enableMultiWindow()&&!isFullscreen) isFullscreen = true&&!sbn.isOngoing(); boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker))) && isAllowed && !accessibilityForcesLaunch && mPowerManager.isScreenOn() && (!mStatusBarKeyguardViewManager.isShowing() || mStatusBarKeyguardViewManager.isOccluded()) && !mStatusBarKeyguardViewManager.isInputRestricted(); try { interrupt = interrupt && !mDreamManager.isDreaming(); } catch (RemoteException e) { Log.d(TAG, "failed to query dream manager", e); } if (DEBUG) Log.d(TAG, "interrupt: " + interrupt); return interrupt; }
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
public boolean showNotification(NotificationData.Entry headsUp) { if (mHeadsUp != null && headsUp != null && !mHeadsUp.key.equals(headsUp.key)) { // bump any previous heads up back to the shade release(); } mHeadsUp = headsUp; if (mContentHolder != null) { mContentHolder.removeAllViews(); } if (mHeadsUp != null) { mMostRecentPackageName = mHeadsUp.notification.getPackageName(); mHeadsUp.row.setSystemExpanded(true); mHeadsUp.row.setSensitive(false); mHeadsUp.row.setHeadsUp(true); mHeadsUp.row.setHideSensitive( false, false /* animated */, 0 /* delay */, 0 /* duration */); if (mContentHolder == null) { // too soon! return false; } mContentHolder.setX(0); mContentHolder.setVisibility(View.VISIBLE); mContentHolder.setAlpha(mMaxAlpha); mContentHolder.addView(mHeadsUp.row); sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); mSwipeHelper.snapChild(mContentHolder, 1f); mStartTouchTime = SystemClock.elapsedRealtime() + mTouchSensitivityDelay; mHeadsUp.setInterruption(); // 2. Animate mHeadsUpNotificationView in mBar.scheduleHeadsUpOpen(); // 3. Set alarm to age the notification off mBar.resetHeadsUpDecayTimer(); } return true; }
通知长按处理
通知VIEW结构:
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java |-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java |-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java ... * N
ExpandableNotificationRow 的父类关系:
ExpandableNotificationRow -> ActivatableNotificationView -> ExpandableOutlineView -> ExpandableView -> FrameLayout
长按事件实际是由NotificationStackScrollLayout处理的:
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java public void setLongPressListener(SwipeHelper.LongPressListener listener) { mSwipeHelper.setLongPressListener(listener); mLongPressListener = listener; }
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
public void setLongPressListener(LongPressListener listener) { mLongPressListener = listener; } public boolean onInterceptTouchEvent(final MotionEvent ev) { final int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: mTouchAboveFalsingThreshold = false; mDragging = false; mLongPressSent = false; mCurrView = mCallback.getChildAtPosition(ev); mVelocityTracker.clear(); if (mCurrView != null) { mCurrAnimView = mCallback.getChildContentView(mCurrView); mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView); mVelocityTracker.addMovement(ev); mInitialTouchPos = getPos(ev); if (mLongPressListener != null) { if (mWatchLongPress == null) { mWatchLongPress = new Runnable() { @Override public void run() { if (mCurrView != null && !mLongPressSent) { mLongPressSent = true; mCurrView.sendAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); mCurrView.getLocationOnScreen(mTmpPos); final int x = (int) ev.getRawX() - mTmpPos[0]; final int y = (int) ev.getRawY() - mTmpPos[1]; mLongPressListener.onLongPress(mCurrView, x, y); } } }; } mHandler.postDelayed(mWatchLongPress, mLongPressTimeout); } } break; ... }
长按的监听由PhoneStatusBar传入:
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
protected PhoneStatusBarView makeStatusBarView() { final Context context = mContext; IntentFilter intentfilter=new IntentFilter(); intentfilter.addAction("rk.android.screenshot.SHOW"); intentfilter.addAction("rk.android.screenshot.ACTION"); context.registerReceiver(receiver, intentfilter); ... mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( R.id.notification_stack_scroller); mStackScroller.setLongPressListener(getNotificationLongClicker()); mStackScroller.setPhoneStatusBar(this); }
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
protected SwipeHelper.LongPressListener getNotificationLongClicker() { return new SwipeHelper.LongPressListener() { @Override public boolean onLongPress(View v, int x, int y) { /**---- 若不希望处理长按, 则可直接返回结果, 或不注册长按监听即可 ----**/ dismissPopups(); if (!(v instanceof ExpandableNotificationRow)) { return false; } if (v.getWindowToken() == null) { Log.e(TAG, "Trying to show notification guts, but not attached to window"); return false; } inflateGuts((ExpandableNotificationRow) v); // Assume we are a status_bar_notification_row final NotificationGuts guts = (NotificationGuts) v.findViewById( R.id.notification_guts); if (guts == null) { // This view has no guts. Examples are the more card or the dismiss all view return false; } // Already showing? if (guts.getVisibility() == View.VISIBLE) { Log.e(TAG, "Trying to show notification guts, but already visible"); return false; } guts.setVisibility(View.VISIBLE); final double horz = Math.max(guts.getWidth() - x, x); final double vert = Math.max(guts.getActualHeight() - y, y); final float r = (float) Math.hypot(horz, vert); final Animator a = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r); a.setDuration(400); a.setInterpolator(mLinearOutSlowIn); a.start(); mNotificationGutsExposed = guts; return true; } }; }