CTS之Keyguard Menu事件处理
事件触发点:
NotificationShadeWindowViewController.dispatchKeyEvent
设置setInteractionEventHandler
回调之后通过NotificationShadeWindowView
触发
调用到return mService.onMenuPressed();
public class NotificationShadeWindowViewController {
public void setupExpandedStatusBar() {
mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
//省略代码
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_BACK:
if (!down) {
mService.onBackPressed();
}
return true;
case KeyEvent.KEYCODE_MENU:
if (!down) {
return mService.onMenuPressed();//☆☆☆☆
}
break;
case KeyEvent.KEYCODE_SPACE:
if (!down) {
return mService.onSpacePressed();
}
break;
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
if (mStatusBarStateController.isDozing()) {
MediaSessionLegacyHelper.getHelper(mView.getContext())
.sendVolumeKeyEvent(
event, AudioManager.USE_DEFAULT_STREAM_TYPE, true);
return true;
}
break;
}
return false;
}
});
}
}
public class NotificationShadeWindowView extends FrameLayout {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (mInteractionEventHandler.interceptMediaKey(event)) {
return true;
}
if (super.dispatchKeyEvent(event)) {
return true;
}
return mInteractionEventHandler.dispatchKeyEvent(event);//☆☆☆☆
}
}
以上通过接口会调用到
StatusBar
类中去
public class StatusBar{
public boolean onMenuPressed() {
if (shouldUnlockOnMenuPressed()) {
mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);//☆☆☆☆
return true;
}
return false;
}}
public class ShadeControllerImpl implements ShadeController {
@Override
public void animateCollapsePanels(int flags, boolean force) {
animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);//☆☆☆☆
}
@Override
public void animateCollapsePanels(int flags, boolean force, boolean delayed,
float speedUpFactor) {
if (!force && mStatusBarStateController.getState() != StatusBarState.SHADE) {
runPostCollapseRunnables();
return;
}
if (SPEW) {
Log.d(TAG, "animateCollapse():"
+ " mExpandedVisible=" + getStatusBar().isExpandedVisible()
+ " flags=" + flags);
}
if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
getStatusBar().postHideRecentApps();
}
// TODO(b/62444020): remove when this bug is fixed
Log.v(TAG, "NotificationShadeWindow: " + getNotificationShadeWindowView()
+ " canPanelBeCollapsed(): "
+ getNotificationPanelViewController().canPanelBeCollapsed());
if (getNotificationShadeWindowView() != null
&& getNotificationPanelViewController().canPanelBeCollapsed()) {
// release focus immediately to kick off focus change transition
mNotificationShadeWindowController.setNotificationShadeFocusable(false);
getStatusBar().getNotificationShadeWindowViewController().cancelExpandHelper();
getStatusBarView().collapsePanel(true /* animate */, delayed, speedUpFactor);//☆☆☆☆
} else {
mBubbleControllerLazy.get().collapseStack();
}
}
}
public abstract class PanelBar extends FrameLayout {
public void collapsePanel(boolean animate, boolean delayed, float speedUpFactor) {
boolean waiting = false;
PanelViewController pv = mPanel;
if (animate && !pv.isFullyCollapsed()) {
pv.collapse(delayed, speedUpFactor);
waiting = true;
} else {
pv.resetViews(false /* animate */);
pv.setExpandedFraction(0); // just in case
pv.cancelPeek();
}
if (DEBUG) LOG("collapsePanel: animate=%s waiting=%s", animate, waiting);
if (!waiting && mState != STATE_CLOSED) {
// it's possible that nothing animated, so we replicate the termination
// conditions of panelExpansionChanged here
go(STATE_CLOSED);
onPanelCollapsed();//☆☆☆☆
}
}
}
public class PhoneStatusBarView extends PanelBar {
private Runnable mHideExpandedRunnable = new Runnable() {
@Override
public void run() {
if (mPanelFraction == 0.0f) {
mBar.makeExpandedInvisible();//☆☆☆☆
}
}
};
@Override
public void onPanelCollapsed() {
super.onPanelCollapsed();
// Close the status bar in the next frame so we can show the end of the animation.
post(mHideExpandedRunnable);//☆☆☆☆
mIsFullyOpenedPanel = false;
}
}
public class StatusBar extends SystemUI {
void makeExpandedInvisible() {
if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
+ " mExpandedVisible=" + mExpandedVisible);
if (!mExpandedVisible || mNotificationShadeWindowView == null) {
return;
}
// Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/,
1.0f /* speedUpFactor */);
mNotificationPanelViewController.closeQs();
mExpandedVisible = false;
visibilityChanged(false);
// Update the visibility of notification shade and status bar window.
mNotificationShadeWindowController.setPanelVisible(false);
mStatusBarWindowController.setForceStatusBarVisible(false);
// Close any guts that might be visible
mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
mShadeController.runPostCollapseRunnables();
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
if (!mNotificationActivityStarter.isCollapsingToShowActivityOverLockscreen()) {
showBouncerIfKeyguard();//☆☆☆☆
} else if (DEBUG) {
Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
}
mCommandQueue.recomputeDisableFlags(
mDisplayId,
mNotificationPanelViewController.hideStatusBarIconsWhenExpanded() /* animate */);
// Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
// the bouncer appear animation.
if (!mStatusBarKeyguardViewManager.isShowing()) {
WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
}
}
private void showBouncerIfKeyguard() {
if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
&& !mKeyguardViewMediator.isHiding()) {
mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */); //☆☆☆☆
}
}
}
public class StatusBarKeyguardViewManager {
public void showBouncer(boolean scrimmed) {
if (mShowing && !mBouncer.isShowing()) {
mBouncer.show(false /* resetSecuritySelection */, scrimmed);//☆☆☆☆
}
updateStates();
}
}
public class KeyguardBouncer {
private final Runnable mShowRunnable = new Runnable() {
@Override
public void run() {
mRoot.setVisibility(View.VISIBLE);
showPromptReason(mBouncerPromptReason);
final CharSequence customMessage = mCallback.consumeCustomMessage();
if (customMessage != null) {
mKeyguardView.showErrorMessage(customMessage);
}
// We might still be collapsed and the view didn't have time to layout yet or still
// be small, let's wait on the predraw to do the animation in that case.
if (mKeyguardView.getHeight() != 0 && mKeyguardView.getHeight() != mStatusBarHeight) {
mKeyguardView.startAppearAnimation();
} else {
mKeyguardView.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
mKeyguardView.getViewTreeObserver().removeOnPreDrawListener(this);
mKeyguardView.startAppearAnimation();//☆☆☆☆
return true;
}
});
mKeyguardView.requestLayout();
}
mShowingSoon = false;
if (mExpansion == EXPANSION_VISIBLE) {
mKeyguardView.onResume();
mKeyguardView.resetSecurityContainer();
showPromptReason(mBouncerPromptReason);
}
SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN);
}
};
public void show(boolean resetSecuritySelection, boolean isScrimmed) {
final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
// In split system user mode, we never unlock system user.
return;
}
ensureView();
mIsScrimmed = isScrimmed;
// On the keyguard, we want to show the bouncer when the user drags up, but it's
// not correct to end the falsing session. We still need to verify if those touches
// are valid.
// Later, at the end of the animation, when the bouncer is at the top of the screen,
// onFullyShown() will be called and FalsingManager will stop recording touches.
if (isScrimmed) {
setExpansion(EXPANSION_VISIBLE);
}
if (resetSecuritySelection) {
// showPrimarySecurityScreen() updates the current security method. This is needed in
// case we are already showing and the current security method changed.
showPrimarySecurityScreen();
}
if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
return;
}
final int activeUserId = KeyguardUpdateMonitor.getCurrentUser();
final boolean isSystemUser =
UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;
final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;
// If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
// set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) {
return;
}
// This condition may indicate an error on Android, so log it.
if (!allowDismissKeyguard) {
Log.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != " + keyguardUserId);
}
mShowingSoon = true;
// Split up the work over multiple frames.
DejankUtils.removeCallbacks(mResetRunnable);
if (mKeyguardStateController.isFaceAuthEnabled() && !needsFullscreenBouncer()
&& !mKeyguardUpdateMonitor.userNeedsStrongAuth()
&& !mKeyguardBypassController.getBypassEnabled()) {
mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);//☆☆☆☆
} else {
DejankUtils.postAfterTraversal(mShowRunnable);//☆☆☆☆
}
mCallback.onBouncerVisiblityChanged(true /* shown */);
mExpansionCallback.onStartingToShow();
}
}
public class KeyguardHostView extends FrameLayout implements SecurityCallback {
public void startAppearAnimation() {
mSecurityContainer.startAppearAnimation();//☆☆☆☆
}
}
public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
public void startAppearAnimation() {
if (mCurrentSecuritySelection != SecurityMode.None) {
getSecurityView(mCurrentSecuritySelection).startAppearAnimation();//☆☆☆☆
}
}
}
public class KeyguardPINView extends KeyguardPinBasedInputView {
@Override
public void startAppearAnimation() {
enableClipping(false);
setAlpha(1f);//☆☆☆☆
setTranslationY(mAppearAnimationUtils.getStartTranslation());
AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 500 /* duration */,
0, mAppearAnimationUtils.getInterpolator());
mAppearAnimationUtils.startAnimation2d(mViews,
new Runnable() {
@Override
public void run() {
enableClipping(true);
}
});
}
}