自由窗口模式
构建了新的服务SmtPCManagerService
该服务的构建是在SystemServer.java中,也就是在system_server进程中
SmtPCManagerService(Contextcontext,ActivityManagerServiceams,InputManagerServiceims)
从启动Activity开始:
Activity.java
Activity.attach()->构建PhoneWindow
PhoneWindow.java
PhoneWindow(Context context,Window preservedWindow,
ActivityConfigCallback activityConfigCallback)
在PhoneWindow的构造方法中,会通过preservedWindow获取到DecorView实例
setContentView
addContentView
getDecorView
getCircularProgressBar
getHorizontalProgressBar
getRightIconView
getLeftIconView
上述方法都会调用到installDecor方法,调用依据就是mContentParent是否为空
,而mContentParent = generateLayout(mDecor)
installDecor()
1) DecorView.onConfigurationChanged(Configuration newConfig) -> createDecorCaptionView (会根据stack号决定是否创建DecorCaptionView)
2) PhoneWIndow.generateLayout(执行requestFeature,setFlags等操作,inflate decorview)->DecorView.onResourcesLoaded(根据不同的features得到不同的资源索引,随后加载view,根据时候存在DecorCaptionView执行不同的addView) -> createDecorCaptionView
->inflateDecorCaptionView(加载xml文件,<com.android.internal.widget.SmtDecorCaptionView)
->创建SmtDecorCaptionView(继承于DecorCaptionView,内部逻辑与DecorCaptionView大同小异)
SmtDecorCaptionView.java
1)setPhoneWindow,会在Activity.attach构建PhoneWindow时调用,控制一些视图的显示
2) 关于事件的监听
首先SmtDecorCaptionView 继承于DecorCaptionView extendsViewGroupimplementsView.OnTouchListener,
GestureDetector.OnGestureListener
那么
a、onInterceptTouchEvent ( 根据view的getHitRect获取到点击范围,判断点击的view,并进行拦截,拦截了之后就意味着,事件不会再传递到下层View,会在SmtDecorCaptionView的onTouchEvent中处理事件)
b、onTouchEvent( 实际将event传递给了GestureDetector进行处理,返回、最小化、结束的点击事件就是在onSingleTapUp方法中处理的)
c、onTouch ->View.OnTouchListener(
当点击的是非特殊事件的位置时,会执行检测是否执行拖动操作,满足拖动操作的条件->
回调到View.startMovingExtendScreenTask->mAttachInfo.mSession.startMovingExtendScreenTask)
dispatchAttachedToWindow - > View.AttachInfo ->WindowManagerGlobal.getWindowSession() -> WindowManagerService.openSession ->Session.startMovingExtendScreenTask
->WindowManagerService.startMovingExtendScreenTask
boolean startMovingExtendScreenTask(IWindow window, float startX, float startY) {
WindowState win = null;
synchronized (mWindowMap) {
win = windowForClientLocked(null, window, false);
// win shouldn't be null here, pass it down to startPositioningLocked
// to get warning if it's null.
if (!startExtendScreenPositioningLocked(
win, false /*resize*/, false /*preserveOrientation*/, startX, startY)) {
return false;
}
if(mSmtTaskPositioners.size() >= 1) {
return true;
}
}
try {
mActivityManager.setFocusedTask(win.getTask().mTaskId);
} catch(RemoteException e) {}
return true;
}
-->windowForClientLocked
-->startExtendScreenPositioningLocked
-->mActivityManager.setFocusedTask
startExtendScreenPositioningLocked
private boolean startExtendScreenPositioningLocked(WindowState win, boolean resize,
boolean preserveOrientation, float startX, float startY) {
if (DEBUG_TASK_POSITIONING)
Slog.d(TAG_WM, "startExtendScreenPositioningLocked: "
+ "win=" + win + ", resize=" + resize + ", preserveOrientation="
+ preserveOrientation + ", {" + startX + ", " + startY + "}");
if(mSmtTaskPositioners.size() >=2) {
return false;
}
if (win == null || win.getAppToken() == null) {
Slog.w(TAG_WM, "startExtendScreenPositioningLocked: Bad window " + win);
return false;
}
if (win.mInputChannel == null) {
Slog.wtf(TAG_WM, "startExtendScreenPositioningLocked: " + win + " has no input channel, "
+ " probably being removed");
return false;
}
final DisplayContent displayContent = win.getDisplayContent();
if (displayContent == null) {
Slog.w(TAG_WM, "startExtendScreenPositioningLocked: Invalid display content " + win);
return false;
}
if(mSmtTaskPositioners.get(win) != null) {
Slog.w(TAG_WM, "startExtendScreenPositioningLocked: Invalid window " + win);
return false;
}
Display display = displayContent.getDisplay();
SmtTaskPositioner taskPositioner = new SmtTaskPositioner(this);
taskPositioner.register(display);
mSmtTaskPositioners.put(win, taskPositioner);
mInputMonitor.updateInputWindowsLw(true /*force*/);
// We need to grab the touch focus so that the touch events during the
// resizing/scrolling are not sent to the app. 'win' is the main window
// of the app, it may not have focus since there might be other windows
// on top (eg. a dialog window).
WindowState transferFocusFromWin = win;
if (mCurrentFocus != null && mCurrentFocus != win
&& mCurrentFocus.mAppToken == win.mAppToken) {
transferFocusFromWin = mCurrentFocus;
}
if (!mInputManager.transferTouchFocus(
transferFocusFromWin.mInputChannel, taskPositioner.mServerChannel)) {
Slog.e(TAG_WM, "startExtendScreenPositioningLocked: Unable to transfer touch focus");
taskPositioner.unregister();
mSmtTaskPositioners.remove(win);
taskPositioner = null;
mInputMonitor.updateInputWindowsLw(true /*force*/);
return false;
}
taskPositioner.startDrag(win, resize, preserveOrientation, startX, startY);
return true;
}