· 一枚大三学生,在实习中接到一个在电话手表的Launcher上实现全局弹框的需求,具体需求会在下面分析;
· 这算是第一次这么认真去阅读源码(要恰饭的嘛)总结了一些自己阅读源码的方法心得,也算是为和我一样第一次接触阅读源码的小伙伴铺路(一开始踩坑太多了,又不知道看哪里有用所以也会失去耐心);
注:本篇文章源码是Android7.1
· 个人建议对照我的流程图,然后自己打开源码去看
· 实在不理解的地方再看我写的源码解析,应该会帮到你
· 同时注意源码用了哪些常见技巧机制(我总结的未必全面)
超级速成法
直接看我的结论
速成法
直接看源码解析
了解Android锁屏是怎么解决这些问题的
研究SystemUI
推荐AS+Git的方式查看,因为AS下载的源码好像不够全.部分被隐藏的也不能直接跳转过去
搜索类通过AS的shift+shift
一定要先看一遍这个,可以少踩很多坑
大致总结一下
起点果然是Zygote——SystemServer——WMS
建议自己看源码,不理解的、乱了或者想找其他需求的看流程图(非常有用)
涉及的源码技巧
阅读源码建议:
1.明确目标
2.明确思路
3.自己看源码
4.怕走错路就看我流程图
5.实在不懂就定位我的源码解析
ps:不想太动脑的直接看源码解析
思路提供:Activity的启动流程
思路提供:AMS与ApplicationThread通信
mRemote 就是我们上面ServiceManager.getService(“activity”)返回的,也就是AMS得BinderProxy,这个BinderProxy会将ApplicationThread的binder 传递到AMS进程,那么AMS就相当于拥有了ApplicationThread得引用。那么就可以远程调用了
思路提供:锁屏的启动流程
可以确定锁屏是一个自定义View
关键与AMS交互的类是KeyguardViewMediator
结论:Activity的生命周期由ActivityThread处理——ActivityThread与AMS通信——锁屏View将想办法与AMS建立关系才能控制Activity的生命周期
先在这解释一下怎么看流程图,理解了后相信很清晰(懒得加箭头了····)
/**
* Handle message sent by {@link #showLocked}.
* @see #SHOW
*/
private void handleShow(Bundle options) {
Trace.beginSection("KeyguardViewMediator#handleShow");
final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
if (mLockPatternUtils.isSecure(currentUser)) {
mLockPatternUtils.getDevicePolicyManager().reportKeyguardSecured(currentUser);
}
synchronized (KeyguardViewMediator.this) {
if (!mSystemReady) {
if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");
return;
} else {
if (DEBUG) Log.d(TAG, "handleShow");
}
setShowingLocked(true);
mStatusBarKeyguardViewManager.show(options);
mHiding = false;
mWakeAndUnlocking = false;
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
updateActivityLockScreenState();//*-这里建立与AMS的连接!
adjustStatusBarLocked();
userActivity();//*-在这里与PowerManager建立起连接!
mShowKeyguardWakeLock.release();
}
mKeyguardDisplayManager.show();
Trace.endSection();
}
private void updateActivityLockScreenState() {
Trace.beginSection("KeyguardViewMediator#updateActivityLockScreenState");
try {
ActivityManagerNative.getDefault().setLockScreenShown(mShowing, mOccluded);//这里建立与AMS连接,这个方法先由ActivityManagerNative内部类来实现
} catch (RemoteException e) {
}
Trace.endSection();
}
/**
* Retrieve the system's default/global activity manager.
*/
static public IActivityManager getDefault() {
return gDefault.get();//为了获得AMS的Binder对象
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");//与获取AMS
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ActivityManagerProxy(obj);//关键是创建这个代理
}
//内部类ActivityManagerProxy
public void setLockScreenShown(boolean showing, boolean occluded) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(showing ? 1 : 0);
data.writeInt(occluded ? 1 : 0);
//这里将会通知AMS执行这个方法
mRemote.transact(SET_LOCK_SCREEN_SHOWN_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
public void setLockScreenShown(boolean showing, boolean occluded) {
if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
+ android.Manifest.permission.DEVICE_POWER);
}
synchronized(this) {
long ident = Binder.clearCallingIdentity();
try {
if (DEBUG_LOCKSCREEN) logLockScreen(" showing=" + showing + " occluded=" + occluded);
mLockScreenShown = (showing && !occluded) ? LOCK_SCREEN_SHOWN : LOCK_SCREEN_HIDDEN;
if (showing && occluded) {
// The lock screen is currently showing, but is occluded by a window that can
// show on top of the lock screen. In this can we want to dismiss the docked
// stack since it will be complicated/risky to try to put the activity on top
// of the lock screen in the right fullscreen configuration.
mStackSupervisor.moveTasksToFullscreenStackLocked(DOCKED_STACK_ID,
mStackSupervisor.mFocusedStack.getStackId() == DOCKED_STACK_ID);
}
updateSleepIfNeededLocked();//做屏幕休眠前的准备
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
void updateSleepIfNeededLocked() {
if (mSleeping && !shouldSleepLocked()) {
mSleeping = false;
startTimeTrackingFocusedActivityLocked();
mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
//*如果需要锁定,请退出睡眠状态.这里只是跳到PowerManager中release(用于释放亮屏锁)
mStackSupervisor.comeOutOfSleepIfNeededLocked();
updateOomAdjLocked();
} else if (!mSleeping && shouldSleepLocked()) {
mSleeping = true;
if (mCurAppTimeTracker != null) {
mCurAppTimeTracker.stop();
}
//*-这里是获取到顶层的Activity,但是在哪里用到还未知
mTopProcessState = ActivityManager.PROCESS_STATE_TOP_SLEEPING;
mStackSupervisor.goingToSleepLocked();//*-从这里出发接触ActivityThread
updateOomAdjLocked();
// Initialize the wake times of all processes.
checkExcessivePowerUsageLocked(false);
mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
}
}
void goingToSleepLocked() {
scheduleSleepTimeout();
if (!mGoingToSleep.isHeld()) {
mGoingToSleep.acquire();
if (mLaunchingActivity.isHeld()) {
if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
throw new IllegalStateException("Calling must be system uid");
}
mLaunchingActivity.release();
mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
}
}
checkReadyForSleepLocked();//检查休眠前的工作是否完成
}
void checkReadyForSleepLocked() {
if (!mService.isSleepingOrShuttingDownLocked()) {
// Do not care.
return;
}
if (!mSleepTimeout) {
boolean dontSleep = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
//遍历Activity任务栈来检查栈内的Activity是否做好了屏幕休眠准备
dontSleep |= stacks.get(stackNdx).checkReadyForSleepLocked();
}
}
}
/**
* @return true if something must be done before going to sleep.
*/
boolean checkReadyForSleepLocked() {
//如果还有正在Resume的Activity
if (mResumedActivity != null) {
// Still have something resumed; can't sleep until it is paused.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
"Sleep => pause with userLeaving=false");
//那就去执行onPause,这么说无论是否顶层的Activity,只要是onResume的都会被执行onPause
startPausingLocked(false, true, null, false);
return true;
}
if (mPausingActivity != null) {
// Still waiting for something to pause; can't sleep yet.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity);
return true;
}
if (hasVisibleBehindActivity()) {
// Stop visible behind activity before going to sleep.
final ActivityRecord r = getVisibleBehindActivity();
mStackSupervisor.mStoppingActivities.add(r);
if (DEBUG_STATES) Slog.v(TAG_STATES, "Sleep still waiting to stop visible behind " + r);
return true;
}
return false;
}
/**
* Start pausing the currently resumed activity. It is an error to call this if there
* is already an activity being paused or there is no resumed activity.
*
* @param userLeaving True if this should result in an onUserLeaving to the current activity.
* @param uiSleeping True if this is happening with the user interface going to sleep (the
* screen turning off).
* @param resuming The activity we are currently trying to resume or null if this is not being
* called as part of resuming the top activity, so we shouldn't try to instigate
* a resume here if not null.
* @param dontWait True if the caller does not want to wait for the pause to complete. If
* set to true, we will immediately complete the pause here before returning.
* @return Returns true if an activity now is in the PAUSING state, and we are waiting for
* it to tell us when it is done.
*/
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming, boolean dontWait) {
//这个类会保存与Activity相关的
//一个ActivityRecord对应一个Activity,保存了一个Activity的所有信息;但是一个Activity可能会有多个ActivityRecord,因为Activity可以被多次启动,这个主要取决于其启动模式。
ActivityRecord prev = mResumedActivity;
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
prev.userId, System.identityHashCode(prev),
prev.shortComponentName);
mService.updateUsageStats(prev, false);
//*-这里到出发去ActivityThread
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
} else {
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
}
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
data.writeInt(finished ? 1 : 0);
data.writeInt(userLeaving ? 1 :0);
data.writeInt(configChanges);
data.writeInt(dontReport ? 1 : 0);
mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
int seq = getLifecycleSeq();
if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this
+ " operation received seq: " + seq);
sendMessage(
//无论发送哪条消息都会触发onPause
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
configChanges,
seq);
}
case PAUSE_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, false,
(args.argi1 & USER_LEAVING) != 0, args.argi2,
(args.argi1 & DONT_REPORT) != 0, args.argi3);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
case PAUSE_ACTIVITY_FINISHING: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
SomeArgs args = (SomeArgs) msg.obj;
handlePauseActivity((IBinder) args.arg1, true, (args.argi1 & USER_LEAVING) != 0,
args.argi2, (args.argi1 & DONT_REPORT) != 0, args.argi3);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport, int seq) {
ActivityClientRecord r = mActivities.get(token);
if (DEBUG_ORDER) Slog.d(TAG, "handlePauseActivity " + r + ", seq: " + seq);
if (!checkAndUpdateLifecycleSeq(seq, r, "pauseActivity")) {
return;
}
if (r != null) {
//Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
if (userLeaving) {
performUserLeavingActivity(r);
}
r.activity.mConfigChangeFlags |= configChanges;
//执行onPause
performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
// Make sure any pending writes are now committed.
if (r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}
// Tell the activity manager we have paused.
if (!dontReport) {
try {
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
mSomeActivitiesChanged = true;
}
}
final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
boolean saveState, String reason) {
if (r.paused) {
if (r.activity.mFinished) {
// If we are finishing, we won't call onResume() in certain cases.
// So here we likewise don't want to call onPause() if the activity
// isn't resumed.
return null;
}
RuntimeException e = new RuntimeException(
"Performing pause of activity that is not resumed: "
+ r.intent.getComponent().toShortString());
Slog.e(TAG, e.getMessage(), e);
}
if (finished) {
r.activity.mFinished = true;
}
// Next have the activity save its current state and managed dialogs...
if (!r.activity.mFinished && saveState) {
callCallActivityOnSaveInstanceState(r);
}
//经过判断后确定需要执行onPause
performPauseActivityIfNeeded(r, reason);
// Notify any outstanding on paused listeners
ArrayList<OnActivityPausedListener> listeners;
synchronized (mOnPauseListeners) {
listeners = mOnPauseListeners.remove(r.activity);
}
int size = (listeners != null ? listeners.size() : 0);
for (int i = 0; i < size; i++) {
listeners.get(i).onPaused(r.activity);
}
return !r.activity.mFinished && saveState ? r.state : null;
}
private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
if (r.paused) {
// You are already paused silly...
return;
}
try {
r.activity.mCalled = false;
//*-在这里正式暂停,Instrumentation是直接管理Activity生命周期的类
mInstrumentation.callActivityOnPause(r.activity);
EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName(), reason);
if (!r.activity.mCalled) {
throw new SuperNotCalledException("Activity " + safeToComponentShortString(r.intent)
+ " did not call through to super.onPause()");
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException("Unable to pause activity "
+ safeToComponentShortString(r.intent) + ": " + e.toString(), e);
}
}
r.paused = true;
}
这里总结一下比较关键的点
要对Binder机制有一定的了解,不然会一头雾水
参考链接
public class SystemBars extends SystemUI implements ServiceMonitor.Callbacks {
......
//start()方法是再启动中调用的额方法
@Override
public void start() {
if (DEBUG) Log.d(TAG, "start");
//这里会启动ServiceMonitor,并调用其的start(),重点看注释“如果没有远程服务,就会回调onNoService()方法”
mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
mServiceMonitor.start(); // will call onNoService if no remote service is found
}
@Override
public void onNoService() {
if (DEBUG) Log.d(TAG, "onNoService");
createStatusBarFromConfig(); // fallback to using an in-process implementation
}
......
//第一次启动时,远程服务没有被启动,因此会回调onNoService()方法,然后调用createStatusBarFromConfig()方法,继续
private void createStatusBarFromConfig() {
if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
//根据xml中的配置,是一个应用包名路径,这里就是“com.android.systemui.statusbar.phone.PhoneStatusBar”
//然后根据包名路径并启动
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 = (BaseStatusBar) cls.newInstance();
} catch (Throwable t) {
throw andLog("Error creating status bar component: " + clsName, t);
}
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mComponents;
//这里调用mStausBar就是“PhoneStatusBar”实例,并调用start()方法
mStatusBar.start();
if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
}
}
public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
HeadsUpManager.OnHeadsUpChangedListener {
......
@Override
public void start() {
......
super.start(); // calls createAndAddWindows(),在这里把状态栏的View加到WindowManager,初始化View,顶部状态栏,和底部导航栏
......
addNavigationBar();
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController,
mUserInfoController, mBluetoothController);
mIconPolicy.setCurrentUserSetup(mUserSetup);
......
startKeyguard(); //启动屏锁
......
}
......
@Override
public void createAndAddWindows() {
addStatusBarWindow();
}
private void addStatusBarWindow() {
makeStatusBarView();//*-这里先生成View
mStatusBarWindowManager = new StatusBarWindowManager(mContext);
mRemoteInputController = new RemoteInputController(mStatusBarWindowManager,
mHeadsUpManager);
//由这里就可知,无论是锁屏View、导航栏View、通知栏View都是基于这个状态栏ViewGroup
//这样就避免了多个Window层级不好管理,转向好管理的ViewGroup
mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());//*-在这里加入WindowManager
}
/**
* 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);
}
//接下来看看锁屏View是怎么出现的
protected void startKeyguard() {
Trace.beginSection("PhoneStatusBar#startKeyguard");
//关注这个类
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
mFingerprintUnlockController = new FingerprintUnlockController(mContext,
mStatusBarWindowManager, mDozeScrimController, keyguardViewMediator,
mScrimController, this);
//关注这个类
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
getBouncerContainer(), mStatusBarWindowManager, mScrimController,
mFingerprintUnlockController);
mKeyguardIndicationController.setStatusBarKeyguardViewManager(
mStatusBarKeyguardViewManager);
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mIconPolicy.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
mRemoteInputController.addCallback(new RemoteInputController.Callback() {
@Override
public void onRemoteInputSent(Entry entry) {
if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) {
removeNotification(entry.key, null);
} else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) {
// We're currently holding onto this notification, but from the apps point of
// view it is already canceled, so we'll need to cancel it on the apps behalf
// after sending - unless the app posts an update in the mean time, so wait a
// bit.
mHandler.postDelayed(() -> {
if (mRemoteInputEntriesToRemoveOnCollapse.remove(entry)) {
removeNotification(entry.key, null);
}
}, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
}
}
});
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
mLightStatusBarController.setFingerprintUnlockController(mFingerprintUnlockController);
Trace.endSection();
}
}
public void registerStatusBar(PhoneStatusBar phoneStatusBar,
ViewGroup container, StatusBarWindowManager statusBarWindowManager,
ScrimController scrimController,
FingerprintUnlockController fingerprintUnlockController) {
mPhoneStatusBar = phoneStatusBar;
//注意这个ViewGroup,就是状态栏
mContainer = container;
mStatusBarWindowManager = statusBarWindowManager;
mScrimController = scrimController;
mFingerprintUnlockController = fingerprintUnlockController;
//他把这个ViewGroup继续传递给解锁界面
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
mViewMediatorCallback, mLockPatternUtils, mStatusBarWindowManager, container);
}
protected void inflateView() {
removeView();
mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
mKeyguardView = (KeyguardHostView) mRoot.findViewById(R.id.keyguard_host_view);
mKeyguardView.setLockPatternUtils(mLockPatternUtils);
mKeyguardView.setViewMediatorCallback(mCallback);
mContainer.addView(mRoot, mContainer.getChildCount());
mRoot.setVisibility(View.INVISIBLE);
}
回顾锁屏启动流程图,从KeyguardService开始,在开启这个服务的时候onCreate方法中获取了一个SystemUIApplication,这个Application是个关键
@Override
public void onCreate() {
((SystemUIApplication) getApplication()).startServicesIfNeeded();
mKeyguardViewMediator =
((SystemUIApplication) getApplication()).getComponent(KeyguardViewMediator.class);
}
//这里是指与SystemUI有关的类数组
private final Class<?>[] SERVICES = new Class[] {
com.android.systemui.tuner.TunerService.class,
com.android.systemui.keyguard.KeyguardViewMediator.class,
com.android.systemui.recents.Recents.class,
com.android.systemui.volume.VolumeUI.class,
Divider.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,
com.android.systemui.keyboard.KeyboardUI.class,
com.android.systemui.tv.pip.PipUI.class,
com.android.systemui.shortcut.ShortcutKeyDispatcher.class,
com.android.systemui.VendorServices.class
};
/**
* Hold a reference on the stuff we start.
*/
private final SystemUI[] mServices = new SystemUI[SERVICES.length];//SystemUI集合
private boolean mServicesStarted;
private boolean mBootCompleted;
private final Map<Class<?>, Object> mComponents = new HashMap<>();//注意这个HashMap
@Override
public void onCreate() {
super.onCreate();
// Set the application theme that is inherited by all services. Note that setting the
// application theme in the manifest does only work for activities. Keep this in sync with
// the theme set there.
setTheme(R.style.systemui_theme);
//这个Application在onCreate的时候把自己的Context传递给了SystemUIFactory,可以说是所有继承了SystemUI的Context的由来
SystemUIFactory.createFromConfig(this);
if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mBootCompleted) return;
if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
unregisterReceiver(this);
mBootCompleted = true;
if (mServicesStarted) {
final int N = mServices.length;
for (int i = 0; i < N; i++) {
mServices[i].onBootCompleted();
}
}
}
}, filter);
} else {
// For a secondary user, boot-completed will never be called because it has already
// been broadcasted on startup for the primary SystemUI process. Instead, for
// components which require the SystemUI component to be initialized per-user, we
// start those components now for the current non-system user.
startServicesIfNeeded(SERVICES_PER_USER);
}
}
private void startServicesIfNeeded(Class<?>[] services) {
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");
}
}
Log.v(TAG, "Starting SystemUI services for user " +
Process.myUserHandle().getIdentifier() + ".");
final int N = services.length;
for (int i=0; i<N; i++) {
Class<?> cl = services[i];
if (DEBUG) Log.d(TAG, "loading: " + cl);
try {
//刚刚那个HashMap中的Object在这里统统实例化
Object newService = SystemUIFactory.getInstance().createInstance(cl);
mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
}
//并且获取了Context
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;
}
@SuppressWarnings("unchecked")
public <T> T getComponent(Class<T> interfaceType) {
//这就是Service调用的方法,通过类名得到一个已经实例化好了的类,带有Context
return (T) mComponents.get(interfaceType);
}
private void setupLocked() {
mStatusBarKeyguardViewManager =
SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext,
mViewMediatorCallback, mLockPatternUtils);
}
public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils) {
mContext = context;
mViewMediatorCallback = callback;
mLockPatternUtils = lockPatternUtils;
}
public void registerStatusBar(PhoneStatusBar phoneStatusBar,
ViewGroup container, StatusBarWindowManager statusBarWindowManager,
ScrimController scrimController,
FingerprintUnlockController fingerprintUnlockController) {
mPhoneStatusBar = phoneStatusBar;
mContainer = container;
mStatusBarWindowManager = statusBarWindowManager;
mScrimController = scrimController;
mFingerprintUnlockController = fingerprintUnlockController;
//流程图中的解锁界面同理
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
mViewMediatorCallback, mLockPatternUtils, mStatusBarWindowManager, container);
}
/**
* Base class for keyguard view. {@link #reset} is where you should
* reset the state of your view. Use the {@link KeyguardViewCallback} via
* {@link #getCallback()} to send information back (such as poking the wake lock,
* or finishing the keyguard).
*
* Handles intercepting of media keys that still work when the keyguard is
* showing.
*/
涉及技巧
原来锁屏的View是附着在状态栏的View中的
这个状态栏的View也是基本整个SystemUI的基View,通过WindowManager显示在手机上置于最上层
以基View为ViewGroup,锁屏,导航栏等View通过ViewGroup的addView方式加入,可以方便的控制插入位置即View 的优先级
View的Context源于SystemUIApplication
工欲善其事必先利其器,一开始我是通过Git的Find File方法找的源码,跳转非常麻烦,效率低下
后面使用AS可以直接搜索+ctrl点击跳转.方便了很多
时间宝贵,先找找有没有相关可借鉴的资料,让自己对想了解的源码快速入门有个大致框架,可以少走弯路
自己阅读源码或者借助他人智慧走通之后,总结一份流程图,对查缺补漏、及时回头、清理思路或者其他扩展有非常大的帮助
一开始看那边介绍SystemUI框架的文章时没有细心···结果走了很多弯路
源码阅读对新手来说太多未知的地方了,很多你觉得没用反而可能是最关键的代码.所以一定要细心耐心
· 面对源码中一大堆的方法、类,很容易迷失自己或者是找不到方向,也会因为部分知识基础缺失而导致一头雾水的情况(比如不了解Binder机制几乎就看不到锁屏调用onPause的关键点在哪里)
· 这时候就要拆分问题(结构化思维):锁屏能调用Activity的回调——ActivityThread控制Activity的生命周期——AMS管理Activity(这是我本来就知道的知识),那么我就去了解Activity的启动流程.打通了这条线后,再去看锁屏哪里与AMS建立的连接,这时候又出现了Binder拦路虎,再打通Binder路线后,就可以将锁屏、AMS、Activity连接起来了(组合)
这次的源码中多次出现跨进程通信的操作
类加载器的使用
一个接口多处回调的例子看第五点