Bug[systemUI]--移除點擊狀態欄也會跳出通知面板功能

防止通話中的錯誤操作,變更通知/快速設置面板操作

1. Description

■ Current conclusion
romve the function of that the pull-down animation will start if a click event happened in the head of screen

■ My analysis

The original problem of Android.
There are three main places for the click event to start the pull-down animation:

  1. MotionEvent.ACTION_DOWN ,if Phine is Fully Collapsed && HeadsUpManager has not Pinned HeadsUp && StatusBaris Bouncer Showing(),the pull-down animation will run
  2. MotionEvent.ACTION_CANCEL, involved in endMotionEvent():
    a, if the distance between x/y in which the on touch down event and x/y in which the on touch up event is greater than 8 dp && the velocity withgetYVelocity()is bigger than 0,the pull-down animation will run
    b, if the distance between x/y in which the on touch down event and x/y in which the on touch up event is greater than 8 dp && the time of on touch down to on touch up less than 500ms,the pull-down animation will run
    wo need to

■Submit URL

2. Analysis

功能定位:該功能主要是涉及到systemUI的狀態欄
觸發點: 點擊狀態欄
現象: 顯示通知欄
解題思路:屏蔽狀態欄的點擊事件,只允許下拉才顯示通知面板


public class SystemBars extends SystemUI {
    private static final String TAG = "SystemBars";
    private static final boolean DEBUG = false;
    private static final int WAIT_FOR_BARS_TO_DIE = 500;


    // in-process fallback implementation, per the product config
    private SystemUI mStatusBar;


    @Override
    public void start() {
        if (DEBUG) Log.d(TAG, "start");
        createStatusBarFromConfig();
    }


    @Override
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        if (mStatusBar != null) {
            mStatusBar.dump(fd, pw, args);
        }
    }
    private void createStatusBarFromConfig() {
        if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
        final String clsName = mContext.getString(R.string.config_statusBarComponent);
        if (clsName == null || clsName.length() == 0) {
            throw andLog("No status bar component configured", null);
        }
        Class<?> cls = null;
        try {
            cls = mContext.getClassLoader().loadClass(clsName);
        } catch (Throwable t) {
            throw andLog("Error loading status bar component: " + clsName, t);
        }
        try {
            mStatusBar = (SystemUI) cls.newInstance();
        } catch (Throwable t) {
            throw andLog("Error creating status bar component: " + clsName, t);
        }
        mStatusBar.mContext = mContext;
        mStatusBar.mComponents = mComponents;
        if (mStatusBar instanceof StatusBar) {
            SystemUIFactory.getInstance().getRootComponent()
                    .getStatusBarInjector()
                    .createStatusBar((StatusBar) mStatusBar);
        }
        mStatusBar.start();
        if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
    }


    private RuntimeException andLog(String msg, Throwable t) {
        Log.w(TAG, msg, t);
        throw new RuntimeException(msg, t);
    }
}

從上面代碼上看,和狀態欄相關的邏輯什麼都沒有做,它只是

  1. 通過配置文件查找到對應得狀態欄實際的實現類
  2. 通過反射獲得實際的實現類對象
  3. 執行start();
    配置文件聲明,具體如下:

    <!-- Component to be used as the status bar service.  Must implement the IStatusBar interface.  This name is in the ComponentName flattened format (package/class)  -->
    <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar</string>

它這樣子的做法其實也很好理解,就是爲了適配不同產品,即如果編譯的產品是手機,就用StatusBar這個類,如果是車載系統/手錶就可能用其他的實現類了。
然後看看StatusBar的實現,因爲它比較大,所以摘錄部分


