android 13分屏源码分析之分割线拖动过程

android T分屏流程 android T上对分屏流程进行了重构,之前用WINDOWING_MODE_SPLIT_SCREEN_PRIMARY等windowingMode来判断当前窗口是否分屏已经失效;分屏的触发操作放在了wm shell下,运行在systemui进程;将分屏涉及到的reparent、reorder等系列操作封装到WindowContainerTransaction中通过WindowOrganizer的applyTransaction来通知system server进行相关处理实现分屏。 阅读详情
AI摘要

本文详细解析了Android系统中分屏模式下DividerView的拖动过程,包括触摸事件处理、分割线位置更新、松手后的移动动画以及Task区域设置。在拖动过程中,涉及的关键方法如onTouch、updateDivideBounds、snapToTarget和flingDividePosition等,以及系统服务端的任务重新布局操作。此外,还提到了分屏退出的几种情况,如返回退出、启动全屏activity退出和拖拽正常退出的处理流程。

hi,上一节已经分析完分屏的启动过程,本节开始来介绍分屏使用过程中对分割线的拖动过程。

1、分割线的拖动部分

b站免费视频教程讲解:
https://www.bilibili.com/video/BV1wj411o7A9/
在这里插入图片描述
来看看拖拽的分割线的DividerView的onTouch

    public boolean onTouch(View v, MotionEvent event) {
        if (mSplitLayout == null || !mInteractive) {
            return false;
        }

        if (mDoubleTapDetector.onTouchEvent(event)) {
            return true;
        }

        // Convert to use screen-based coordinates to prevent lost track of motion events while
        // moving divider bar and calculating dragging velocity.
        event.setLocation(event.getRawX(), event.getRawY());
        final int action = event.getAction() & MotionEvent.ACTION_MASK;
        final boolean isLandscape = isLandscape();
        final int touchPos = (int) (isLandscape ? event.getX() : event.getY());
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mVelocityTracker = VelocityTracker.obtain();
                mVelocityTracker.addMovement(event);
                setTouching();
                mStartPos = touchPos;
                mMoving = false;
                break;
            case MotionEvent.ACTION_MOVE:
                mVelocityTracker.addMovement(event);
                if (!mMoving && Math.abs(touchPos - mStartPos) > mTouchSlop) {
                    mStartPos = touchPos;
                    mMoving = true;
                }
                if (mMoving) {
                    final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos;
                    mSplitLayout.updateDivideBounds(position);//最重要的拖动方法
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                releaseTouching();
                if (!mMoving) break;

                mVelocityTracker.addMovement(event);
                mVelocityTracker.computeCurrentVelocity(1000 /* units */);
                final float velocity = isLandscape
                        ? mVelocityTracker.getXVelocity()
                        : mVelocityTracker.getYVelocity();
                final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos;
                final DividerSnapAlgorithm.SnapTarget snapTarget =
                        mSplitLayout.findSnapTarget(position, velocity, false /* hardDismiss */);
                mSplitLayout.snapToTarget(position, snapTarget);//松手后要进行动画,DividerView自动到某个区域
                mMoving = false;
                break;
        }

        return true;
    }

这里重点分析 mSplitLayout.updateDivideBounds(position)方法:

    /**
     * Updates bounds with the passing position. Usually used to update recording bounds while
     * performing animation or dragging divider bar to resize the splits.
     */
    void updateDivideBounds(int position) {
        updateBounds(position);//更新一下bound区域
        mSplitLayoutHandler.onLayoutSizeChanging(this);
        //会调用对应的onLayoutSizeChanging方法来负责通知size变化了
    }

   @Override
    public void onLayoutSizeChanging(SplitLayout layout) {
        final SurfaceControl.Transaction t = mTransactionPool.acquire();
        t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
        setResizingSplits(true /* resizing */);
        updateSurfaceBounds(layout, t, true /* applyResizingOffset */);//会把对应的DividerView进行坐标更新,实现跟手
        mMainStage.onResizing(getMainStageBounds(), t);//通知主屏幕,告知有size变化,如果bounds变大则显示icon+背景,否则显示原来内容,并控制内容的区域跟随divideriew位置
        mSideStage.onResizing(getSideStageBounds(), t);//通知次屏幕,告知有size变化,如果bounds变大则显示icon+背景,否则显示原来内容,并控制内容的区域跟随divideriew位置
        t.apply();
        mTransactionPool.release(t);
    }
       void updateSurfaceBounds(@Nullable SplitLayout layout, @NonNull SurfaceControl.Transaction t,
            boolean applyResizingOffset) {
        final StageTaskListener topLeftStage =
                mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
        final StageTaskListener bottomRightStage =
                mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
                //这里关键调用了applySurfaceChanges
        (layout != null ? layout : mSplitLayout).applySurfaceChanges(t, topLeftStage.mRootLeash,
                bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer,
                applyResizingOffset);
    }

下面来看看applySurfaceChanges方法:

