RK3288 + Android 5.1
|-- 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, 聚焦后面我们研究状态栏.
|-- 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: com.android.systemui.statusbar.phone.PhoneStatusBar
**/
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);
在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);
|-- 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
*
*
* 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.
*
* 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;
}
};
}