public class StatusBar extends SystemUI implements DemoMode,
        ActivityStarter, OnUnlockMethodChangedListener,
        OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
        ColorExtractor.OnColorsChangedListener, ConfigurationListener,
        StatusBarStateController.StateListener, ShadeController,
        ActivityLaunchAnimator.Callback, AppOpsController.Callback {


    @Override
    public void start() {
/*
1. 獲得各個服務的對象,方便後續使用
2. 執行createAndAddWindows(result);開始繪製界面
*/
        mGroupManager = Dependency.get(NotificationGroupManager.class);
        mGroupAlertTransferHelper = Dependency.get(NotificationGroupAlertTransferHelper.class);
        mVisualStabilityManager = Dependency.get(VisualStabilityManager.class);
        mNotificationLogger = Dependency.get(NotificationLogger.class);
        mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
        mNotificationListener =  Dependency.get(NotificationListener.class);
        mNotificationListener.registerAsSystemService();
        mNetworkController = Dependency.get(NetworkController.class);
        mUserSwitcherController = Dependency.get(UserSwitcherController.class);
        mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
        mScreenLifecycle.addObserver(mScreenObserver);
        mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
        mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
        mBatteryController = Dependency.get(BatteryController.class);
        mAssistManager = Dependency.get(AssistManager.class);
        mUiModeManager = mContext.getSystemService(UiModeManager.class);
        mLockscreenUserManager = Dependency.get(NotificationLockscreenUserManager.class);
        mGutsManager = Dependency.get(NotificationGutsManager.class);
        mMediaManager = Dependency.get(NotificationMediaManager.class);
        mEntryManager = Dependency.get(NotificationEntryManager.class);
        mBypassHeadsUpNotifier.setUp(mEntryManager);
        mNotificationInterruptionStateProvider =Dependency.get(NotificationInterruptionStateProvider.class);
        mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
        mForegroundServiceController = Dependency.get(ForegroundServiceController.class);
        mAppOpsController = Dependency.get(AppOpsController.class);
        mZenController = Dependency.get(ZenModeController.class);
        mKeyguardViewMediator = getComponent(KeyguardViewMediator.class);
        mColorExtractor = Dependency.get(SysuiColorExtractor.class);
        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
        mNavigationBarController = Dependency.get(NavigationBarController.class);
        mBubbleController = Dependency.get(BubbleController.class);
        mBubbleController.setExpandListener(mBubbleExpandListener);
        mActivityIntentHelper = new ActivityIntentHelper(mContext);
        KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance();


        if (sliceProvider != null) {
            sliceProvider.initDependencies(mMediaManager, mStatusBarStateController,mKeyguardBypassController, DozeParameters.getInstance(mContext));
        } else {
            Log.w(TAG, "Cannot init KeyguardSliceProvider dependencies");
        }


        mColorExtractor.addOnColorsChangedListener(this);
        mStatusBarStateController.addCallback(this,SysuiStatusBarStateController.RANK_STATUS_BAR);


        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        mDreamManager = IDreamManager.Stub.asInterface(ServiceManager.checkService(DreamService.DREAM_SERVICE));


        mDisplay = mWindowManager.getDefaultDisplay();
        mDisplayId = mDisplay.getDisplayId();
        updateDisplaySize();


        mVibrateOnOpening = mContext.getResources().getBoolean(R.bool.config_vibrateOnIconAnimation);
        mVibratorHelper = Dependency.get(VibratorHelper.class);


        DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER));
        putComponent(StatusBar.class, this);


        // start old BaseStatusBar.start().
        mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
        mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);


        mAccessibilityManager = (AccessibilityManager)mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);


        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
        mKeyguardUpdateMonitor.setStatusBar(this);
        mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
        mBarService = IStatusBarService.Stub.asInterface(ServiceManager.getService(Context.STATUS_BAR_SERVICE));


        mRecents = getComponent(Recents.class);


        mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
        mFalsingManager = Dependency.get(FalsingManager.class);




        // Connect in to the status bar manager service
        mCommandQueue = getComponent(CommandQueue.class);
        mCommandQueue.addCallback(this);


        RegisterStatusBarResult result = null;
        try {
            result = mBarService.registerStatusBar(mCommandQueue);
        } catch (RemoteException ex) {
            ex.rethrowFromSystemServer();
        }
        createAndAddWindows(result);


        // Make sure we always have the most current wallpaper info.
        IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
        mContext.registerReceiverAsUser(mWallpaperChangedReceiver, UserHandle.ALL,wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
        mWallpaperChangedReceiver.onReceive(mContext, null);


        // Set up the initial notification state. This needs to happen before CommandQueue.disable()
        setUpPresenter();


        setSystemUiVisibility(mDisplayId, result.mSystemUiVisibility,result.mFullscreenStackSysUiVisibility, result.mDockedStackSysUiVisibility,0xffffffff, result.mFullscreenStackBounds, result.mDockedStackBounds,result.mNavbarColorManagedByIme);
        // StatusBarManagerService has a back up of IME token and it's restored here.
        setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,result.mImeBackDisposition, result.mShowImeSwitcher);


        // Set up the initial icon state
        int numIcons = result.mIcons.size();
        for (int i = 0; i < numIcons; i++) {
            mCommandQueue.setIcon(result.mIcons.keyAt(i), result.mIcons.valueAt(i));
        }




        IntentFilter internalFilter = new IntentFilter();
        internalFilter.addAction(BANNER_ACTION_CANCEL);
        internalFilter.addAction(BANNER_ACTION_SETUP);
        mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,null);


        IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(ServiceManager.getService(Context.WALLPAPER_SERVICE));
        try {
            wallpaperManager.setInAmbientMode(false /* ambientMode */, 0L /* duration */);
        } catch (RemoteException e) {
            // Just pass, nothing critical.
        }


        // end old BaseStatusBar.start().


        // Lastly, call to the icon policy to install/update all the icons.
        mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
        mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);


        mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
        mUnlockMethodCache.addListener(this);
        startKeyguard();


        mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
        putComponent(DozeHost.class, mDozeServiceHost);
        mScreenPinningRequest = new ScreenPinningRequest(mContext);
        Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this)
        Dependency.get(ConfigurationController.class).addCallback(this);
        // set the initial view visibility
        Dependency.get(InitController.class).addPostInitTask(this::updateAreThereNotifications);
        int disabledFlags1 = result.mDisabledFlags1;
        int disabledFlags2 = result.mDisabledFlags2;
        Dependency.get(InitController.class).addPostInitTask(() -> setUpDisableFlags(disabledFlags1, disabledFlags2));
    }




}