public void applySurfaceChanges(SurfaceControl.Transaction t, SurfaceControl leash1,
            SurfaceControl leash2, SurfaceControl dimLayer1, SurfaceControl dimLayer2,
            boolean applyResizingOffset) {
        final SurfaceControl dividerLeash = getDividerLeash();
        if (dividerLeash != null) {
            mTempRect.set(getRefDividerBounds());
            t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
            //这里是设置DeviderView进行位置设置
            // Resets layer of divider bar to make sure it is always on top.
            t.setLayer(dividerLeash, Integer.MAX_VALUE);
        }
        mTempRect.set(getRefBounds1());
        t.setPosition(leash1, mTempRect.left, mTempRect.top)//设置上下分屏的位置和裁减
                .setWindowCrop(leash1, mTempRect.width(), mTempRect.height());
        mTempRect.set(getRefBounds2());
        t.setPosition(leash2, mTempRect.left, mTempRect.top)
                .setWindowCrop(leash2, mTempRect.width(), mTempRect.height());

        if (mImePositionProcessor.adjustSurfaceLayoutForIme(
                t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) {
            return;
        }

        mSurfaceEffectPolicy.adjustDimSurface(t, dimLayer1, dimLayer2);//进行对应的特效显示,拉到底部或之顶部进行灰度提示
        if (applyResizingOffset) {
            mSurfaceEffectPolicy.adjustRootSurface(t, leash1, leash2);
        }
    }

接下来再看 mMainStage.onResizing方法:


 /** Showing resizing hint. */
    public void onResizing(ActivityManager.RunningTaskInfo resizingTask, Rect newBounds,
            SurfaceControl.Transaction t) {
   //省略
   //这里本质就是判断是否该区域有变大,如果有变大则变成ICON+背景,另一个屏则保持原样,因为show是为false
        final boolean show =
                newBounds.width() > mBounds.width() || newBounds.height() > mBounds.height();
 			//省略
        t.setPosition(mIconLeash,
                newBounds.width() / 2 - mIconSize / 2,
                newBounds.height() / 2 - mIconSize / 2);

        if (animate) {//启动相关显示的动画
            startFadeAnimation(show, false /* isResized */);
            mShown = show;
        }
    }

在这里插入图片描述

拖动DividerView移动的坐标设置堆栈


setPosition:2964, SurfaceControl$Transaction (android.view)
applySurfaceChanges:508, SplitLayout (com.android.wm.shell.common.split)
updateSurfaceBounds:1286, StageCoordinator (com.android.wm.shell.splitscreen)
onLayoutSizeChanging:1233, StageCoordinator (com.android.wm.shell.splitscreen)
updateDivideBounds:358, SplitLayout (com.android.wm.shell.common.split)
onTouch:298, DividerView (com.android.wm.shell.common.split)
dispatchTouchEvent:15000, View (android.view)
dispatchTransformedTouchEvent:3115, ViewGroup (android.view)
dispatchTouchEvent:2788, ViewGroup (android.view)
dispatchPointerEvent:15263, View (android.view)
processPointerEvent:6548, ViewRootImpl$ViewPostImeInputStage (android.view)
onProcess:6348, ViewRootImpl$ViewPostImeInputStage (android.view)
deliver:5804, ViewRootImpl$InputStage (android.view)
onDeliverToNext:5861, ViewRootImpl$InputStage (android.view)
forward:5827, ViewRootImpl$InputStage (android.view)
forward:5992, ViewRootImpl$AsyncInputStage (android.view)
apply:5835, ViewRootImpl$InputStage (android.view)
apply:6049, ViewRootImpl$AsyncInputStage (android.view)
deliver:5808, ViewRootImpl$InputStage (android.view)
onDeliverToNext:5861, ViewRootImpl$InputStage (android.view)
forward:5827, ViewRootImpl$InputStage (android.view)
apply:5835, ViewRootImpl$InputStage (android.view)
deliver:5808, ViewRootImpl$InputStage (android.view)
deliverInputEvent:8857, ViewRootImpl (android.view)
doProcessInputEvents:8808, ViewRootImpl (android.view)
enqueueInputEvent:8777, ViewRootImpl (android.view)
onInputEvent:8980, ViewRootImpl$WindowInputEventReceiver (android.view)
dispatchInputEvent:267, InputEventReceiver (android.view)
nativeConsumeBatchedInputEvents:-1, InputEventReceiver (android.view)
consumeBatchedInputEvents:247, InputEventReceiver (android.view)
doConsumeBatchedInput:8937, ViewRootImpl (android.view)
run:9071, ViewRootImpl$ConsumeBatchedInputRunnable (android.view)
run:1231, Choreographer$CallbackRecord (android.view)
run:1239, Choreographer$CallbackRecord (android.view)
doCallbacks:899, Choreographer (android.view)
doFrame:824, Choreographer (android.view)
run:1214, Choreographer$FrameDisplayEventReceiver (android.view)
handleCallback:942, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:201, Looper (android.os)
loop:288, Looper (android.os)
main:7897, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:548, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:936, ZygoteInit (com.android.internal.os)

2、松手后的移动动画及Task的区域设置

上文已经知道了松手后主要靠 mSplitLayout.snapToTarget(position, snapTarget)执行:

  /**
     * Sets new divide position and updates bounds correspondingly. Notifies listener if the new
     * target indicates dismissing split.
     */
    public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) {
        switch (snapTarget.flag) {
            case FLAG_DISMISS_START:
                flingDividePosition(currentPosition, snapTarget.position,
                        () -> mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */));
                break;
            case FLAG_DISMISS_END:
                flingDividePosition(currentPosition, snapTarget.position,
                        () -> mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */));
                break;
            default:
                flingDividePosition(currentPosition, snapTarget.position,
                        () -> setDividePosition(snapTarget.position, true /* applyLayoutChange */));
                break;
        }
    }

