analysis chaozhuo multiwindow - HybridOS/Document GitHub Wiki
Android 多窗口分析
我的思路,前期主要了解了tieto项目的jabol分支代码,分析tieto在kitkat 分支上加入的功能解读:
首先看jabol的第一次提交:0001-Initial-commit-for-mw.patch
---
core/java/android/app/Activity.java | 41 +-
core/java/android/app/ActivityManagerNative.java | 43 +++
core/java/android/app/IActivityManager.java | 22 ++
core/java/android/view/ViewRootImpl.java | 8 +-
core/java/android/view/Window.java | 37 ++
core/res/res/drawable/mw_app_header_focused.9.png | Bin 0 -> 2891 bytes
.../res/res/drawable/mw_app_header_unfocused.9.png | Bin 0 -> 2883 bytes
core/res/res/drawable/mw_btn_add_content.xml | 6 +
.../res/drawable/mw_btn_add_content_clicked.png | Bin 0 -> 3221 bytes
.../res/drawable/mw_btn_add_content_default.png | Bin 0 -> 3231 bytes
core/res/res/drawable/mw_btn_close.xml | 6 +
core/res/res/drawable/mw_btn_close_clicked.png | Bin 0 -> 3712 bytes
core/res/res/drawable/mw_btn_close_default.png | Bin 0 -> 3362 bytes
core/res/res/drawable/mw_btn_maximize.xml | 6 +
core/res/res/drawable/mw_btn_maximize_clicked.png | Bin 0 -> 3843 bytes
core/res/res/drawable/mw_btn_maximize_default.png | Bin 0 -> 3564 bytes
core/res/res/drawable/mw_btn_minimize.xml | 6 +
core/res/res/drawable/mw_btn_minimize_clicked.png | Bin 0 -> 3942 bytes
core/res/res/drawable/mw_btn_minimize_default.png | Bin 0 -> 3819 bytes
core/res/res/drawable/mw_btn_resize_left.xml | 6 +
.../res/drawable/mw_btn_resize_left_clicked.png | Bin 0 -> 3840 bytes
.../res/drawable/mw_btn_resize_left_default.png | Bin 0 -> 3914 bytes
core/res/res/drawable/mw_btn_resize_right.xml | 6 +
.../res/drawable/mw_btn_resize_right_clicked.png | Bin 0 -> 3825 bytes
.../res/drawable/mw_btn_resize_right_default.png | Bin 0 -> 3905 bytes
core/res/res/drawable/mw_inner_border.xml | 5 +
core/res/res/drawable/mw_outer_border.xml | 5 +
core/res/res/drawable/mw_outer_border_wide.xml | 5 +
core/res/res/layout/mw_decor.xml | 83 +++++
core/res/res/values/colors.xml | 6 +
core/res/res/values/mw_values.xml | 10 +
core/res/res/values/symbols.xml | 28 ++
.../android/internal/policy/impl/PhoneWindow.java | 411 +++++++++++++++++++++
.../android/server/am/ActivityManagerService.java | 33 +-
.../java/com/android/server/am/ActivityStack.java | 14 +-
.../android/server/am/ActivityStackSupervisor.java | 73 +++-
services/java/com/android/server/wm/DimLayer.java | 24 +-
.../java/com/android/server/wm/DisplayContent.java | 134 ++++++-
services/java/com/android/server/wm/StackBox.java | 48 ++-
.../android/server/wm/WindowManagerService.java | 37 ++
.../java/com/android/server/wm/WindowState.java | 23 +-
41 files changed, 1076 insertions(+), 50 deletions(-)
create mode 100644 core/res/res/drawable/mw_app_header_focused.9.png
create mode 100644 core/res/res/drawable/mw_app_header_unfocused.9.png
create mode 100644 core/res/res/drawable/mw_btn_add_content.xml
create mode 100755 core/res/res/drawable/mw_btn_add_content_clicked.png
create mode 100644 core/res/res/drawable/mw_btn_add_content_default.png
create mode 100644 core/res/res/drawable/mw_btn_close.xml
create mode 100755 core/res/res/drawable/mw_btn_close_clicked.png
create mode 100644 core/res/res/drawable/mw_btn_close_default.png
create mode 100644 core/res/res/drawable/mw_btn_maximize.xml
create mode 100755 core/res/res/drawable/mw_btn_minimize_clicked.png
create mode 100755 core/res/res/drawable/mw_btn_minimize_default.png
create mode 100644 core/res/res/drawable/mw_btn_resize_left.xml
create mode 100755 core/res/res/drawable/mw_btn_resize_left_clicked.png
create mode 100644 core/res/res/drawable/mw_btn_resize_left_default.png
create mode 100644 core/res/res/drawable/mw_btn_resize_right.xml
create mode 100755 core/res/res/drawable/mw_btn_resize_right_clicked.png
create mode 100644 core/res/res/drawable/mw_btn_resize_right_default.png
create mode 100644 core/res/res/drawable/mw_inner_border.xml
create mode 100644 core/res/res/drawable/mw_outer_border.xml
create mode 100644 core/res/res/drawable/mw_outer_border_wide.xml
create mode 100644 core/res/res/layout/mw_decor.xml
create mode 100644 core/res/res/values/mw_values.xml
对第一个补丁进行分类 ,分为java代码和资源代码两类:
- java 代码部分解释:
core/java/android/app/Activity.java | 41 +-
core/java/android/app/ActivityManagerNative.java | 43 +++
core/java/android/app/IActivityManager.java | 22 ++
core/java/android/view/ViewRootImpl.java | 8 +-
core/java/android/view/Window.java | 37 ++
分析以上5个文件中的修改内容发现:
Activity.java 文件添加获取stackboxID函数,在每个app启动时获取其 sb.stack.taskIds[i]
+ private int getStackBoxId() {
+ try {
+ int taskId = getTaskId();
+ List<StackBoxInfo> list = ActivityManagerNative.getDefault().getStackBoxes();
+ for (StackBoxInfo sb : list) {
+ if ((sb.stackBoxId != 0) && (sb.stack != null) && (sb.stack.taskIds != null)) {
+ for (int i = 0; i < sb.stack.taskIds.length; i++) {
+ if (taskId == sb.stack.taskIds[i]) {
+ return sb.stackBoxId;
+ }
+ }
+ }
+ }
mWindow.setStackBoxId(getStackBoxId());
**设置窗口的 stackbox id **
ActivityManagerNative.java
IActivityManager.java
ViewRootImpl.java
以上三个java文件的修改,用于获取当前窗口的位置并且调整窗口位置;
- 窗口绘制部分的java代码分析
.../android/internal/policy/impl/PhoneWindow.java | 411 +++++++++++++++++++++
.../android/server/am/ActivityManagerService.java | 33 +-
.../java/com/android/server/am/ActivityStack.java | 14 +-
.../android/server/am/ActivityStackSupervisor.java | 73 +++-
services/java/com/android/server/wm/DimLayer.java | 24 +-
.../java/com/android/server/wm/DisplayContent.java | 134 ++++++-
services/java/com/android/server/wm/StackBox.java | 48 ++-
.../android/server/wm/WindowManagerService.java | 37 ++
.../java/com/android/server/wm/WindowState.java | 23 +-
41 files changed, 1076 insertions(+), 50 deletions(-)
<1> PhoneWindow.java 首先导入和stackbox 相关的类;
+import android.app.ActivityManager.StackBoxInfo;
绘制相关的类:
+import android.graphics.Color; +import android.graphics.drawable.ColorDrawable;
输入事件监听相关的类:
+import android.view.View.OnTouchListener; +import android.app.ActivityManagerNative; +import android.view.View.OnClickListener;
控件布局相关的类:
+import android.widget.Button; +import android.widget.ImageButton; +import android.widget.LinearLayout;
默认情况下,android原生的DecorView为整个Window界面的最顶层View ,DecorView只有一个子元素为LinearLayout。 代表整个Window界面,包含通知栏,标题栏,内容显示栏三块区域。
<2>jabol 代码在这里定义了和decorview类似的 用于多窗口显示的 顶层view如下:
+ private DecorMWView mDecorMW;
并且在方法setWindowBackground
设置了window的背景色为透明Color.TRANSPARENT
紧接着在方法fitSystemWindows(Rect insets)
中设置边界偏移量 int of = mDecorMW.getBorderPadding();
这里比较关键的点**DecorMWView
** 类的成员的变量的声明:
+ class DecorMWView {
+
+ private LinearLayout mHeader;
+ private ImageButton mCloseBtn;
+ private ImageButton mLaunchBtn;
+ private ImageButton mMaximizeBtn;
+ private View mInnerBorder;
+ private View mOuterBorder;
+ private View mBackground;
+ private View mLeftResize;
+ private View mRightResize;
+
+ private View mDecorView;
+ private int mTopBarHeight;
+ private int mMultiwindowHeight;
+ private int mStatusBarHeight;
+ private int mBorderPadding;
+ private boolean mRemoteConnected = false;
+ private Rect mFullScreen;
+
+ private Rect mOldSize;
//DecorMWView 类的构造函数
+ public DecorMWView() {
+ mDecorView = getLayoutInflater().inflate(com.android.internal.R.layout.mw_decor, null);
+
+ mHeader = (LinearLayout)mDecorView.findViewById(com.android.internal.R.id.mw_decor_header);
+ mTopBarHeight = getContext().getResources().getDimensionPixelSize(com.android.internal.R.dimen.mw_inner_border);
+ //mMultiwindowHeight = getContext().getResources().getDimensionPixelSize(android.R.dimen.mw_app_height);
+ mStatusBarHeight = getContext().getResources().getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ mBorderPadding = mDecorView.getPaddingLeft() + mTopBarHeight;
+ mCloseBtn = (ImageButton)mDecorView.findViewById(com.android.internal.R.id.mwCloseBtn);
+ mLaunchBtn = (ImageButton)mDecorView.findViewById(com.android.internal.R.id.mwLaunchBtn);
+ mMaximizeBtn = (ImageButton)mDecorView.findViewById(com.android.internal.R.id.mwMaximizeBtn);
.....
.....
+ mInnerBorder = mDecorView.findViewById(com.android.internal.R.id.mwInnerBorder);
+ mOuterBorder = mDecorView.findViewById(com.android.internal.R.id.mwOuterBorder);
+ mBackground = mDecorView.findViewById(com.android.internal.R.id.mwBackground);
+ mLeftResize = mDecorView.findViewById(com.android.internal.R.id.mwResizeLeft);
+ mRightResize = mDecorView.findViewById(com.android.internal.R.id.mwResizeRight);
+
+ DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
+ mFullScreen = new Rect(0, mStatusBarHeight + mMultiwindowHeight, metrics.widthPixels, metrics.heightPixels);
+
// 外部输入事件的监听(包括鼠标点击或者触摸时的各种响应)
+ mHeader.setOnTouchListener(new TouchListener(new ResizeWindow() {
+ @Override
+ public Rect resize(Rect frame, int diffX, int diffY) {
.....
+ }
+ }, mMaximizeBtn, mFullScreen));
+
+ mLeftResize.setOnTouchListener(new TouchListener(new ResizeWindow() {
+ @Override
+ public Rect resize(Rect frame, int diffX, int diffY) {
.......
+ }
+ }, mMaximizeBtn, mLeftResize, mFullScreen));
+
+ mRightResize.setOnTouchListener(new TouchListener(new ResizeWindow() {
+ @Override
+ public Rect resize(Rect frame, int diffX, int diffY) {
.....
+ }
+ }, mMaximizeBtn, mRightResize, mFullScreen));
+
+ mCloseBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
.......
}
+ mLaunchBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
.....
+ }
+ });
+
+ mMaximizeBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ });
+ public int getTopBarHeight() {
+ return mTopBarHeight;
+ }
+
//获取边框
+ public int getBorderPadding() {
+ return mBorderPadding;
+ }
+
+ public void startMultiwindowApp(final Intent intent,final int index) {
+ new Thread(new Runnable() {
+ public void run() {
....
+ }
+ }
+
+ public View getView(){
+ return mDecorView;
+ }
+
//选中模式下视图的背景和边框的设置
+ void setFocus(){
+ int tietoBlue = com.android.internal.R.color.mw_blue_decor;
+ mLeftResize.setBackgroundResource(tietoBlue);
+ mRightResize.setBackgroundResource(tietoBlue);
+ mHeader.setBackgroundResource(tietoBlue);
+ if (mRemoteConnected) {
+ mInnerBorder.setBackgroundResource(0);
+ mInnerBorder.setBackgroundColor(Color.TRANSPARENT);
+ mOuterBorder.setBackgroundResource(com.android.internal.R.drawable.mw_outer_border_wide);
+ } else {
+ mInnerBorder.setBackgroundResource(com.android.internal.R.color.mw_transparent_white);
+ mOuterBorder.setBackgroundResource(com.android.internal.R.drawable.mw_outer_border);
+ }
+ mDecorView.invalidate();
+ }
// 非选中状态下的背景以及边框颜色的设置
+ void unsetFocus() {
+ mLeftResize.setBackgroundResource(0);
+ mRightResize.setBackgroundResource(0);
+ mLeftResize.setBackgroundColor(Color.TRANSPARENT);
+ mRightResize.setBackgroundColor(Color.TRANSPARENT);
+ mHeader.setBackgroundResource(0);
+ mHeader.setBackgroundColor(Color.TRANSPARENT);
+ if (mRemoteConnected) {
+ mInnerBorder.setBackgroundResource(0);
+ mInnerBorder.setBackgroundColor(Color.TRANSPARENT);
+ } else {
+ mInnerBorder.setBackgroundResource(com.android.internal.R.color.mw_transparent_white);
+ }
+ mOuterBorder.setBackgroundResource(com.android.internal.R.drawable.mw_outer_border);
+ mDecorView.invalidate();
+ }
+ public void setBackground(Drawable d) {
+ mBackground.setBackground(d);
+ }
+
+ }