然後看看createAndAddWindows是如何繪製界面的


    public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
        makeStatusBarView(result);
        mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
        mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight());
    }


   // ================================================================================
    // Constructing the view ,這裏開始創建狀態欄
    // ================================================================================
    protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
        final Context context = mContext;
        updateDisplaySize(); // populates mDisplayMetrics
        updateResources();
        updateTheme();


        inflateStatusBarWindow(context);
        mStatusBarWindow.setService(this);
        mStatusBarWindow.setFastFingerLauncher(mFastFingerLauncer);
        mStatusBarWindow.setBypassController(mKeyguardBypassController);
        mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());


        // TODO: Deal with the ugliness that comes from having some of the statusbar broken out into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
        mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);/*mNotificationPanel 就是下拉出來的通知面板*/
        mFingerIconView = mStatusBarWindow.findViewById(R.id.finger_icon);
        mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
        mZenController.addCallback(this);
        NotificationListContainer notifListContainer = (NotificationListContainer) mStackScroller;
        mNotificationLogger.setUpWithContainer(notifListContainer);


        mNotificationIconAreaController = SystemUIFactory.getInstance().createNotificationIconAreaController(context, this,mWakeUpCoordinator,mKeyguardBypassController,mStatusBarStateController);
        mWakeUpCoordinator.setIconAreaController(mNotificationIconAreaController);
        inflateShelf();
        mNotificationIconAreaController.setupShelf(mNotificationShelf);
        mNotificationPanel.setOnReinflationListener(mNotificationIconAreaController::initAodIcons);
        mNotificationPanel.addExpansionListener(mWakeUpCoordinator);


        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
        // Allow plugins to reference DarkIconDispatcher and StatusBarStateController
        Dependency.get(PluginDependencyProvider.class).allowPluginDependency(DarkIconDispatcher.class);
        Dependency.get(PluginDependencyProvider.class)
                .allowPluginDependency(StatusBarStateController.class);
        FragmentHostManager.get(mStatusBarWindow)
                .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                    CollapsedStatusBarFragment statusBarFragment =
                            (CollapsedStatusBarFragment) fragment;
                    statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
                    PhoneStatusBarView oldStatusBarView = mStatusBarView;
                    mStatusBarView = (PhoneStatusBarView) fragment.getView();
                    mStatusBarView.setBar(this);
                    mStatusBarView.setPanel(mNotificationPanel);
                    mStatusBarView.setScrimController(mScrimController);


                    // CollapsedStatusBarFragment re-inflated PhoneStatusBarView and both of
                    // mStatusBarView.mExpanded and mStatusBarView.mBouncerShowing are false.
                    // PhoneStatusBarView's new instance will set to be gone in
                    // PanelBar.updateVisibility after calling mStatusBarView.setBouncerShowing
                    // that will trigger PanelBar.updateVisibility. If there is a heads up showing,
                    // it needs to notify PhoneStatusBarView's new instance to update the correct
                    // status by calling mNotificationPanel.notifyBarPanelExpansionChanged().
                    if (mHeadsUpManager.hasPinnedHeadsUp()) {
                        mNotificationPanel.notifyBarPanelExpansionChanged();
                    }
                    mStatusBarView.setBouncerShowing(mBouncerShowing);
                    if (oldStatusBarView != null) {
                        float fraction = oldStatusBarView.getExpansionFraction();
                        boolean expanded = oldStatusBarView.isExpanded();
                        mStatusBarView.panelExpansionChanged(fraction, expanded);
                    }


                    HeadsUpAppearanceController oldController = mHeadsUpAppearanceController;
                    if (mHeadsUpAppearanceController != null) {
                        // This view is being recreated, let's destroy the old one
                        mHeadsUpAppearanceController.destroy();
                    }
                    mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                            mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow,
                            mStatusBarStateController, mKeyguardBypassController,
                            mWakeUpCoordinator);
                    mHeadsUpAppearanceController.readFrom(oldController);
                    mStatusBarWindow.setStatusBarView(mStatusBarView);
                    updateAreThereNotifications();
                    getStatusBarTransitions().setCutoutView(addCornerCutoutSpaceView());
                    checkBarModes();
                }).getFragmentManager()
                .beginTransaction()
                .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
                        CollapsedStatusBarFragment.TAG)
                .commit();
        mIconController = Dependency.get(StatusBarIconController.class);


        mHeadsUpManager.setUp(mStatusBarWindow, mGroupManager, this, mVisualStabilityManager);
        Dependency.get(ConfigurationController.class).addCallback(mHeadsUpManager);
        mHeadsUpManager.addListener(this);
        mHeadsUpManager.addListener(mNotificationPanel);
        mHeadsUpManager.addListener(mGroupManager);
        mHeadsUpManager.addListener(mGroupAlertTransferHelper);
        mHeadsUpManager.addListener(mVisualStabilityManager);
        mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
        mGroupManager.setHeadsUpManager(mHeadsUpManager);
        mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager);
        mNotificationLogger.setHeadsUpManager(mHeadsUpManager);
        putComponent(HeadsUpManager.class, mHeadsUpManager);


        createNavigationBar(result);


        if (ENABLE_LOCKSCREEN_WALLPAPER) {
            mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
        }


     mKeyguardIndicationController =SystemUIFactory.getInstance().createKeyguardIndicationController(mContext, mStatusBarWindow.findViewById(R.id.keyguard_indication_area), mStatusBarWindow.findViewById(R.id.lock_icon));
     mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
        KeyguardBottomAreaView fjBottomArea =(KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
        mKeyguardIndicationController =SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,(ViewGroup) fjBottomArea.findViewById(R.id.keyguard_indication_area), mStatusBarWindow.findViewById(R.id.lock_icon)); mKeyguardIndicationController.setStatusBar(this);
        mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);




        mAmbientIndicationContainer = mStatusBarWindow.findViewById(
                R.id.ambient_indication_container);


        // TODO: Find better place for this callback.
        mBatteryController.addCallback(new BatteryStateChangeCallback() {
            @Override
            public void onPowerSaveChanged(boolean isPowerSave) {
                mHandler.post(mCheckBarModes);
                if (mDozeServiceHost != null) {
                    mDozeServiceHost.firePowerSaveChanged(isPowerSave);
                }
            }


            @Override
            public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
                // noop
            }
        });


        mAutoHideController = Dependency.get(AutoHideController.class);
        mAutoHideController.setStatusBar(this);


        mLightBarController = Dependency.get(LightBarController.class);


        ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind);
        ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front);
        mScrimController = SystemUIFactory.getInstance().createScrimController(
                scrimBehind, scrimInFront, mLockscreenWallpaper,
                (state, alpha, color) -> mLightBarController.setScrimState(state, alpha, color),
                scrimsVisible -> {
                    if (mStatusBarWindowController != null) {
                        mStatusBarWindowController.setScrimsVisibility(scrimsVisible);
                    }
                    if (mStatusBarWindow != null) {
                        mStatusBarWindow.onScrimVisibilityChanged(scrimsVisible);
                    }
                }, DozeParameters.getInstance(mContext),
                mContext.getSystemService(AlarmManager.class),
                mKeyguardMonitor);
        mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf,
                mHeadsUpManager, mNotificationIconAreaController, mScrimController);
        mDozeScrimController = new DozeScrimController(DozeParameters.getInstance(context));


        BackDropView backdrop = mStatusBarWindow.findViewById(R.id.backdrop);
        mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),backdrop.findViewById(R.id.backdrop_back), mScrimController, mLockscreenWallpaper);


        // Other icons
        mVolumeComponent = getComponent(VolumeComponent.class);


        mNotificationPanel.setUserSetupComplete(mUserSetup);
        if (UserManager.get(mContext).isUserSwitcherEnabled()) {
            createUserSwitcher();
        }


        mNotificationPanel.setLaunchAffordanceListener(mStatusBarWindow::onShowingLaunchAffordanceChanged);


        // Set up the quick settings tile panel
        View container = mStatusBarWindow.findViewById(R.id.qs_frame);
        if (container != null) {
            FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
            ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame,
                    Dependency.get(ExtensionController.class)
                            .newExtension(QS.class)
                            .withPlugin(QS.class)
                            .withDefault(this::createDefaultQSFragment)
                            .build());
            mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow,
                    (visible) -> {
                        mBrightnessMirrorVisible = visible;
                        updateScrimController();
                    });
            fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
                QS qs = (QS) f;
                if (qs instanceof QSFragment) {
                    mQSPanel = ((QSFragment) qs).getQsPanel();
                    mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
                }
            });
        }


        mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch);
        if (mReportRejectedTouch != null) {
            updateReportRejectedTouchVisibility();
            mReportRejectedTouch.setOnClickListener(v -> {
                Uri session = mFalsingManager.reportRejectedTouch();
                if (session == null) { return; }


                StringWriter message = new StringWriter();
                message.write("Build info: ");
                message.write(SystemProperties.get("ro.build.description"));
                message.write("\nSerial number: ");
                message.write(SystemProperties.get("ro.serialno"));
                message.write("\n");


                PrintWriter falsingPw = new PrintWriter(message);
                FalsingLog.dump(falsingPw);
                falsingPw.flush();


                startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND).setType("*/*") .putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report").putExtra(Intent.EXTRA_STREAM, session).putExtra(Intent.EXTRA_TEXT, message.toString()),"Share rejected touch report") .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
                        true /* onlyProvisioned */, true /* dismissShade */);
            });
        }


        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
        if (!pm.isScreenOn()) {
            mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
        }
        mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GestureWakeLock");
        mVibrator = mContext.getSystemService(Vibrator.class);
        int[] pattern = mContext.getResources().getIntArray( R.array.config_cameraLaunchGestureVibePattern);
        mCameraLaunchGestureVibePattern = new long[pattern.length];
        for (int i = 0; i < pattern.length; i++) {
            mCameraLaunchGestureVibePattern[i] = pattern[i];
        }


        // receive broadcasts
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);


        IntentFilter demoFilter = new IntentFilter();
        if (DEBUG_MEDIA_FAKE_ARTWORK) {
            demoFilter.addAction(ACTION_FAKE_ARTWORK);
        }
        demoFilter.addAction(ACTION_DEMO);
        context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,android.Manifest.permission.DUMP, null);
        // listen for USER_SETUP_COMPLETE setting (per-user)
        mDeviceProvisionedController.addCallback(mUserSetupObserver);
        mUserSetupObserver.onUserSetupChanged();
        Typeface typeface = Typeface.defaultFromStyle(Typeface.NORMAL);
        if(mStatusBarView != null) { //TODO(TS_FW-AF) : For build success so mark below code.
                TextView clock = (TextView) mStatusBarView.findViewById(R.id.clock);
                if( clock != null) {
                    clock.setTypeface(typeface);
                }
        }




        if( mNotificationPanel != null ) {
            List<TextView> textViews = getViewsGroupRecursive(mNotificationPanel);
            for (TextView textView : textViews) {
                if(textView.getId() != R.id.time_view){
                    textView.getPaint().setTypeface(typeface);
                }
            }
        }


        // disable profiling bars, since they overlap and clutter the output on app windows
        ThreadedRenderer.overrideProperty("disableProfileBars", "true");


        // Private API call to make the shadows look better for Recents
        ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));


        mBiometricManager = mContext.getSystemService(BiometricManager.class);
        if (mFingerIconView != null) {
            mFingerIconView.setStatusBar(this);
          if (hasEnrolledBiometrics()) {
              mFingerIconView.setVisibility(View.VISIBLE);
          } else {
             mFingerIconView.setVisibility(View.GONE);
          }
            mFingerIconView.setVisibility(View.GONE);


        }
    }

