在最近的学习过程中,遇到了一个android7.0原生的缺陷。是关于android7.0新增的分屏功能,久久难以攻克,还是在主管的帮助下,遂记录之,希望以后能少走弯路,高效学习。
bug详情
General Description:
The notification bar will display stripe when tap the back key on multi-window screen.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Reproducibility:
7/10
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Precondition:
Auto-rotate is on.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Step:
1.Main Menu->Phone->Rotate to landscape mode->Long press RECENT key->Press BACK key->Check the phone displays.
2.Main Menu->Calculator->Rotate to landscape mode->Long press RECENT key->Press BACK key->Check the phone displays.
3.Main Menu->Clock->Rotate to landscape mode->Long press RECENT key->Press BACK key->Check the phone displays.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Actual result:
The notification bar will display stripe when tap the back key on multi-window screen.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expect result:
The notification bar shouldn't display stripe when tap the back key on multi-window screen.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Related Test Case:
N/A
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SW version:
36.1.A.0.37
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
HW version:
AP2
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
我们打开SystemUI的源代码
这里应该是一个文件夹对应一个模块,比如最近任务,锁屏,电池,截图,状态栏等等。然而我们要关注的是stackdivider,android中会把Activity放到栈中来管理,实际上分屏的话相当于会有一个新的stack,我们看看ActivityManager.java(base/core/java/android/app)文件有个内部类,记录管理着所有的stack
public static class StackId {
/** Invalid stack ID. */
public static final int INVALID_STACK_ID = -1;
/** First static stack ID. */
public static final int FIRST_STATIC_STACK_ID = 0;
/** Home activity stack ID. */
public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;
/** ID of stack where fullscreen activities are normally launched into. */
public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
/** ID of stack where freeform/resized activities are normally launched into. */
public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
/** ID of stack that occupies a dedicated region of the screen. */
public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;
/** ID of stack that always on top (always visible) when it exist. */
public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
/** Last static stack stack ID. */
public static final int LAST_STATIC_STACK_ID = PINNED_STACK_ID;
。。。。。
}
知道了这些,我们看看为什么标题栏上会有黑色的条纹,并且是两条,难道是横屏分屏的时候statusbar绘制的时候还有其他的view也被显示了。实际上我们在测试的过程中可以发现
在当前应用屏幕和最近任务屏幕之间有个黑色条纹,可能是这个条纹没有被隐藏掉影响了statusbar的状态。那么我们看看这边的代码
/**
* Controls the docked stack divider.
*/
public class Divider extends SystemUI {
......
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
update(newConfig);
}
......
private void update(Configuration configuration) {
removeDivider();
addDivider(configuration);
if (mMinimized) {
mView.setMinimizedDockStack(true);
updateTouchable();
}
}
......
......
}
当config change 后会调用update方法,最终看看DividerView的绘制 mView.setMinimizedDockStack(true);
/**
* Docked stack divider.
*/
public class DividerView extends FrameLayout implements OnTouchListener,
OnComputeInternalInsetsListener {
......
public void setMinimizedDockStack(boolean minimized) {
updateDockSide();
mHandle.setAlpha(minimized ? 0f : 1f);
if (!minimized) {
resetBackground();
} else if (mDockSide == WindowManager.DOCKED_TOP) {
mBackground.setPivotY(0);
mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
} else if (mDockSide == WindowManager.DOCKED_LEFT
|| mDockSide == WindowManager.DOCKED_RIGHT) {
mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
? 0
: mBackground.getWidth());
mBackground.setScaleX(MINIMIZE_DOCK_SCALE);
}
mMinimizedShadow.setAlpha(minimized ? 1f : 0f);
mDockedStackMinimized = minimized;
}
......
private void updateDockSide() {
mDockSide = mWindowManagerProxy.getDockSide();
mMinimizedShadow.setDockSide(mDockSide);
}
}
分析上面的code,在最小化分屏界面时会首先执行updateDockSide()方法
public interface WindowManager extends ViewManager {
......
/** @hide */
int DOCKED_INVALID = -1;
/** @hide */
int DOCKED_LEFT = 1;
/** @hide */
int DOCKED_TOP = 2;
/** @hide */
int DOCKED_RIGHT = 3;
/** @hide */
int DOCKED_BOTTOM = 4;
......
}
WindowManageProxy下(SystemUI)
public int getDockSide() {
try {
return WindowManagerGlobal.getWindowManagerService().getDockedStackSide();
} catch (RemoteException e) {
Log.w(TAG, "Failed to get dock side: " + e);
}
return DOCKED_INVALID;
}
Z:\frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java下
public int getDockedStackSide() {
synchronized (mWindowMap) {
final TaskStack dockedStack = getDefaultDisplayContentLocked()
.getDockedStackVisibleForUserLocked();
return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide();
}
}
最终是TaskStack getDockSide
回到setMinimizedDockStack方法,会判断dockside,有些情况dockside的值不满足,而这是确实要求隐藏
mMinimizedShadow被異常畫出,
mBackground沒有被隱藏:
(mMinimizedShadow: 阴影view,
mBackground:分割線View )。所以在updatedockside里当是无效的,给他赋值
if(mDockSide == WindowManager.DOCKED_INVALID){
mDockSide = WindowManager.DOCKED_TOP;
android.util.Log.d("DividerView", "updateDockSide() mDockSide is DOCKED_INVALID change to DOCKED_TOP!");
}
搞清楚