这里说一下FLAG_DISMISS_START和FLAG_DISMISS_END:
FLAG_DISMISS_START:代表DividerView上滑到顶部,导致上分屏退出情况,如下图
在这里插入图片描述

FLAG_DISMISS_END:代表一直向下滑动,一直到下分屏退出场景

可以看到有多种情况,不过都会调用到flingDividePosition,只是最后的回调方法不一样,这里一般我们是default情况:

 @VisibleForTesting
    void flingDividePosition(int from, int to, @Nullable Runnable flingFinishedCallback) {
        if (from == to) {
            // No animation run, still callback to stop resizing.
            mSplitLayoutHandler.onLayoutSizeChanged(this);
            return;
        }
        InteractionJankMonitorUtils.beginTracing(InteractionJankMonitor.CUJ_SPLIT_SCREEN_RESIZE,
                mSplitWindowManager.getDividerView(), "Divider fling");
        ValueAnimator animator = ValueAnimator
                .ofInt(from, to)
                .setDuration(250);//开始设置动画,一个from一个to作为开始和截至地方
        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
        animator.addUpdateListener(
                animation -> updateDivideBounds((int) animation.getAnimatedValue()));
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
            //动画结束以后的最重要的操作,需要真正的windowcontainer的bounds进行操作了
                if (flingFinishedCallback != null) {
                    flingFinishedCallback.run();//执行传递进来的那个runable
                }
                InteractionJankMonitorUtils.endTracing(
                        InteractionJankMonitor.CUJ_SPLIT_SCREEN_RESIZE);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                setDividePosition(to, true /* applyLayoutChange */);
            }
        });
        animator.start();
    }

这里重点又动画执行完成后的收尾操作就是调用 setDividePosition方法

  void setDividePosition(int position, boolean applyLayoutChange) {
        mDividePosition = position;
        updateBounds(mDividePosition);
        if (applyLayoutChange) {
            mSplitLayoutHandler.onLayoutSizeChanged(this);
        }
    }

这个setDividePosition前面有讲解 https://blog.youkuaiyun.com/learnframework/article/details/130944230
最后会把对应的bounds设置到systemserver的task中

3、systemserver端退出原理

看看systemui端的调用情况:

frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java

 private void applyExitSplitScreen(@Nullable StageTaskListener childrenToTop,
            WindowContainerTransaction wct, @ExitReason int exitReason) {
       //省略
        final boolean fromEnteringPip = exitReason == EXIT_REASON_CHILD_TASK_ENTER_PIP;
        mSideStage.removeAllTasks(wct, !fromEnteringPip && mSideStage == childrenToTop);//移除对应的sidestate下面task节点,其实本质就是把子节点进行对应的reparent到新的父亲
        mMainStage.deactivate(wct, !fromEnteringPip && mMainStage == childrenToTop);//其实和上面的removeAllTask类似,都是对task进行reparent操作,不能再继续挂载在分屏的节点了
        
        //对分屏的总节点进行对应的reorder,放到后面了,不能到最前啦
        wct.reorder(mRootTaskInfo.token, false /* onTop */);
        mTaskOrganizer.applyTransaction(wct);
        mSyncQueue.runInSync(t -> {
            setResizingSplits(false /* resizing */);
            t.setWindowCrop(mMainStage.mRootLeash, null)
                    .setWindowCrop(mSideStage.mRootLeash, null);
            setDividerVisibility(false, t);
        });
//省略
    }

看看对应的mSideStage.removeAllTasks方法:

   boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
        if (mChildrenTaskInfo.size() == 0) return false;
        wct.reparentTasks(
                mRootTaskInfo.token,
                null /* newParent */,
                CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE,
                CONTROLLED_ACTIVITY_TYPES,
                toTop);
        return true;
    }

调用到了reparentTasks,来看看reparentTasks
frameworks/base/core/java/android/window/WindowContainerTransaction.java

public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent,
            @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes,
            @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly) {
        mHierarchyOps.add(HierarchyOp.createForChildrenTasksReparent(
                currentParent != null ? currentParent.asBinder() : null,
                newParent != null ? newParent.asBinder() : null,
                windowingModes,
                activityTypes,
                onTop,
                reparentTopOnly));
        return this;
    }

//创建对应HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT的HierarchyOp
        public static HierarchyOp createForChildrenTasksReparent(IBinder currentParent,
                IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop,
                boolean reparentTopOnly) {
            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT)
                    .setContainer(currentParent)
                    .setReparentContainer(newParent)
                    .setWindowingModes(windowingModes)
                    .setActivityTypes(activityTypes)
                    .setToTop(onTop)
                    .setReparentTopOnly(reparentTopOnly)
                    .build();
        }

到此systemui部分的退出操作完成

看看systemserver端的调用情况:

frameworks/base/services/core/java/com/android/server/wm/WindowOrganizerController.java

 private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
            int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
            @NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
            @Nullable ITaskFragmentOrganizer organizer, @Nullable Transition finishTransition) {
            //省略
               switch (type) {
            case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: {
            //核心方法
                effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
                break;
            }
            //省略
            }   

这里调用到了核心方法reparentChildrenTasksHierarchyOp


 private int reparentChildrenTasksHierarchyOp(WindowContainerTransaction.HierarchyOp hop,
            @Nullable Transition transition, int syncId) {
        WindowContainer<?> currentParent = hop.getContainer() != null
                ? WindowContainer.fromBinder(hop.getContainer()) : null;
        WindowContainer newParent = hop.getNewParent() != null
                ? WindowContainer.fromBinder(hop.getNewParent()) : null;
        if (currentParent == null && newParent == null) {
           //省略
        } else if (newParent == null) {//这里传递为null,所以给予没人的parent为DefaultTaskDisplayArea
            newParent = currentParent.asTask().getDisplayContent().getDefaultTaskDisplayArea();
        }

       //省略
        final ArrayList<Task> tasksToReparent = new ArrayList<>();
//对当前的task节点下面所有children进行遍历
        currentParent.forAllTasks(task -> {
            final boolean reparent;
            //注意这里的话可能activitytype和windowmode不支持,就要直接返回不会放入tasksToReparent
            if (!ArrayUtils.contains(hop.getActivityTypes(), task.getActivityType())
                    || !ArrayUtils.contains(hop.getWindowingModes(), task.getWindowingMode())) {
                return false;
            }
					//如果放到顶部的就放到
            if (hop.getToTop()) {
                tasksToReparent.add(0, task);
            } else {
                tasksToReparent.add(task);
            }
            return hop.getReparentTopOnly() && tasksToReparent.size() == 1;
        });

        final int count = tasksToReparent.size();
        for (int i = 0; i < count; ++i) {
            final Task task = tasksToReparent.get(i);
          //省略
          //刚好这里newParent就是TaskDisplayArea,即直接把原理挂在上下分屏的task挂到TaskDisplayArea下面
            if (newParent instanceof TaskDisplayArea) {
                // For now, reparenting to display area is different from other reparents...
                task.reparent((TaskDisplayArea) newParent, hop.getToTop());
            } else {
                task.reparent((Task) newParent,
                        hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
                        false /*moveParents*/, "processChildrenTaskReparentHierarchyOp");
            }
        }
        return TRANSACT_EFFECTS_LIFECYCLE;
    }

这样整个分屏结束核心流程完毕,剩下的肯定就是要进行相关resumeToActivity和ensureVisibleActivity等操作,触发生命周期的变化

补充相关分割线相关位置的初始化流程,一共有5处位置,最顶,最底,中间,上半,下半,分别创建过程如下:

07-15 16:51:55.253   745   745 I lsm666  : java.lang.Exception
07-15 16:51:55.253   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm$SnapTarget.<init>(DividerSnapAlgorithm.java:478)
07-15 16:51:55.253   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.calculateTargets(DividerSnapAlgorithm.java:301)
07-15 16:51:55.253   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.<init>(DividerSnapAlgorithm.java:138)
07-15 16:51:55.253   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.<init>(DividerSnapAlgorithm.java:112)
07-15 16:51:55.253   745   745 I lsm666  : 	at com.android.wm.shell.common.split.SplitLayout.getSnapAlgorithm(SplitLayout.java:433)
07-15 16:51:55.253   745   745 I lsm666  : 	at com.android.wm.shell.common.split.SplitLayout.<init>(SplitLayout.java:134)
07-15 16:51:55.253   745   745 I lsm666  : 	at com.android.wm.shell.splitscreen.StageCoordinator.onTaskAppeared(StageCoordinator.java:956)
07-15 16:51:55.253   745   745 I lsm666  : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:438)
07-15 16:51:55.253   745   745 I lsm666  : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:427)
07-15 16:51:55.253   745   745 I lsm666  : 	at android.window.TaskOrganizer$1.lambda$onTaskAppeared$4$android-window-TaskOrganizer$1(TaskOrganizer.java:306)
07-15 16:51:55.253   745   745 I lsm666  : 	at android.window.TaskOrganizer$1$$ExternalSyntheticLambda6.run(Unknown Source:6)
07-15 16:51:55.253   745   745 I lsm666  : 	at android.os.Handler.handleCallback(Handler.java:942)
07-15 16:51:55.253   745   745 I lsm666  : 	at android.os.Handler.dispatchMessage(Handler.java:99)
07-15 16:51:55.253   745   745 I lsm666  : 	at android.os.Looper.loopOnce(Looper.java:201)
07-15 16:51:55.253   745   745 I lsm666  : 	at android.os.Looper.loop(Looper.java:288)
07-15 16:51:55.253   745   745 I lsm666  : 	at android.app.ActivityThread.main(ActivityThread.java:7898)
07-15 16:51:55.253   745   745 I lsm666  : 	at java.lang.reflect.Method.invoke(Native Method)
07-15 16:51:55.253   745   745 I lsm666  : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
07-15 16:51:55.253   745   745 I lsm666  : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
07-15 16:51:55.254   745   745 I lsm666  : SnapTarget position = 810
07-15 16:51:55.254   745   745 I lsm666  : java.lang.Exception
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm$SnapTarget.<init>(DividerSnapAlgorithm.java:478)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm$SnapTarget.<init>(DividerSnapAlgorithm.java:474)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.maybeAddTarget(DividerSnapAlgorithm.java:362)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.addNonDismissingTargets(DividerSnapAlgorithm.java:323)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.addRatio16_9Targets(DividerSnapAlgorithm.java:353)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.calculateTargets(DividerSnapAlgorithm.java:305)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.<init>(DividerSnapAlgorithm.java:138)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.<init>(DividerSnapAlgorithm.java:112)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.common.split.SplitLayout.getSnapAlgorithm(SplitLayout.java:433)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.common.split.SplitLayout.<init>(SplitLayout.java:134)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.splitscreen.StageCoordinator.onTaskAppeared(StageCoordinator.java:956)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:438)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:427)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.window.TaskOrganizer$1.lambda$onTaskAppeared$4$android-window-TaskOrganizer$1(TaskOrganizer.java:306)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.window.TaskOrganizer$1$$ExternalSyntheticLambda6.run(Unknown Source:6)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Handler.handleCallback(Handler.java:942)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Handler.dispatchMessage(Handler.java:99)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Looper.loopOnce(Looper.java:201)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Looper.loop(Looper.java:288)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.app.ActivityThread.main(ActivityThread.java:7898)
07-15 16:51:55.254   745   745 I lsm666  : 	at java.lang.reflect.Method.invoke(Native Method)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
07-15 16:51:55.254   745   745 I lsm666  : SnapTarget position = 1463
07-15 16:51:55.254   745   745 I lsm666  : java.lang.Exception
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm$SnapTarget.<init>(DividerSnapAlgorithm.java:478)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm$SnapTarget.<init>(DividerSnapAlgorithm.java:474)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.addMiddleTarget(DividerSnapAlgorithm.java:369)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.addNonDismissingTargets(DividerSnapAlgorithm.java:324)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.addRatio16_9Targets(DividerSnapAlgorithm.java:353)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.calculateTargets(DividerSnapAlgorithm.java:305)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.<init>(DividerSnapAlgorithm.java:138)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.<init>(DividerSnapAlgorithm.java:112)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.common.split.SplitLayout.getSnapAlgorithm(SplitLayout.java:433)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.common.split.SplitLayout.<init>(SplitLayout.java:134)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.splitscreen.StageCoordinator.onTaskAppeared(StageCoordinator.java:956)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:438)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:427)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.window.TaskOrganizer$1.lambda$onTaskAppeared$4$android-window-TaskOrganizer$1(TaskOrganizer.java:306)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.window.TaskOrganizer$1$$ExternalSyntheticLambda6.run(Unknown Source:6)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Handler.handleCallback(Handler.java:942)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Handler.dispatchMessage(Handler.java:99)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Looper.loopOnce(Looper.java:201)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Looper.loop(Looper.java:288)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.app.ActivityThread.main(ActivityThread.java:7898)
07-15 16:51:55.254   745   745 I lsm666  : 	at java.lang.reflect.Method.invoke(Native Method)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
07-15 16:51:55.254   745   745 I lsm666  : SnapTarget position = 2115
07-15 16:51:55.254   745   745 I lsm666  : java.lang.Exception
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm$SnapTarget.<init>(DividerSnapAlgorithm.java:478)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm$SnapTarget.<init>(DividerSnapAlgorithm.java:474)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.maybeAddTarget(DividerSnapAlgorithm.java:362)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.addNonDismissingTargets(DividerSnapAlgorithm.java:325)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.addRatio16_9Targets(DividerSnapAlgorithm.java:353)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.calculateTargets(DividerSnapAlgorithm.java:305)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.<init>(DividerSnapAlgorithm.java:138)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.<init>(DividerSnapAlgorithm.java:112)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.common.split.SplitLayout.getSnapAlgorithm(SplitLayout.java:433)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.common.split.SplitLayout.<init>(SplitLayout.java:134)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.splitscreen.StageCoordinator.onTaskAppeared(StageCoordinator.java:956)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:438)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:427)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.window.TaskOrganizer$1.lambda$onTaskAppeared$4$android-window-TaskOrganizer$1(TaskOrganizer.java:306)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.window.TaskOrganizer$1$$ExternalSyntheticLambda6.run(Unknown Source:6)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Handler.handleCallback(Handler.java:942)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Handler.dispatchMessage(Handler.java:99)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Looper.loopOnce(Looper.java:201)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Looper.loop(Looper.java:288)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.app.ActivityThread.main(ActivityThread.java:7898)
07-15 16:51:55.254   745   745 I lsm666  : 	at java.lang.reflect.Method.invoke(Native Method)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
07-15 16:51:55.254   745   745 I lsm666  : SnapTarget position = 2960
07-15 16:51:55.254   745   745 I lsm666  : java.lang.Exception
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm$SnapTarget.<init>(DividerSnapAlgorithm.java:478)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.calculateTargets(DividerSnapAlgorithm.java:317)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.<init>(DividerSnapAlgorithm.java:138)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.policy.DividerSnapAlgorithm.<init>(DividerSnapAlgorithm.java:112)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.common.split.SplitLayout.getSnapAlgorithm(SplitLayout.java:433)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.common.split.SplitLayout.<init>(SplitLayout.java:134)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.splitscreen.StageCoordinator.onTaskAppeared(StageCoordinator.java:956)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:438)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.wm.shell.ShellTaskOrganizer.onTaskAppeared(ShellTaskOrganizer.java:427)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.window.TaskOrganizer$1.lambda$onTaskAppeared$4$android-window-TaskOrganizer$1(TaskOrganizer.java:306)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.window.TaskOrganizer$1$$ExternalSyntheticLambda6.run(Unknown Source:6)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Handler.handleCallback(Handler.java:942)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Handler.dispatchMessage(Handler.java:99)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Looper.loopOnce(Looper.java:201)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.os.Looper.loop(Looper.java:288)
07-15 16:51:55.254   745   745 I lsm666  : 	at android.app.ActivityThread.main(ActivityThread.java:7898)
07-15 16:51:55.254   745   745 I lsm666  : 	at java.lang.reflect.Method.invoke(Native Method)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
07-15 16:51:55.254   745   745 I lsm666  : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