然後轉入通知面板的實現類NotificationPanelView,主要看看它的onTouchEvent方法裏面的邏輯,觸摸屏幕的實現都是在裏面做的


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mBlockTouches || (mQs != null && mQs.isCustomizing())) {
            Log.d(TAG, "onTouchEvent  false   mBlockTouches="+mBlockTouches);
            return false;
        }
        // Do not allow panel expansion if bouncer is scrimmed, otherwise user would be able to pull down QS or expand the shade.
        if (mStatusBar.isBouncerShowingScrimmed()) {
            return false;
        }


        // Make sure the next touch won't the blocked after the current ends.
        if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
            mBlockingExpansionForCurrentTouch = false;
        }
        // When touch focus transfer happens, ACTION_DOWN->ACTION_UP may happen immediately without any ACTION_MOVE event.In such case, simply expand the panel instead of being stuck at the bottom bar.
        if (mLastEventSynthesizedDown && event.getAction() == MotionEvent.ACTION_UP) {
            expand(true /* animate */);
        }
        initDownStates(event);
        Log.d(TAG, "onTouchEvent   mIsExpanding="+mIsExpanding);
        if (!mIsExpanding && !shouldQuickSettingsIntercept(mDownX, mDownY, 0)
                && mPulseExpansionHandler.onTouchEvent(event)) {
            // We're expanding all the other ones shouldn't get this anymore
            return true;
        }
        if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp()
                && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
            mIsExpansionFromHeadsUp = true;
            MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1);
        }
        boolean handled = false;
        Log.d(TAG, "onTouchEvent  mAffordanceHelper.isFinishingUnlockAnimationEnabled()="+mAffordanceHelper.isFinishingUnlockAnimationEnabled());


        if (((mAffordanceHelper.isFinishingUnlockAnimationEnabled())
                || (!mIsExpanding || mHintAnimationRunning))
                && !mQsExpanded
                && mBarState != StatusBarState.SHADE
                && !mDozing) {
            handled |= mAffordanceHelper.onTouchEvent(event);
        }
        if (mOnlyAffordanceInThisMotion) {
            return true;
        }
        handled |= mHeadsUpTouchHelper.onTouchEvent(event);


        if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) {
            return true;
        }
        if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
            MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1);
            updateVerticalPanelPosition(event.getX());
            handled = true;
        }
        handled |= super.onTouchEvent(event);
