android 分屏显示左右或者上下 您所在的位置:网站首页 手机分两个屏幕显示 android 分屏显示左右或者上下

android 分屏显示左右或者上下

2024-06-29 12:13| 来源: 网络整理| 查看: 265

Android N 支持多窗口模式,或者叫分屏模式,即在屏幕上可以同时显示多个窗口。

在手机模式下,两个应用可以并排或者上下同时显示,如图 1 所示,屏幕上半部分的窗口是系统的 CLOCK 应用,下半部分是系统设置功能。用户可以拖动两个应用之间的分界线改变两个窗口的大小,放大其中一个应用,同时缩小另一个应用。  

分屏模式 图 1  分屏模式

在分屏模式下,各个窗口的应用都可以正常运行,但是只能有一个窗口获得焦点,而另外的窗口则属于暂停状态。

在某个应用界面进入分屏,这个应用会显示在上半部分或者左半部分,在android9之后会显示在下半部分或者右半部分。公司的车机项目从android8升级到android9,客户想要显示的和之前的一样,显示在左半部分。

分屏模式相关代码在SystemUI中,进入分屏的代码如下

private boolean onLongPressRecents() { if (mRecents == null || !ActivityManager.supportsMultiWindow(getContext()) || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible()) { return false; } return mStatusBar.toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS, MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS); }

走到src/com/android/systemui/statusbar/phone/StatusBar.java中

protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) { if (mRecents == null) { return false; } int dockSide = WindowManagerProxy.getInstance().getDockSide(); if (dockSide == WindowManager.DOCKED_INVALID) { final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(); if (navbarPos == NAV_BAR_POS_INVALID) { return false; } int createMode = navbarPos == NAV_BAR_POS_LEFT ? ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT : ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; return mRecents.splitPrimaryTask(NavigationBarGestureHelper.DRAG_MODE_NONE, createMode, null, metricsDockAction); } else { Divider divider = getComponent(Divider.class); if (divider != null && divider.isMinimized() && !divider.isHomeStackResizable()) { // Undocking from the minimized state is not supported return false; } else { EventBus.getDefault().send(new UndockingTaskEvent()); if (metricsUndockAction != -1) { mMetricsLogger.action(metricsUndockAction); } } } return true; }

进入分屏时,dockSide = WindowManager.DOCKED_INVALID,所以执行mRecents.splitPrimaryTask()

在src/com/android/systemui/recents/Recents.java的方法splitPrimaryTask中,最终执行的是

if (sSystemServicesProxy.isSystemUser(currentUser)) { mImpl.splitPrimaryTask(runningTask.id, dragMode, stackCreateMode, initialBounds); }

在src/com/android/systemui/recents/RecentsImpl.java

public void splitPrimaryTask(int taskId, int dragMode, int stackCreateMode, Rect initialBounds) { SystemServicesProxy ssp = Recents.getSystemServices(); // Make sure we inform DividerView before we actually start the activity so we can change // the resize mode already. if (ssp.setTaskWindowingModeSplitScreenPrimary(taskId, stackCreateMode, initialBounds)) { EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds)); } }

EventBus是一种用于Android的事件发布-订阅框架,通过解耦发布者和订阅者简化Android事件传递,因此接收DockedTopTaskEvent事件是具体执行方法。

在src/com/android/systemui/stackdivider/DividerView.java接收EventBus发送的事件

public final void onBusEvent(DockedTopTaskEvent event) { if (event.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) { mState.growAfterRecentsDrawn = false; mState.animateAfterRecentsDrawn = true; startDragging(false /* animate */, false /* touching */); } updateDockSide(); mEntranceAnimationRunning = true; resizeStack(calculatePositionForInsetBounds(), mSnapAlgorithm.getMiddleTarget().position, mSnapAlgorithm.getMiddleTarget()); }

mState.animateAfterRecentsDrawn置为true,执行分屏动画

public void onRecentsDrawn() { updateDockSide(); final int position = calculatePositionForInsetBounds(); if (mState.animateAfterRecentsDrawn) { mState.animateAfterRecentsDrawn = false; mHandler.post(() -> { // Delay switching resizing mode because this might cause jank in recents animation // that's longer than this animation. stopDragging(position, getSnapAlgorithm().getMiddleTarget(), mLongPressEntraceAnimDuration, Interpolators.FAST_OUT_SLOW_IN, 200 /* endDelay */); }); } if (mState.growAfterRecentsDrawn) { mState.growAfterRecentsDrawn = false; updateDockSide(); EventBus.getDefault().send(new RecentsGrowingEvent()); stopDragging(position, getSnapAlgorithm().getMiddleTarget(), 336, Interpolators.FAST_OUT_SLOW_IN); } }

此方法根据animateAfterRecentsDrawn是否为true而执行stopDragging()

public void stopDragging(int position, SnapTarget target, long duration, long startDelay, long endDelay, Interpolator interpolator) { mHandle.setTouching(false, true /* animate */); flingTo(position, target, duration, startDelay, endDelay, interpolator); mWindowManager.setSlippery(true); releaseBackground(); } private void flingTo(int position, SnapTarget target, long duration, long startDelay, long endDelay, Interpolator interpolator) { ValueAnimator anim = getFlingAnimator(position, target, endDelay); anim.setDuration(duration); anim.setStartDelay(startDelay); anim.setInterpolator(interpolator); anim.start(); }

通过getFlingAnimator获取动画,在getFlingAnimator中

ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position); anim.addUpdateListener(animation -> resizeStackDelayed((int) animation.getAnimatedValue(), taskPositionSameAtEnd && animation.getAnimatedFraction() == 1f ? TASK_POSITION_SAME : snapTarget.taskPosition, snapTarget));

resizeStackDelayed是动画执行的步骤

public void resizeStackDelayed(int position, int taskPosition, SnapTarget taskSnapTarget) { Message message = mHandler.obtainMessage(MSG_RESIZE_STACK, position, taskPosition, taskSnapTarget); message.setAsynchronous(true); mSfChoreographer.scheduleAtSfVsync(mHandler, message); } private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_RESIZE_STACK: resizeStack(msg.arg1, msg.arg2, (SnapTarget) msg.obj); break; default: super.handleMessage(msg); } } }; public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) { if (mRemoved) { // This divider view has been removed so shouldn't have any additional influence. return; } calculateBoundsForPosition(position, mDockSide, mDockedRect); if (mDockedRect.equals(mLastResizeRect) && !mEntranceAnimationRunning) { return; } // Make sure shadows are updated if (mBackground.getZ() > 0f) { mBackground.invalidate(); } mLastResizeRect.set(mDockedRect); if (mHomeStackResizable && mIsInMinimizeInteraction) { calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide, mDockedTaskRect); calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect); // Move a right-docked-app to line up with the divider while dragging it if (mDockSide == DOCKED_RIGHT) { mDockedTaskRect.offset(Math.max(position, mStableInsets.left - mDividerSize) - mDockedTaskRect.left + mDividerSize, 0); } mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedTaskRect, mOtherTaskRect, null); return; } ... ... ... ... }

mDockSide是影响显示左右的参数,

private void updateDockSide() { mDockSide = mWindowManagerProxy.getDockSide(); mMinimizedShadow.setDockSide(mDockSide); }

mDockSide是通过mWindowManagerProxy.getDockSide(),最终是通过WindowManagerService获取,我最终没找到WMS在哪里设置的,只能在updateDockSide方法中将mDockSide置为WindowManager.DOCKED_LEFT。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有