4、分屏退出部分

4.1 返回退出

applyExitSplitScreen:735, StageCoordinator (com.android.wm.shell.splitscreen)
exitSplitScreen:730, StageCoordinator (com.android.wm.shell.splitscreen)
onStageHasChildrenChanged:1187, StageCoordinator (com.android.wm.shell.splitscreen)
-$$Nest$monStageHasChildrenChanged:-1, StageCoordinator (com.android.wm.shell.splitscreen)
onStatusChanged:1864, StageCoordinator$StageListenerImpl (com.android.wm.shell.splitscreen)
sendStatusChanged:377, StageTaskListener (com.android.wm.shell.splitscreen)
onTaskVanished:276, StageTaskListener (com.android.wm.shell.splitscreen)
updateTaskListenerIfNeeded:552, ShellTaskOrganizer (com.android.wm.shell)
onTaskInfoChanged:465, ShellTaskOrganizer (com.android.wm.shell)
lambda$onTaskInfoChanged$6$android-window-TaskOrganizer$1:316, TaskOrganizer$1 (android.window)
run:-1, TaskOrganizer$1$$ExternalSyntheticLambda3 (android.window)
handleCallback:942, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:201, Looper (android.os)
loop:288, Looper (android.os)
main:7898, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:548, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:936, ZygoteInit (com.android.internal.os)