//      return !mDozing || mPulsing || handled;
        Log.d(TAG, "onTouchEvent("+(!mDozing || mPulsing || handled)+"  mDozing="+mDozing+"   mPulsing="+mPulsing+"   handled="+handled);
        return !mDozing || handled;
    }

從上面看到,onTouchEvent 的幾個常用見得行爲(MotionEvent.ACTION_DOWN、MotionEvent.ACTION_MOVE、MotionEvent.ACTION_UP)最終還是要傳給它的父類PanelView處理,所以在看看PanelView的onTouchEvent的處理流程:


   @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mInstantExpanding|| (mTouchDisabled && event.getActionMasked() != MotionEvent.ACTION_CANCEL)|| (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN)) {
            return false;
        }
        // If dragging should not expand the notifications shade, then return false.
        if (!mNotificationsDragEnabled) {/*不展開通知陰影*/
            if (mTracking) {
                // Turn off tracking if it's on or the shade can get stuck in the down position.
                onTrackingStopped(true /* expand */);
            }
            return false;
        }


        // On expanding, single mouse click expands the panel instead of dragging.
        if (isFullyCollapsed() && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                expand(true);
            }
            return true;
        }


        /*
         * We capture touch events here and update the expand height here in case according to the users fingers. This also handles multi-touch.
         *If the user just clicks shortly, we show a quick peek of the shade.
         * Flinging is also enabled in order to open or close the shade.
         */


        int pointerIndex = event.findPointerIndex(mTrackingPointer);
        if (pointerIndex < 0) {
            pointerIndex = 0;
            mTrackingPointer = event.getPointerId(pointerIndex);
        }
        final float x = event.getX(pointerIndex);
        final float y = event.getY(pointerIndex);
