1.功用描绘
2.相关类
>GestureLauncherService
frameworks/base/services/core/java/com/android/server/GestureLauncherService.java
现在只支持相机手势
/**
* The service that listens for gestures detected in sensor firmware and starts the intent
* accordingly.
* <p>For now, only camera launch gesture is supported, and in the future, more gestures can be
* added.</p>
* @hide
*/
public class GestureLauncherService extends SystemService {
private static final boolean DBG = false;
@Override
public void onStart() {
LocalServices.addService(GestureLauncherService.class, this);
}
这个类是在SystemService里调用的
if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) {
t.traceBegin("StartGestureLauncher");
//这个主要是调用GestureLauncherService的onStart办法
mSystemServiceManager.startService(GestureLauncherService.class);
t.traceEnd();
}
相关办法
/**
* Whether GestureLauncherService should be enabled according to system properties.
*/
public static boolean isGestureLauncherEnabled(Resources resources) {
return isCameraLaunchEnabled(resources)
|| isCameraDoubleTapPowerEnabled(resources)
|| isCameraLiftTriggerEnabled(resources)
|| isEmergencyGestureEnabled(resources);
}
>> —
默许配置里id是-1,所以这儿的listener不会注册,
int cameraLaunchGestureId = resources.getInteger(
com.android.internal.R.integer.config_cameraLaunchGestureSensorType);
if (cameraLaunchGestureId != -1) {
这个没有注册,不必研讨
private final class GestureEventListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {
if (!mCameraLaunchRegistered) {
return;
}
if (event.sensor == mCameraLaunchSensor) {
if (handleCameraGesture(true /* useWakelock */,
StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) {
mMetricsLogger.action(MetricsEvent.ACTION_WIGGLE_CAMERA_GESTURE);
mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_WIGGLE);
trackCameraLaunchEvent(event);
}
return;
}
}
3.PhoneWindowManager.java
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
/**
* WindowManagerPolicy implementation for the Android phone UI. This
* introduces a new method suffix, Lp, for an internal lock of the
* PhoneWindowManager. This is used to protect some internal state, and
* can be acquired with either the Lw and Li lock held, so has the restrictions
* of both of those when held.
*/
public class PhoneWindowManager implements WindowManagerPolicy {
获取GestureLauncherService的实例
public void systemReady() {
// In normal flow, systemReady is called before other system services are ready.
// So it is better not to bind keyguard here.
mKeyguardDelegate.onSystemReady();
//...
mGestureLauncherService = LocalServices.getService(GestureLauncherService.class);
}
>handleCameraGesture
查下上述实例调用的当地
// The camera gesture will be detected by GestureLauncherService.
private boolean handleCameraGesture(KeyEvent event, boolean interactive) {
// camera gesture.
if (mGestureLauncherService == null) {
return false;
}
mCameraGestureTriggered = false;
final MutableBoolean outLaunched = new MutableBoolean(false);
//这儿用到了
final boolean intercept =
mGestureLauncherService.interceptPowerKeyDown(event, interactive, outLaunched);
if (!outLaunched.value) {
// If GestureLauncherService intercepted the power key, but didn't launch camera app,
// we should still return the intercept result. This prevents the single key gesture
// detector from processing the power key later on.
return intercept;
}
mCameraGestureTriggered = true;
if (mRequestedOrSleepingDefaultDisplay) {
mCameraGestureTriggeredDuringGoingToSleep = true;
// Wake device up early to prevent display doing redundant turning off/on stuff.
wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromPowerKey,
PowerManager.WAKE_REASON_CAMERA_LAUNCH,
"android.policy:CAMERA_GESTURE_PREVENT_LOCK");
}
return true;
}
>handleKeyGesture
继续检查上述办法在哪里被调用
private void handleKeyGesture(KeyEvent event, boolean interactive) {
if (mKeyCombinationManager.interceptKey(event, interactive)) {
// handled by combo keys manager.
mSingleKeyGestureDetector.reset();
return;
}
if (event.getKeyCode() == KEYCODE_POWER && event.getAction() == KeyEvent.ACTION_DOWN) {
//这儿
mPowerKeyHandled = handleCameraGesture(event, interactive);
if (mPowerKeyHandled) {
// handled by camera gesture.
mSingleKeyGestureDetector.reset();
return;
}
}
mSingleKeyGestureDetector.interceptKey(event, interactive);
}
>interceptKeyBeforeQueueing
继续检查handleKeyGesture办法的调用
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
final int keyCode = event.getKeyCode();
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
|| event.isWakeKey();
if (!mSystemBooted) {
//系统还没发动的时候,不处理key event
return 0;
}
//...
// Basic policy based on interactive state.
int result;
if (interactive || (isInjected && !isWakeKey)) {
// When the device is interactive or the key is injected pass the
// key to the application.
result = ACTION_PASS_TO_USER;
isWakeKey = false;
if (interactive) {
// If the screen is awake, but the button pressed was the one that woke the device
// then don't pass it to the application
if (keyCode == mPendingWakeKey && !down) {
result = 0;
}
// Reset the pending key
mPendingWakeKey = PENDING_KEY_NULL;
}
} else if (shouldDispatchInputWhenNonInteractive(displayId, keyCode)) {
// If we're currently dozing with the screen on and the keyguard showing, pass the key
// to the application but preserve its wake key status to make sure we still move
// from dozing to fully interactive if we would normally go from off to fully
// interactive.
result = ACTION_PASS_TO_USER;
// Since we're dispatching the input, reset the pending key
mPendingWakeKey = PENDING_KEY_NULL;
} else {
// When the screen is off and the key is not injected, determine whether
// to wake the device but don't pass the key to the application.
result = 0;
if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
isWakeKey = false;
}
// Cache the wake key on down event so we can also avoid sending the up event to the app
if (isWakeKey && down) {
mPendingWakeKey = keyCode;
}
}
// If the key would be handled globally, just return the result, don't worry about special
// key processing.
if (isValidGlobalKey(keyCode)
&& mGlobalKeyManager.shouldHandleGlobalKey(keyCode)) {
// Dispatch if global key defined dispatchWhenNonInteractive.
if (!interactive && isWakeKey && down
&& mGlobalKeyManager.shouldDispatchFromNonInteractive(keyCode)) {
mGlobalKeyManager.setBeganFromNonInteractive();
result = ACTION_PASS_TO_USER;
// Since we're dispatching the input, reset the pending key
mPendingWakeKey = PENDING_KEY_NULL;
}
if (isWakeKey) {
wakeUpFromWakeKey(event);
}
return result;
}
// Alternate TV power to power key for Android TV device.
final HdmiControlManager hdmiControlManager = getHdmiControlManager();
if (keyCode == KeyEvent.KEYCODE_TV_POWER && mHasFeatureLeanback
&& (hdmiControlManager == null || !hdmiControlManager.shouldHandleTvPowerKey())) {
event = KeyEvent.obtain(
event.getDownTime(), event.getEventTime(),
event.getAction(), KeyEvent.KEYCODE_POWER,
event.getRepeatCount(), event.getMetaState(),
event.getDeviceId(), event.getScanCode(),
event.getFlags(), event.getSource(), event.getDisplayId(), null);
//递归调用自己?
return interceptKeyBeforeQueueing(event, policyFlags);
}
// This could prevent some wrong state in multi-displays environment,
// the default display may turned off but interactive is true.
final boolean isDefaultDisplayOn = Display.isOnState(mDefaultDisplay.getState());
final boolean interactiveAndOn = interactive && isDefaultDisplayOn;
if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
//这儿调用的
handleKeyGesture(event, interactiveAndOn);
}
>interceptFallback
继续查
private boolean interceptFallback(IBinder focusedToken, KeyEvent fallbackEvent,
int policyFlags) {
//这儿
int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
if ((actions & ACTION_PASS_TO_USER) != 0) {
long delayMillis = interceptKeyBeforeDispatching(
focusedToken, fallbackEvent, policyFlags);
if (delayMillis == 0 && !interceptUnhandledKey(fallbackEvent)) {
return true;
}
}
return false;
}
>dispatchUnhandledKey
继续
public KeyEvent dispatchUnhandledKey(IBinder focusedToken, KeyEvent event, int policyFlags) {
// Note: This method is only called if the initial down was unhandled.
//...
//这儿处理下3个特殊的键,空格,z键,system request键
if (interceptUnhandledKey(event)) {
return null;
}
KeyEvent fallbackEvent = null;
if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
final KeyCharacterMap kcm = event.getKeyCharacterMap();
final int keyCode = event.getKeyCode();
final int metaState = event.getMetaState();
final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN
&& event.getRepeatCount() == 0;
// Check for fallback actions specified by the key character map.
final FallbackAction fallbackAction;
if (initialDown) {
fallbackAction = kcm.getFallbackAction(keyCode, metaState);
} else {
fallbackAction = mFallbackActions.get(keyCode);
}
if (fallbackAction != null) {
final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
fallbackEvent = KeyEvent.obtain(
event.getDownTime(), event.getEventTime(),
event.getAction(), fallbackAction.keyCode,
event.getRepeatCount(), fallbackAction.metaState,
event.getDeviceId(), event.getScanCode(),
flags, event.getSource(), event.getDisplayId(), null);
//这儿调用的
if (!interceptFallback(focusedToken, fallbackEvent, policyFlags)) {
fallbackEvent.recycle();
fallbackEvent = null;
}
if (initialDown) {
mFallbackActions.put(keyCode, fallbackAction);
} else if (event.getAction() == KeyEvent.ACTION_UP) {
mFallbackActions.remove(keyCode);
fallbackAction.recycle();
}
}
}
return fallbackEvent;
}
4.GestureLauncherService
>interceptPowerKeyDown
这个办法便是PhoneWindowManger类的handleCameraGesture办法里调用的
/**
* Attempts to intercept power key down event by detecting certain gesture patterns
*
* @param interactive true if the event's policy contains {@code FLAG_INTERACTIVE}
* @param outLaunched true if some action is taken as part of the key intercept (eg, app launch)
* @return true if the key down event is intercepted
*/
public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive,
MutableBoolean outLaunched) {
//先判别emergency手势相关
if (mEmergencyGestureEnabled && mEmergencyGesturePowerButtonCooldownPeriodMs >= 0
&& event.getEventTime() - mLastEmergencyGestureTriggered
< mEmergencyGesturePowerButtonCooldownPeriodMs) {
outLaunched.value = false;
return true;
}
//长按的话不做处理
if (event.isLongPress()) {
// Long presses are sent as a second key down. If the long press threshold is set lower
// than the double tap of sequence interval thresholds, this could cause false double
// taps or consecutive taps, so we want to ignore the long press event.
outLaunched.value = false;
return false;
}
boolean launchCamera = false;
boolean launchEmergencyGesture = false;
boolean intercept = false;
long powerTapInterval;
synchronized (this) {
powerTapInterval = event.getEventTime() - mLastPowerDown;
mLastPowerDown = event.getEventTime();
两次距离大于300ms的,本次event当做初始事情
if (powerTapInterval >= POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS) {//500ms
// Tap too slow, reset consecutive tap counts.
mFirstPowerDown = event.getEventTime();
mPowerButtonConsecutiveTaps = 1;
mPowerButtonSlowConsecutiveTaps = 1;
} else if (powerTapInterval >= CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) {//300ms
// Tap too slow for shortcuts
mFirstPowerDown = event.getEventTime();
mPowerButtonConsecutiveTaps = 1;
mPowerButtonSlowConsecutiveTaps++;
} else {
// Fast consecutive tap 判别为连续点击
mPowerButtonConsecutiveTaps++;
mPowerButtonSlowConsecutiveTaps++;
}
// Check if we need to launch camera or emergency gesture flows
if (mEmergencyGestureEnabled) {
// Commit to intercepting the powerkey event after the second "quick" tap to avoid
// lockscreen changes between launching camera and the emergency gesture flow.
// Since watch doesn't have camera gesture, only intercept power key event after
// emergency gesture tap count.
//feature watch 指的是手表,手表的话阈值是5次
if (mPowerButtonConsecutiveTaps
> (mHasFeatureWatch ? EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD : 1)) {
intercept = interactive;
}
//连续点击等于5次
if (mPowerButtonConsecutiveTaps == EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD) {
long emergencyGestureSpentTime = event.getEventTime() - mFirstPowerDown;
long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(
mContext.getContentResolver(),
Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS,
EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS);
if (emergencyGestureSpentTime <= emergencyGestureTapDetectionMinTimeMs) {
// 连续点击太快了,比最小值还小,重置event为第一次点击
// Reset consecutive tap counts.
mFirstPowerDown = event.getEventTime();
mPowerButtonConsecutiveTaps = 1;
mPowerButtonSlowConsecutiveTaps = 1;
} else {
//触发紧急手势事情了
launchEmergencyGesture = true;
mMetricsLogger.histogram("emergency_gesture_spent_time",
(int) emergencyGestureSpentTime);
}
}
}
//判别是否满意双击电源键翻开相机的条件
//双击功用功用需要enable,再次2次点击距离小于300ms,继续点击次数是2
if (mCameraDoubleTapPowerEnabled
&& powerTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS
&& mPowerButtonConsecutiveTaps == CAMERA_POWER_TAP_COUNT_THRESHOLD) {
launchCamera = true;
intercept = interactive;
}
}
if (launchCamera) {
//根据上边的判别满意双击翻开相机的逻辑
launchCamera = handleCameraGesture(false /* useWakelock */,
StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
//...
} else if (launchEmergencyGesture) {
Slog.i(TAG, "Emergency gesture detected, launching.");
//处理紧急事情
launchEmergencyGesture = handleEmergencyGesture();
// Record emergency trigger time if emergency UI was launched
if (launchEmergencyGesture) {
synchronized (this) {
mLastEmergencyGestureTriggered = event.getEventTime();
}
}
}
outLaunched.value = launchCamera || launchEmergencyGesture;
// Intercept power key event if the press is part of a gesture (camera, eGesture) and the
// user has completed setup.
return intercept && isUserSetupComplete();
}
>handleCameraGesture
调用发动相机的逻辑,成功的话回来true,不然回来false。
/**
* @return true if camera was launched, false otherwise.
*/
boolean handleCameraGesture(boolean useWakelock, int source) {
try {
boolean userSetupComplete = isUserSetupComplete();
if (!userSetupComplete) {
//
return false;
}
if (useWakelock) {
// Make sure we don't sleep too early
mWakeLock.acquire(500L);
}
StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class);
service.onCameraLaunchGestureDetected(source);
return true;
} finally {
}
}
>handleEmergencyGesture
/**
* @return true if emergency gesture UI was launched, false otherwise.
*/
boolean handleEmergencyGesture() {
try {
boolean userSetupComplete = isUserSetupComplete();
if (!userSetupComplete) {
return false;
}
if (mHasFeatureWatch) {
//这个是手表的逻辑
onEmergencyGestureDetectedOnWatch();
return true;
}
StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class);
service.onEmergencyActionLaunchGestureDetected();
return true;
} finally {
}
}
5.StatusBarManagerInternal
翻开相机以及紧急事情都是这个类处理的,看一下,大部分都是经过一个mBar的对象来处理
/**
* Private API used by NotificationManagerService.
*/
private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() {
private boolean mNotificationLightOn;
//
public void onCameraLaunchGestureDetected(int source) {
if (mBar != null) {
try {
mBar.onCameraLaunchGestureDetected(source);
} catch (RemoteException e) {
}
}
}
/**
* Notifies the status bar that a Emergency Action launch gesture has been detected.
*/
@Override
public void onEmergencyActionLaunchGestureDetected() {
if (mBar != null) {
try {
mBar.onEmergencyActionLaunchGestureDetected();
} catch (RemoteException e) {
}
}
}
这个mBar是外部传进来的
public RegisterStatusBarResult registerStatusBar(IStatusBar bar) {
enforceStatusBarService();
Slog.i(TAG, "registerStatusBar bar=" + bar);
mBar = bar;
>IStatusBar来历
IStatusBar便是下边的那个CommandQueue(继承的IStatusBar.Stub),里面的办法终究又调用的callbacks里的办法
来历CentralSurfacesImpl.java
//结构办法里初始化的,注解生成的
protected final CommandQueue mCommandQueue;
@Override
public void start() {
//...StatusBarManagerService
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
//...
RegisterStatusBarResult result = null;
try {
result = mBarService.registerStatusBar(mCommandQueue);
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
}
mCommandQueue里增加的callback是CentralSurfacesCommandQueueCallbacks
private void inflateStatusBarWindow() {
//...
if (mCommandQueueCallbacks != null) {
mCommandQueue.removeCallback(mCommandQueueCallbacks);
}
mCommandQueueCallbacks =
mCentralSurfacesComponent.getCentralSurfacesCommandQueueCallbacks();
// Connect in to the status bar manager service
mCommandQueue.addCallback(mCommandQueueCallbacks);
CentralSurfacesCommandQueueCallbacks
CentralSurfacesCommandQueueCallbacks getCentralSurfacesCommandQueueCallbacks();
>CentralSurfacesCommandQueueCallbacks
这儿便是详细的翻开相机,以及紧急事情的处理逻辑了
下边的mCentralSurfaces便是CentralSurfacesImpl.java
@CentralSurfacesComponent.CentralSurfacesScope
public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callbacks {
@Override
public void onCameraLaunchGestureDetected(int source) {
mCentralSurfaces.setLastCameraLaunchSource(source);
//是否即将休眠
if (mCentralSurfaces.isGoingToSleep()) {
if (CentralSurfaces.DEBUG_CAMERA_LIFT) {
Slog.d(CentralSurfaces.TAG, "Finish going to sleep before launching camera");
}
//修改了一个boolean值,在goingToSleep完毕的回调里用到,终究又调用了这个callbacks,详见参阅1
mCentralSurfaces.setLaunchCameraOnFinishedGoingToSleep(true);
return;
}
//判别相机是否可用,不可用的话直接return,详见参阅2
if (!mCameraLauncherLazy.get().canCameraGestureBeLaunched(
mNotificationPanelViewController.getBarState())) {
if (CentralSurfaces.DEBUG_CAMERA_LIFT) {
Slog.d(CentralSurfaces.TAG, "Can't launch camera right now");
}
return;
}
//非交互形式,也便是说息屏形式的话,先唤醒设备
if (!mCentralSurfaces.isDeviceInteractive()) {
mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH,
"com.android.systemui:CAMERA_GESTURE");
}
//有轰动逻辑的话来个轰动
vibrateForCameraGesture();
//我们双击电源键终究传递的source便是这个
if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
//告诉keyguard要翻开相机了,好更新一些状况
mKeyguardUpdateMonitor.onCameraLaunched();
}
//下边根据是否有键盘锁,翻开两种不同的camera task
if (!mKeyguardStateController.isShowing()) {
//没有键盘锁
//发动普通相机的代码,详细参阅4
final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext);
cameraIntent.putExtra(CameraIntents.EXTRA_LAUNCH_SOURCE, source);
mCentralSurfaces.startActivityDismissingKeyguard(cameraIntent,
false /* onlyProvisioned */, true /* dismissShade */,
true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
null /* animationController */, UserHandle.CURRENT);
} else {
//有键盘锁
if (!mCentralSurfaces.isDeviceInteractive()) {
// Avoid flickering of the scrim when we instant launch the camera and the bouncer
// comes on.
mCentralSurfaces.acquireGestureWakeLock(
CentralSurfaces.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
}
//唤醒状况,直接发动camera
if (isWakingUpOrAwake()) {
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.reset(true /* hide */);
}
//发动相机,详见参阅5
mCameraLauncherLazy.get().launchCamera(source,
mNotificationPanelViewController.isFullyCollapsed());
mCentralSurfaces.updateScrimController();
} else {
// We need to defer the camera launch until the screen comes on, since otherwise
// we will dismiss us too early since we are waiting on an activity to be drawn and
// incorrectly get notified because of the screen on event (which resumes and pauses
// some activities)
//非唤醒状况,在唤醒完毕的回调里处理,详见参阅3
mCentralSurfaces.setLaunchCameraOnFinishedWaking(true);
}
}
}
@Override
public void onEmergencyActionLaunchGestureDetected() {
Intent emergencyIntent = mCentralSurfaces.getEmergencyActionIntent();
if (emergencyIntent == null) {
Log.wtf(CentralSurfaces.TAG, "Couldn't find an app to process the emergency intent.");
return;
}
if (isGoingToSleep()) {
mCentralSurfaces.setLaunchEmergencyActionOnFinishedGoingToSleep(true);
return;
}
if (!mCentralSurfaces.isDeviceInteractive()) {
mPowerManager.wakeUp(SystemClock.uptimeMillis(),
PowerManager.WAKE_REASON_GESTURE,
"com.android.systemui:EMERGENCY_GESTURE");
}
// TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for
// app-side haptic experimentation.
if (!mKeyguardStateController.isShowing()) {
mCentralSurfaces.startActivityDismissingKeyguard(emergencyIntent,
false /* onlyProvisioned */, true /* dismissShade */,
true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
null /* animationController */, UserHandle.CURRENT);
return;
}
if (!mCentralSurfaces.isDeviceInteractive()) {
// Avoid flickering of the scrim when we instant launch the camera and the bouncer
// comes on.
mCentralSurfaces.acquireGestureWakeLock(
CentralSurfaces.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
}
if (isWakingUpOrAwake()) {
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.reset(true /* hide */);
}
mContext.startActivityAsUser(emergencyIntent, UserHandle.CURRENT);
return;
}
// We need to defer the emergency action launch until the screen comes on, since otherwise
// we will dismiss us too early since we are waiting on an activity to be drawn and
// incorrectly get notified because of the screen on event (which resumes and pauses
// some activities)
mCentralSurfaces.setLaunchEmergencyActionOnFinishedWaking(true);
}
>>参阅1
在isGongingToSleep完毕的回调里处理
final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
// isGoingToSleep 完毕今后的回调
@Override
public void onFinishedGoingToSleep() {
//...
//前边回调里判别isGoingToSleep就把下边这个变量改为true了,所以在isGoingToSleep完毕的时候会走if条件
if (mLaunchCameraOnFinishedGoingToSleep) {
mLaunchCameraOnFinishedGoingToSleep = false;
// This gets executed before we will show Keyguard, so post it in order that the state
// is correct.
//又回调前边的callback了
mMainExecutor.execute(() -> mCommandQueueCallbacks.onCameraLaunchGestureDetected(
mLastCameraLaunchSource));
}
if (mLaunchEmergencyActionOnFinishedGoingToSleep) {
mLaunchEmergencyActionOnFinishedGoingToSleep = false;
// This gets executed before we will show Keyguard, so post it in order that the
// state is correct.
mMainExecutor.execute(
() -> mCommandQueueCallbacks.onEmergencyActionLaunchGestureDetected());
}
updateIsKeyguard();
}
>>参阅2
判别camera是否可用的相关代码,CameraGestureHelper.kt
fun canCameraGestureBeLaunched(statusBarState: Int): Boolean {
if (!centralSurfaces.isCameraAllowedByAdmin) {
return false
}
val resolveInfo: ResolveInfo? = packageManager.resolveActivityAsUser(
getStartCameraIntent(),
PackageManager.MATCH_DEFAULT_ONLY,
KeyguardUpdateMonitor.getCurrentUser()
)
val resolvedPackage = resolveInfo?.activityInfo?.packageName
return (resolvedPackage != null &&
(statusBarState != StatusBarState.SHADE ||
!activityManager.isInForeground(resolvedPackage)))
}
>>参阅3
在wakeup相关的回调里处理
public void setLaunchCameraOnFinishedWaking(boolean launch) {
mLaunchCameraWhenFinishedWaking = launch;
}
@VisibleForTesting
final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
public void onFinishedWakingUp() {
mWakeUpCoordinator.setFullyAwake(true);
mWakeUpCoordinator.setWakingUp(false);
//...
//在唤醒流程完毕的回调里再开始调用相机
if (mLaunchCameraWhenFinishedWaking) {
mCameraLauncherLazy.get().launchCamera(mLastCameraLaunchSource,
mNotificationPanelViewController.isFullyCollapsed());
mLaunchCameraWhenFinishedWaking = false;
}
if (mLaunchEmergencyActionWhenFinishedWaking) {
mLaunchEmergencyActionWhenFinishedWaking = false;
Intent emergencyIntent = getEmergencyActionIntent();
if (emergencyIntent != null) {
mContext.startActivityAsUser(emergencyIntent,
getActivityUserHandle(emergencyIntent));
}
}
updateScrimController();
}
>>参阅4
CameraIntents.kt
fun getInsecureCameraIntent(context: Context): Intent {
val intent = Intent(DEFAULT_INSECURE_CAMERA_INTENT_ACTION)
getOverrideCameraPackage(context)?.let {
intent.setPackage(it)
}
return intent
}
public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned,
final boolean dismissShade, final boolean disallowEnterPictureInPictureWhileLaunching,
final Callback callback, int flags,
@Nullable ActivityLaunchAnimator.Controller animationController,
final UserHandle userHandle) {
if (onlyProvisioned && !mDeviceProvisionedController.isDeviceProvisioned()) return;
//...
Runnable runnable = () -> {
//intent 增加了flag
intent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(flags);
int[] result = new int[]{ActivityManager.START_CANCELED};
mActivityLaunchAnimator.startIntentWithAnimation(animController,
animate, intent.getPackage(), (adapter) -> {
ActivityOptions options = new ActivityOptions(
CentralSurfaces.getActivityOptions(mDisplayId, adapter));
//...
try {
//这个便是终究的发动intent的代码了,详细的便是 ActivityTaskManagerService类
result[0] = ActivityTaskManager.getService().startActivityAsUser(
null, mContext.getBasePackageName(),
mContext.getAttributionTag(),
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
options.toBundle(), userHandle.getIdentifier());
} catch (RemoteException e) {
Log.w(TAG, "Unable to start activity", e);
}
return result[0];
});
if (callback != null) {
callback.onActivityStarted(result[0]);
}
};
Runnable cancelRunnable = () -> {
if (callback != null) {
callback.onActivityStarted(ActivityManager.START_CANCELED);
}
};
//...
//下边便是处理keyguard消失今后发动runnable
executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShadeDirectly,
willLaunchResolverActivity, deferred /* deferred */, animate);
}
>>参阅5
CameraLauncher.java
public void launchCamera(int source, boolean isShadeFullyCollapsed) {
if (!isShadeFullyCollapsed) {
setLaunchingAffordance(true);
}
mCameraGestureHelper.launchCamera(source);
}
fun launchCamera(source: Int) {
val intent: Intent = getStartCameraIntent()
intent.putExtra(CameraIntents.EXTRA_LAUNCH_SOURCE, source)
val wouldLaunchResolverActivity = activityIntentHelper.wouldLaunchResolverActivity(
intent, KeyguardUpdateMonitor.getCurrentUser()
)
if (CameraIntents.isSecureCameraIntent(intent) && !wouldLaunchResolverActivity) {
uiExecutor.execute {
// Normally an activity will set its requested rotation animation on its window.
// However when launching an activity causes the orientation to change this is too
// late. In these cases, the default animation is used. This doesn't look good for
// the camera (as it rotates the camera contents out of sync with physical reality).
// Therefore, we ask the WindowManager to force the cross-fade animation if an
// orientation change happens to occur during the launch.
val activityOptions = ActivityOptions.makeBasic()
activityOptions.setDisallowEnterPictureInPictureWhileLaunching(true)
activityOptions.rotationAnimationHint =
WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS
try {
//这儿也走到start activity了
activityTaskManager.startActivityAsUser(
null,
context.basePackageName,
context.attributionTag,
intent,
intent.resolveTypeIfNeeded(contentResolver),
null,
null,
0,
Intent.FLAG_ACTIVITY_NEW_TASK,
null,
activityOptions.toBundle(),
UserHandle.CURRENT.identifier,
)
} catch (e: RemoteException) {
Log.w(
"CameraGestureHelper",
"Unable to start camera activity",
e
)
}
}
} else {
// We need to delay starting the activity because ResolverActivity finishes itself if
// launched from behind the lock-screen.
//这个终究调的是参阅4里的那个startActivity办法
activityStarter.startActivity(intent, false /* dismissShade */)
}
//如果camera app发动失利,超时后恢复keyguard
centralSurfaces.startLaunchTransitionTimeout()
//保证camera intent能够发动后躲藏keyguard
centralSurfaces.readyForKeyguardDone()
}
other
fun getSecureCameraIntent(context: Context): Intent {
val intent = Intent(DEFAULT_SECURE_CAMERA_INTENT_ACTION)
getOverrideCameraPackage(context)?.let {
intent.setPackage(it)
}
return intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
}
>CommandQueue
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
调用CommandQueue的某个办法今后,里面是经过handler处理的,handler里终究又给到了callback来处理
/**
* This class takes the functions from IStatusBar that come in on
* binder pool threads and posts messages to get them onto the main
* thread, and calls onto Callbacks. It also takes care of
* coalescing these calls so they don't stack up. For the calls
* are coalesced, note that they are all idempotent.
*/
public class CommandQueue extends IStatusBar.Stub implements
CallbackController<Callbacks>,
DisplayManager.DisplayListener {
@Override
public void onCameraLaunchGestureDetected(int source) {
synchronized (mLock) {
mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE);
mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE, source, 0).sendToTarget();
}
}
@Override
public void onEmergencyActionLaunchGestureDetected() {
synchronized (mLock) {
mHandler.removeMessages(MSG_EMERGENCY_ACTION_LAUNCH_GESTURE);
mHandler.obtainMessage(MSG_EMERGENCY_ACTION_LAUNCH_GESTURE).sendToTarget();
}
}
//终究都是这些回调处理的
@Override
public void addCallback(@NonNull Callbacks callbacks) {
mCallbacks.add(callbacks);
// TODO(b/117478341): find a better way to pass disable flags by display.
for (int i = 0; i < mDisplayDisabled.size(); i++) {
int displayId = mDisplayDisabled.keyAt(i);
int disabled1 = getDisabled1(displayId);
int disabled2 = getDisabled2(displayId);
callbacks.disable(displayId, disabled1, disabled2, false /* animate */);
}
}
//handler
private final class H extends Handler {
private H(Looper l) {
super(l);
}
//...
case MSG_CAMERA_LAUNCH_GESTURE:
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onCameraLaunchGestureDetected(msg.arg1);
}
break;
case MSG_EMERGENCY_ACTION_LAUNCH_GESTURE:
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onEmergencyActionLaunchGestureDetected();
}
break;
6.StatusBarManagerService
>结构办法
结构办法里绑定了StatusBarManagerInternal实例
public StatusBarManagerService(Context context) {
mContext = context;
LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
LocalServices.addService(GlobalActionsProvider.class, mGlobalActionsProvider);
>实例化
是在frameworks/base/services/java/com/android/server/SystemServer.java里初始化的
import android.os.ServiceManager;
if (!isWatch) {
try {
statusBar = new StatusBarManagerService(context);
ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar, false,
DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
} catch (Throwable e) {
}
}
>addService
frameworks/base/core/java/android/os/ServiceManager.java
/**
* Place a new @a service called @a name into the service
* manager.
*
* @param name the name of the new service
* @param service the service object
* @param allowIsolated set to true to allow isolated sandboxed processes
* @param dumpPriority supported dump priority levels as a bitmask
* to access this service
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static void addService(String name, IBinder service, boolean allowIsolated,
int dumpPriority) {
try {
getIServiceManager().addService(name, service, allowIsolated, dumpPriority);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
7.总结
双击电源键的手势,流程如下:
最先接纳到手势事情的是InputManagerService.java里的dispatchUnhandledKey办法,
完事传递给 PhoneWindowManager.java里的dispatchUnhandledKey办法,然后依次interceptFallback办法,》interceptKeyBeforeQueueing >>handleKeyGusture >>handleCameraGesture
然后是GestureLauncherService.java的interceptPowerKeyDown办法,》handleCameraGesture办法
继续走到StatusBarManagerInternal的onCameraLaunchGestureDetected办法,里面的详细完成都是经过一个变量mBar来处理的,这个mBar是个CommandQueue,详细完成又是给到了callback,这儿用到的是CentralSurfacesCommandQueueCallbacks.java,所以终究逻辑都在这个类里。