4.2 启动全屏activity退出


applyExitSplitScreen:735, StageCoordinator (com.android.wm.shell.splitscreen)
exitSplitScreen:730, StageCoordinator (com.android.wm.shell.splitscreen)
onStageVisibilityChanged:1079, StageCoordinator (com.android.wm.shell.splitscreen)
-$$Nest$monStageVisibilityChanged:-1, StageCoordinator (com.android.wm.shell.splitscreen)
onStatusChanged:1868, StageCoordinator$StageListenerImpl (com.android.wm.shell.splitscreen)
sendStatusChanged:377, StageTaskListener (com.android.wm.shell.splitscreen)
onTaskInfoChanged:251, StageTaskListener (com.android.wm.shell.splitscreen)
onTaskInfoChanged:468, ShellTaskOrganizer (com.android.wm.shell)
lambda$onTaskInfoChanged$6$android-window-TaskOrganizer$1:316, TaskOrganizer$1 (android.window)
run:-1, TaskOrganizer$1$$ExternalSyntheticLambda3 (android.window)
handleCallback:942, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:201, Looper (android.os)
loop:288, Looper (android.os)
main:7898, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:548, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:936, ZygoteInit (com.android.internal.os)

4.3 拖拽正常退出

applyExitSplitScreen:735, StageCoordinator (com.android.wm.shell.splitscreen)
exitSplitScreen:730, StageCoordinator (com.android.wm.shell.splitscreen)
onSnappedToDismiss:1219, StageCoordinator (com.android.wm.shell.splitscreen)
lambda$snapToTarget$0:400, SplitLayout (com.android.wm.shell.common.split)
$r8$lambda$eePA67tW_LBGfBgW6IWST62hoPI:-1, SplitLayout (com.android.wm.shell.common.split)
run:-1, SplitLayout$$ExternalSyntheticLambda0 (com.android.wm.shell.common.split)
onAnimationEnd:458, SplitLayout$1 (com.android.wm.shell.common.split)
:-1, Animator$AnimatorListener (android.animation)
endAnimation:1333, ValueAnimator (android.animation)
doAnimationFrame:1575, ValueAnimator (android.animation)
doAnimationFrame:307, AnimationHandler (android.animation)
-$$Nest$mdoAnimationFrame:-1, AnimationHandler (android.animation)
doFrame:86, AnimationHandler$1 (android.animation)
run:1229, Choreographer$CallbackRecord (android.view)
run:1239, Choreographer$CallbackRecord (android.view)
doCallbacks:899, Choreographer (android.view)
doFrame:827, Choreographer (android.view)
run:1214, Choreographer$FrameDisplayEventReceiver (android.view)
handleCallback:942, Handler (android.os)
dispatchMessage:99, Handler (android.os)
loopOnce:201, Looper (android.os)
loop:288, Looper (android.os)
main:7898, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:548, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:936, ZygoteInit (com.android.internal.os)