/*  此處獲得點擊位置的x&&y座標*/
        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
            mGestureWaitForTouchSlop = shouldGestureWaitForTouchSlop();
            mIgnoreXTouchSlop = isFullyCollapsed() || shouldGestureIgnoreXTouchSlop(x, y);
        }


        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:/*處理按下的事件*/
                startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
                mJustPeeked = false;
                mMinExpandHeight = 0.0f;
                mPanelClosedOnDown = isFullyCollapsed();
                mHasLayoutedSinceDown = false;
                mUpdateFlingOnLayout = false;
                mMotionAborted = false;
                mPeekTouching = mPanelClosedOnDown;
                mDownTime = SystemClock.uptimeMillis();
                mTouchAboveFalsingThreshold = false;
                mCollapsedAndHeadsUpOnDown = isFullyCollapsed()&& mHeadsUpManager.hasPinnedHeadsUp();
                addMovement(event);/*這個方法跟着move的行爲*/
                if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning)|| mPeekAnimator != null) {
                    mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning)|| mPeekAnimator != null || mTouchSlopExceededBeforeDown;
                    cancelHeightAnimator();
                    cancelPeek();
                    onTrackingStarted();
                }
                if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()&& !mStatusBar.isBouncerShowing()) {
                    startOpening(event);/*if Phine is Fully Collapsed && HeadsUpManager has not Pinned HeadsUp && StatusBaris Bouncer Showing(),the pull-down animation will run*/
                }
                break;


            case MotionEvent.ACTION_POINTER_UP:
                final int upPointer = event.getPointerId(event.getActionIndex());
                if (mTrackingPointer == upPointer) {
                    // gesture is ongoing, find a new pointer to track
                    final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
                    final float newY = event.getY(newIndex);
                    final float newX = event.getX(newIndex);
                    mTrackingPointer = event.getPointerId(newIndex);
                    startExpandMotion(newX, newY, true /* startTracking */, mExpandedHeight);
                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
                    mMotionAborted = true;
                    endMotionEvent(event, x, y, true /* forceCancel */);
                    return false;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                addMovement(event);
                float h = y - mInitialTouchY;


                // If the panel was collapsed when touching, we only need to check for the y-component of the gesture, as we have no conflicting horizontal gesture.
                if (Math.abs(h) > mTouchSlop && (Math.abs(h) > Math.abs(x - mInitialTouchX) || mIgnoreXTouchSlop)) {/*滑動行爲處理,如果x方向或者y方向移動大於8dip 就認爲是在滑動*/
                    mTouchSlopExceeded = true;
                    if (mGestureWaitForTouchSlop && !mTracking && !mCollapsedAndHeadsUpOnDown) {
                        if (!mJustPeeked && mInitialOffsetOnTouch != 0f) {
                            startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
                            h = 0;
                        }
                        cancelHeightAnimator();
                        onTrackingStarted();
                    }
                }
                float newHeight = Math.max(0, h + mInitialOffsetOnTouch);/*計算新的展開高度*/
                if (newHeight > mPeekHeight) {
                    if (mPeekAnimator != null) {
                        mPeekAnimator.cancel();/*取消下拉通知面板行爲*/
                    }
                    mJustPeeked = false;
                } else if (mPeekAnimator == null && mJustPeeked) {
                    // The initial peek has finished, but we haven't dragged as far yet, lets speed it up by starting at the peek height.
                    mInitialOffsetOnTouch = mExpandedHeight;
                    mInitialTouchY = y;
                    mMinExpandHeight = mExpandedHeight;
                    mJustPeeked = false;
                }
                newHeight = Math.max(newHeight, mMinExpandHeight);
                if (-h >= getFalsingThreshold()) {
                    mTouchAboveFalsingThreshold = true;
                    mUpwardsWhenTresholdReached = isDirectionUpwards(x, y);
                }
                if (!mJustPeeked && (!mGestureWaitForTouchSlop || mTracking) &&
                        !isTrackingBlocked()) {
                    setExpandedHeightInternal(newHeight);
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
              if (isFullyCollapsed() && event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
                    if (mTracking) {
                        onTrackingStopped(false);
                    }
                    return true;
                }
                addMovement(event);
                endMotionEvent(event, x, y, false /* forceCancel */); /*這個方法會出來手指離開屏幕那一刻的觸摸事件*/
                break;
        }
        return !mGestureWaitForTouchSlop || mTracking;
    }

在該方法中:

  1. MotionEvent.ACTION_DOWN時,如果notification面板沒有展開,點擊則會展開notification面板
  2. 在放開屏幕是,會執行一個endMotionEvent邏輯,然後裏面也有展開notification面板操作

然後看看endMotionEvent方法的實現


    private void endMotionEvent(MotionEvent event, float x, float y, boolean forceCancel) {
        mTrackingPointer = -1;
        if ((mTracking && mTouchSlopExceeded)|| Math.abs(x - mInitialTouchX) > mTouchSlop || Math.abs(y - mInitialTouchY) > mTouchSlop|| event.getActionMasked() == MotionEvent.ACTION_CANCEL|| forceCancel) {
            mVelocityTracker.computeCurrentVelocity(1000);
            float vel = mVelocityTracker.getYVelocity();
            float vectorVel = (float) Math.hypot(
                    mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
            if (isOnClickdToStartPeekAnimationDisable && (Math.abs(x - mInitialTouchX) > 2 * mTouchSlop || Math.abs(y - mInitialTouchY) > 2 * mTouchSlop)) {
                Log.d(TAG, "a move event has happened! mTouchSlop is double length!");
                mLongTouchSlop = true;
            }
            boolean expand = flingExpands(vel, vectorVel, x, y)
                    || event.getActionMasked() == MotionEvent.ACTION_CANCEL
                    || forceCancel;
            DozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
                    mStatusBar.isFalsingThresholdNeeded(),
                    mStatusBar.isWakeUpComingFromTouch());
                    // Log collapse gesture if on lock screen.
                    if (!expand && mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
                        float displayDensity = mStatusBar.getDisplayDensity();
                        int heightDp = (int) Math.abs((y - mInitialTouchY) / displayDensity);
                        int velocityDp = (int) Math.abs(vel / displayDensity);
                        mLockscreenGestureLogger.write(
                                MetricsEvent.ACTION_LS_UNLOCK,
                                heightDp, velocityDp);
                    }
            fling(vel, expand, isFalseTouch(x, y));
            onTrackingStopped(expand);
            mUpdateFlingOnLayout = expand && mPanelClosedOnDown && !mHasLayoutedSinceDown;
            if (mUpdateFlingOnLayout) {
                mUpdateFlingVelocity = vel;
            }
        } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking
                && !mStatusBar.isBouncerShowing() && !mKeyguardMonitor.isKeyguardFadingAway()) {
            long timePassed = SystemClock.uptimeMillis() - mDownTime;


            if (timePassed < ViewConfiguration.getLongPressTimeout() && !isOnClickdToStartPeekAnimationDisable) {
                // Lets show the user that he can actually expand the panel
                runPeekAnimation(PEEK_ANIMATION_DURATION, getPeekHeight(), true /* collapseWhenFinished */);
            } else {
                // We need to collapse the panel since we peeked to the small height.
                postOnAnimation(mPostCollapseRunnable);
            }


        } else if (!mStatusBar.isBouncerShowing()) {
            boolean expands = onEmptySpaceClick(mInitialTouchX);
            onTrackingStopped(expands);
        }


        mVelocityTracker.clear();
        mPeekTouching = false;
    }

3. solution


diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 76407e1..e88d968 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -124,6 +124,12 @@ public abstract class PanelView extends FrameLayout {
     private final FalsingManager mFalsingManager;
     private final VibratorHelper mVibratorHelper;
 
+    // fix bug Add-S
+    private boolean isOnClickdToStartPeekAnimationDisable =true;
+    private boolean mLongTouchSlop=false;
+    // fix bug Add-E
+
+
     /**
      * For PanelView fling perflock call
      */
@@ -352,10 +358,12 @@ public abstract class PanelView extends FrameLayout {
                     cancelPeek();
                     onTrackingStarted();
                 }
+                // fix bug Mod-S
                 if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()
-                        && !mStatusBar.isBouncerShowing()) {
+                        && !mStatusBar.isBouncerShowing() && !isOnClickdToStartPeekAnimationDisable) {
                     startOpening(event);
                 }