android13 设置左右分屏修改为单屏幕,应用分屏改为单屏 android13中,系统设置变成,左边是一级菜单,右侧是二级菜单,这样跟我们以前android7/8/9的布局是不一样的,我们需要将它修改为一级菜单,点进去才是二级菜单这种。效果如下。 阅读详情

相关推荐

Android 13 设置界面会判断当前屏幕的大小,如果是大屏,则为左右屏显示

在13.0的系统rom定制化开发中,在某些时候,在大屏设备中,设置新增了左右分屏的功能,就是 左边显示主菜单,右边显示一级菜单的功能,某些情况下不需要,接下来关闭这个功能

安卓兼职framework和app工程师的博客 412

Android分屏功能原理(基于Android12L)

Android分屏功能原理(基于Android12L)分屏功能目的是为了提高用户的生产效率,提高多应用使用的便捷性;Android 很早版本就已经提供了分屏功能,不过随着版本的迭代,特别是Google开始关注Android大屏设备的用户使用体验,内部的实现逻辑也和以前有很大的差别值得注意的是原生Android分屏功能只允许在任务管理器中选择分屏应用,如果应用未打开过,就无法分屏Android13上...

Android技术之家 4335

Rk3568 Android12 SystemUI 源码

Rk3568 Android12 SystemUI 源码,AndroidStudio可以直接导入,方便分析源码,跟代码流程。

Android分屏流程分析

安卓分屏流程分析

qq_36063677的博客 6176

避坑指南:汇川SV660N配合SOEM时,PDO映射与CiA402状态机那些容易出错的地方

本文深入解析汇川SV660N伺服驱动与SOEM主站在PDO动态映射和CiA402状态机切换中的常见问题,提供实战代码和调试技巧。重点解决PDO配置时序、状态机转换同步等关键难点,帮助工程师避免典型错误,实现稳定通信与控制。

weixin_30653023的博客 498

智能化运维(AIOps)

• 调查显示,54.79%的企业当前着重关注智能运维的质量领域(包括异常检测、告警收敛、根因分析、 故障处置等)能力建设,其次45.77%的企业关注效率领域,45.49%的企业关注成本领域,30.82%的 企业关注安全领域。从目前的发展情况来看,现阶段AIOps能力大多集中在L2级别, 主要以系统辅助分析,帮助人工进行决策和操作为主,较为领先的 能力实践可以达到L3级别,而L4和L5级别随着AIOps的技术发展 和能力的逐步增强,将是未来智能运维能力建设的发展方向和目标。

追求更专业的设计 3101

android 12/13 分屏设置Task的Bounds区域-系统车机开发必学

这里面进行对应分屏相关的一个业务处理, 比如分割线拖拽对两个分屏大小影响等。最后都会通过包装成WindowContainerTransaction对象,再通过WindowOrganizerController的本地代理,跨进程传递到systemserver的WindowOrganizerController类中进行处理.hi,近来研究分屏时候发现android 13上的分屏和以前的分屏代码差别比较大。最后就是调用的windowConfiguration.getBounds。其实Task的Bounds就是。

learnframework的博客 2366

TC3xx芯片中断配置避坑指南:从AUTOSAR Davinci配置到SRN地址计算的完整流程

本文详细解析了英飞凌TC3xx芯片的中断配置流程,从AUTOSAR Davinci工具链到硬件调试的全链路指南。重点介绍了中断路由(IR)模块、服务请求节点(SRN)和中断控制单元(ICU)的配置技巧,帮助开发者避开常见陷阱,优化中断性能。

weixin_30628801的博客 413

Android N App分屏模式完全解析

转载地址:http://unclechen.github.io/2016/03/12/Android-N-App%E5%88%86%E5%B1%8F%E6%A8%A1%E5%BC%8F%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90-%E4%B8%8A%E7%AF%87/ Android N App分屏模式完全解析(上) 12 Mar 2016

scott2017的博客 9934

从涡流求解器到瞬态场:Maxwell 3D里无线充电仿真,选对求解器能省一半计算时间

本文深入探讨了Maxwell 3D在无线充电仿真中涡流求解器与瞬态求解器的选择策略,帮助工程师优化计算效率与精度。通过对比分析两种求解器的适用场景、性能差异及实战技巧,揭示如何根据频率特性、材料非线性和动态过程需求做出精准选择,可节省高达50%的计算时间。特别针对3D线圈模型的无线充电系统设计提供了专业建议。

weixin_26861329的博客 231

Trae+雪球MCP,化身专业的股票分析师(玩转100个MCP系列第二弹)