+                // fix bug Mod-E
                 break;
 
             case MotionEvent.ACTION_POINTER_UP:
@@ -507,10 +515,17 @@ public abstract class PanelView extends FrameLayout {
             float vel = mVelocityTracker.getYVelocity();
             float vectorVel = (float) Math.hypot(
                     mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
-
+            // fix bug Add-S
+            if(isOnClickdToStartPeekAnimationDisable && (Math.abs(x - mInitialTouchX) > 2*mTouchSlop || Math.abs(y - mInitialTouchY) > 2*mTouchSlop)){
+                Log.d(TAG,"a move event has happened! mTouchSlop is double length!");
+                mLongTouchSlop=true;
+            }
+            // fix bug Add-E
             boolean expand = flingExpands(vel, vectorVel, x, y)
                     || event.getActionMasked() == MotionEvent.ACTION_CANCEL
                     || forceCancel;
+            
+
             DozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
                     mStatusBar.isFalsingThresholdNeeded(),
                     mStatusBar.isWakeUpComingFromTouch());
@@ -532,13 +547,15 @@ public abstract class PanelView extends FrameLayout {
         } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking
                 && !mStatusBar.isBouncerShowing() && !mKeyguardMonitor.isKeyguardFadingAway()) {
             long timePassed = SystemClock.uptimeMillis() - mDownTime;
-            if (timePassed < ViewConfiguration.getLongPressTimeout()) {
+            // fix bug Mod-S
+            if (timePassed < ViewConfiguration.getLongPressTimeout() && !isOnClickdToStartPeekAnimationDisable) {
                 // Lets show the user that he can actually expand the panel
                 runPeekAnimation(PEEK_ANIMATION_DURATION, getPeekHeight(), true /* collapseWhenFinished */);
             } else {
                 // We need to collapse the panel since we peeked to the small height.
                 postOnAnimation(mPostCollapseRunnable);
             }
+            // fix bug Mod-S
         } else if (!mStatusBar.isBouncerShowing()) {
             boolean expands = onEmptySpaceClick(mInitialTouchX);
             onTrackingStopped(expands);
@@ -721,6 +738,13 @@ public abstract class PanelView extends FrameLayout {
         if (Math.abs(vectorVel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
             return shouldExpandWhenNotFlinging();
         } else {
+            // fix bug Add-S
+            if(isOnClickdToStartPeekAnimationDisable && !mLongTouchSlop){
+                return false;
+            }else {
+                mLongTouchSlop=false;
+            }
+            // fix bug Add-E
             return vel > 0;
         }
     }
@@ -762,9 +786,11 @@ public abstract class PanelView extends FrameLayout {
             boolean expandBecauseOfFalsing) {
         cancelPeek();
         float target = expand ? getMaxPanelHeight() : 0;
+
         if (!expand) {
             mClosing = true;
         }
+        Log.d(TAG,"fling,target ="+target +",vel="+vel+",expand="+expand+".collapseSpeedUpFactor="+collapseSpeedUpFactor+",expandBecauseOfFalsing="+expandBecauseOfFalsing);
         flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
     }
 
@@ -787,6 +813,7 @@ public abstract class PanelView extends FrameLayout {
         ValueAnimator animator = createHeightAnimator(target);
         if (expand) {
             if (expandBecauseOfFalsing && vel < 0) {
+                Log.d(TAG,"expandBecauseOfFalsing && vel < 0");
                 vel = 0;
             }
             mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, getHeight());
@@ -804,6 +831,7 @@ public abstract class PanelView extends FrameLayout {
                             getHeight());
                 }
             } else {
+                Log.d(TAG,"mFlingAnimationUtilsClosing!");
                 mFlingAnimationUtilsClosing
                         .apply(animator, mExpandedHeight, target, vel, getHeight());
             }

4. summary

+".collapseSpeedUpFactor="+collapseSpeedUpFactor+",expandBecauseOfFalsing="+expandBecauseOfFalsing);
flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
}

@@ -787,6 +813,7 @@ public abstract class PanelView extends FrameLayout {
ValueAnimator animator = createHeightAnimator(target);
if (expand) {
if (expandBecauseOfFalsing && vel < 0) {

  •            Log.d(TAG,"expandBecauseOfFalsing && vel < 0");
               vel = 0;
           }
           mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, getHeight());
    

@@ -804,6 +831,7 @@ public abstract class PanelView extends FrameLayout {
getHeight());
}
} else {

  •            Log.d(TAG,"mFlingAnimationUtilsClosing!");
               mFlingAnimationUtilsClosing
                       .apply(animator, mExpandedHeight, target, vel, getHeight());
           }
    





## 4. summary


該問題主要涉及到狀態欄的onTouchEvent事件,只需要找到對應得處理邏輯就可以屏蔽點擊事件。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章