大家好呀,我是程序员夏叶,深度AI编程使用者,专注于分享AI编程方面的使用技巧、经验以及前沿资讯,有兴趣的可以关注我的公众号,一起学习,共同进步。第二弹,使用Trae+雪球MCP,获取股票实时行情,分析股票走向等,写代码间隙看看股票价格,研究研究行情,哈哈。真的很不错呀,最关键的是,足够隐蔽,同事以为你在写代码,实际你在浏览股票行情,哈哈,感兴趣的可以试一下哦。说实话,沧州明珠这只股我算是砸手里了,不过还好买的不多,哈哈。

cpp加油站的专栏 518

android T 分屏流程之systemui部分/android framework车载车机手机实战开发

hi,上一节已经讲解清楚了分屏在Launcher端的一个启动情况,本节课开始将进行systemui部分的详细讲解: b站免费视频教程讲解: https://www.bilibili.com/video/BV1wj411o7A9/ 回忆上一节launcher端会调用以下方法来调用到systemui端 这里注意最后桌面调用了mSplitScreen.startIntentAndTaskWithLegacyTransition,这里的mSplitScreen就是一个binder代理,会调用到systemui的服务

liaosongmao1的专栏 1748

Open3D (C++) 泊松重建【2025最新版】

使用C++版本的Open3D实现点云的泊松重建

点云侠的博客 3077

解决layout布局把背景图片一起分割了,以及全屏背景无法显示的问题

解决layout布局把背景图片一起分割了,以及全屏背景无法显示的问题

qq_63524016的博客 427

在 SAP GUI Editor 中使用 OpenAI 自动生成 ABAP 代码 —— 技术实践与思考

在传统 SAP GUI Editor 场景下融入OpenAI开发者表达意图,模型负责实现。随着的持续演进,以及Joule等官方 Copilot 的加入,未来 ABAP 开发形态必将更加专注业务逻辑与架构设计,而把样板式编码交给 AI 自动完成。现在就动手试试,让你的下一段 ABAP 由 AI 来书写吧!

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 709

RuyiDify如何创建知识库API密钥:让程序安全访问知识库

知识库 API Key 是程序访问知识库的钥匙。创建它很简单,但真正重要的是知道它能做什么、应该放在哪里、不能暴露给谁。RuyiDify 讲这一步,不是为了让大家多记一个按钮,而是为了把知识库从“人工上传资料”推进到“程序化维护资料”。

未来已来,AI时代,学AI编程,做AI量化,就来大鹏AI教育。 136

Android N App分屏模式完全解析(下)

转载地址:http://unclechen.github.io/2016/03/12/Android-N-App%E5%88%86%E5%B1%8F%E6%A8%A1%E5%BC%8F%E5%AE%8C%E5%85%A8%E8%A7%A3%E6%9E%90-%E4%B8%8B%E7%AF%87/ 在上篇中,介绍了什么是App分屏模式,以及如何设置我们的App来进入分屏模式。这次我

scott2017的博客 2万+

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

辉哥的分屏学习笔记

安卓T 分屏

qq_30215785的博客 2121

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

android T分屏流程systemserver端操作

2、针对task相关的2类操作,reorder和startTask两类都是包装成了HierarchyOp,对这类也是调用了applyHierarchyOp方法来进行处理。总体来看这个reorder相对来说操作还是比较简单,就是一个把RootTask放到第一位,即显示再最前面。的话这个看起来也很简单,对上面3个步骤也非常好理解,甚至可以自己写出相关的代码。可以看看通过下图先有个大概的Task区域及结构的了解,其实这个如果前期学习过。这里其实也可以猜想出systemserver端也一样要有类似的3步操作。

liaosongmao1的专栏 666

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

安卓13设置分屏bug:竖屏进入设置>旋转平板横屏>旋转平板进入竖屏>按返回键>提示报错

经分析,控制这个页面的代码是在alps_mssi\vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\network下的NetworkDashboardFragment.java,在这个类里面的各个方法中加入log信息后再复现问题,查看log后可知在页面创建时,该类里的onAttach(),onCreatePreferences()方法被调用了。

qq_51029492的博客 719

ANDROID N 分屏设置

一 概述 android N的发布,最大的亮点有2个,原生系统对应用分屏的支持和快捷回复。现在只介绍分屏功能,目前最新的Android N系统支持横屏时让两个APP并排,竖屏时上下排放,而在Android TV上,原生系统也支持APP实现画中画。用户还可以在这两个App之间拖动数据,例如将一个App的Activity上的文件拖动到另外一个App的Activity中去。 用户开启分屏模式: 1

hecheng2009的博客 1209

android双屏显示的一些修改与尝试

转载时请注明出处和作者 文章出处:http://www.cnblogs.com/xl19862005 作者:Xandy 用的是android2.3的代码 这些天来一直在看android display相关的代码和资料并作了一些尝试,现在将这些天来的工作记录如下,有错误的地方希望广大同行指正,谢谢! 经过阅读代码和查到的相关一些资料,对android双屏的支持总体思

kin95的专栏 914

Android 把屏幕划分3等份;应用显示在中间区域

Android 把屏幕划分3等份;应用显示在中间区域 效果如下:

501846585_QQAndroid_java 1936
上一篇: android framework面试经验分享
下一篇: SurfaceFlinge/InputFlinger分析-android画面缩放后依然点击正常原理分析
千里马学框架
博客等级 码龄6年 1万+粉丝 650原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值