安卓车机手机系统开发--多窗口模式之PIP详细讲解

Android悬浮窗口-画中画功能 Android画中画功能播放视频 比悬浮窗更快更方便 阅读详情
AI摘要

文章详细解析了Android系统中Picture-in-Picture(PIP)模式的应用进入和退出流程,包括系统服务器如何处理窗口模式变化,以及如何控制应用进入暂停而非停止状态。在进入PIP模式时,系统主要通过调整ActivityRecord和Task的窗口模式,并在动画过程中保持ActivityRecord的全屏模式,直到动画结束才切换到PIP模式。此外,还讨论了动画的触发和结束过程。

视频教程讲解:
https://www.bilibili.com/video/BV1wj411o7A9/
在这里插入图片描述

1、PIP进入

官方解释及备注:
/** Always on-top (always visible). of other siblings in its parent container. */
public static final int WINDOWING_MODE_PINNED = 2;

app层:

  private void enterPiPMode() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (mPictureInPictureParamsBuilder == null) {
                mPictureInPictureParamsBuilder = new PictureInPictureParams.Builder();
            }
            if (videoView != null) {
                int mVideoWith = videoView.getWidth();
                int mVideoHeight = videoView.getHeight();
                if (mVideoWith != 0 && mVideoHeight != 0) {
                    //设置param宽高比,根据宽高比例调整初始参数
                    Rational aspectRatio = new Rational(mVideoWith, mVideoHeight);
                    mPictureInPictureParamsBuilder.setAspectRatio(aspectRatio);
                }

            }
            //进入pip模式
            enterPictureInPictureMode(mPictureInPictureParamsBuilder.build());
        }
    }

systemserver层面核心:
核心方法moveActivityToPinnedRootTask:


void moveActivityToPinnedRootTask(@NonNull ActivityRecord r,
            @Nullable ActivityRecord launchIntoPipHostActivity, String reason) {
      //省略
            // The intermediate windowing mode to be set on the ActivityRecord later.
            // This needs to happen before the re-parenting, otherwise we will always set the
            // ActivityRecord to be fullscreen.
            final int intermediateWindowingMode = rootTask.getWindowingMode();
        //省略
            //注意ActivityRecord设置的是intermediateWindowingMode即不是pip还是fullscreen
            r.setWindowingMode(intermediateWindowingMode);
            r.mWaitForEnteringPinnedMode = true;
            //省略
            //Task被尽快设置成了WINDOWING_MODE_PINNED
            rootTask.setWindowingMode(WINDOWING_MODE_PINNED);
      //省略
      //这里会触发sendTaskAppeared
            rootTask.setDeferTaskAppear(false);

                  //省略
        } finally {
            mService.continueWindowLayout();
        }
			//进行了Task的windowmode设置后一般要触发ensureActivitiesVisible和resumeFocusedTasksTopActivities来保证系统所有Activity的显示正常
        ensureActivitiesVisible(null, 0, false /* preserveWindows */);
        resumeFocusedTasksTopActivities();

        notifyActivityPipModeChanged(r.getTask(), r);
    }

总结:
1、pip模式进入,systemserver层面主要有对ActivityRecord单独设置windowmode为fullscreen,对Task设置windowmode为pip模式
2、一般改变了Task相关的属性后都会触发ensureActivitiesVisible和resumeFocusedTasksTopActivities保证系统当前activity可以正常排列显示

2、 生命周期变化

launcher进入resume:


obtain:78, ResumeActivityItem (android.app.servertransaction)
resumeTopActivity:1434, TaskFragment (com.android.server.wm)
resumeTopActivityInnerLocked:5003, Task (com.android.server.wm)
resumeTopActivityUncheckedLocked:4938, Task (com.android.server.wm)
resumeTopActivityUncheckedLocked:4952, Task (com.android.server.wm)
resumeTopActivityUncheckedLocked:4984, Task (com.android.server.wm)
makeActiveIfNeeded:5765, ActivityRecord (com.android.server.wm)
makeVisibleIfNeeded:5697, ActivityRecord (com.android.server.wm)
setActivityVisibilityState:210, EnsureActivitiesVisibleHelper (com.android.server.wm)
process:143, EnsureActivitiesVisibleHelper (com.android.server.wm)
updateActivityVisibilities:1111, TaskFragment (com.android.server.wm)
lambda$ensureActivitiesVisible$18:4834, Task (com.android.server.wm)
accept:-1, Task$$ExternalSyntheticLambda23 (com.android.server.wm)
forAllLeafTasks:3160, Task (com.android.server.wm)
forAllLeafTasks:3148, Task (com.android.server.wm)
ensureActivitiesVisible:4833, Task (com.android.server.wm)
lambda$ensureActivitiesVisible$45:6217, DisplayContent (com.android.server.wm)
accept:-1, DisplayContent$$ExternalSyntheticLambda38 (com.android.server.wm)
forAllRootTasks:3172, Task (com.android.server.wm)
forAllRootTasks:2014, WindowContainer (com.android.server.wm)
forAllRootTasks:2014, WindowContainer (com.android.server.wm)
forAllRootTasks:2014, WindowContainer (com.android.server.wm)
forAllRootTasks:2014, WindowContainer (com.android.server.wm)
forAllRootTasks:2014, WindowContainer (com.android.server.wm)
forAllRootTasks:2014, WindowContainer (com.android.server.wm)
forAllRootTasks:2007, WindowContainer (com.android.server.wm)
ensureActivitiesVisible:6216, DisplayContent (com.android.server.wm)
ensureActivitiesVisible:1864, RootWindowContainer (com.android.server.wm)
ensureActivitiesVisible:1845, RootWindowContainer (com.android.server.wm)
setWindowingModeInSurfaceTransaction:4632, Task (com.android.server.wm)
lambda$setWindowingMode$16$com-android-server-wm-Task:4513, Task (com.android.server.wm)
run:-1, Task$$ExternalSyntheticLambda40 (com.android.server.wm)
inSurfaceTransaction:8282, WindowManagerService (com.android.server.wm)
setWindowingMode:4513, Task (com.android.server.wm)
setWindowingMode:4501, Task (com.android.server.wm)
moveActivityToPinnedRootTask:2114, RootWindowContainer (com.android.server.wm)
lambda$enterPictureInPictureMode$5$com-android-server-wm-ActivityTaskManagerService:3474, ActivityTaskManagerService (com.android.server.wm)
run:-1, ActivityTaskManagerService$$ExternalSyntheticLambda3 (com.android.server.wm)
enterPictureInPictureMode:3497, ActivityTaskManagerService (com.android.server.wm)
enterPictureInPictureMode:740, ActivityClientController (com.android.server.wm)
onTransact:878, IActivityClientController$Stub (android.app)
onTransact:124, ActivityClientController (com.android.server.wm)
execTransactInternal:1280, Binder (android.os)
execTransact:1244, Binder (android.os)

pip的app进入pasue
疑问1: 为啥pip只进行pause不进行stop

进入onPause

可以通过在服务端的PauseActivityItem构造时候打印对应的堆栈:

obtain:75, PauseActivityItem (android.app.servertransaction)
makeActiveIfNeeded:5779, ActivityRecord (com.android.server.wm)
setActivityVisibilityState:207, EnsureActivitiesVisibleHelper (com.android.server.wm)
process:143, EnsureActivitiesVisibleHelper (com.android.server.wm)
updateActivityVisibilities:1119, TaskFragment (com.android.server.wm)
lambda$ensureActivitiesVisible$18:4834, Task (com.android.server.wm)
accept:-1, Task$$ExternalSyntheticLambda23 (com.android.server.wm)
forAllLeafTasks:3160, Task (com.android.server.wm)
ensureActivitiesVisible:4833, Task (com.android.server.wm)
lambda$ensureActivitiesVisible$45:6216, DisplayContent (com.android.server.wm)
accept:-1, DisplayContent$$ExternalSyntheticLambda38 (com.android.server.wm)
forAllRootTasks:3172, Task (com.android.server.wm)
forAllRootTasks:2020, WindowContainer (com.android.server.wm)
forAllRootTasks:2020, WindowContainer (com.android.server.wm)
forAllRootTasks:2020, WindowContainer (com.android.server.wm)
forAllRootTasks:2020, WindowContainer (com.android.server.wm)
forAllRootTasks:2020, WindowContainer (com.android.server.wm)
forAllRootTasks:2020, WindowContainer (com.android.server.wm)
forAllRootTasks:2013, WindowContainer (com.android.server.wm)
ensureActivitiesVisible:6215, DisplayContent (com.android.server.wm)
ensureActivitiesVisible:1864, RootWindowContainer (com.android.server.wm)
ensureActivitiesVisible:1845, RootWindowContainer (com.android.server.wm)
setWindowingModeInSurfaceTransaction:4632, Task (com.android.server.wm)
lambda$setWindowingMode$16$com-android-server-wm-Task:4513, Task (com.android.server.wm)
run:-1, Task$$ExternalSyntheticLambda40 (com.android.server.wm)
inSurfaceTransaction:8282, WindowManagerService (com.android.server.wm)
setWindowingMode:4513, Task (com.android.server.wm)
setWindowingMode:4501, Task (com.android.server.wm)
moveActivityToPinnedRootTask:2114, RootWindowContainer (com.android.server.wm)
lambda$enterPictureInPictureMode$5$com-android-server-wm-ActivityTaskManagerService:3474, ActivityTaskManagerService (com.android.server.wm)
run:-1, ActivityTaskManagerService$$ExternalSyntheticLambda3 (com.android.server.wm)
enterPictureInPictureMode:3497, ActivityTaskManagerService (com.android.server.wm)
enterPictureInPictureMode:740, ActivityClientController (com.android.server.wm)
onTransact:878, IActivityClientController$Stub (android.app)
onTransact:124, ActivityClientController (com.android.server.wm)
execTransactInternal:1280, Binder (android.os)
execTransact:1244, Binder (android.os)

堆栈中关键判断如下:

boolean makeActiveIfNeeded(ActivityRecord activeActivity) {
        if (shouldResumeActivity(activeActivity)) {
         //省略
        } else if (shouldPauseActivity(activeActivity)) { //核心在与这里的shouldPauseActivity为true
            setState(PAUSING, "makeActiveIfNeeded");
            try {
                mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
                        PauseActivityItem.obtain(finishing, false /* userLeaving */,
                                configChangeFlags, false /* dontReport */));
            } catch (Exception e) {
                Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e);
            }
        }
          @VisibleForTesting
    boolean shouldPauseActivity(ActivityRecord activeActivity) { //这里面的isFocusable是关键,即现在已经属于不可以焦点状态
        return shouldMakeActive(activeActivity) && !isFocusable() && !isState(PAUSING, PAUSED)&& (results == null);
    }
    
    @Override
    boolean isFocusable() {
        return super.isFocusable() && (canReceiveKeys() || isAlwaysFocusable());
    }
     boolean canReceiveKeys() {
        // TODO(156521483): Propagate the state down the hierarchy instead of checking the parent
        return getWindowConfiguration().canReceiveKeys()
                && (task == null || task.getWindowConfiguration().canReceiveKeys());
    }
       /**
     * Returns true if the windows associated with this window configuration can receive input keys.
     * @hide
     */
    public boolean canReceiveKeys() { //这里是WINDOWING_MODE_PINNED,所以返回false,这里就是核心关键地方导致focusable为false
        return mWindowingMode != WINDOWING_MODE_PINNED;
    }

总结精简后的流程图如下:
在这里插入图片描述

一般正常情况下Activity的Visible状态就会决定它是否要进入Stop

即Activity如果属于Pasued状态了系统如果触发了ensureActivitiesVisible的调用
则会遍历每一个Task的一个对应的EnsureActivitiesVisibleHelper的process方法:

void process(@Nullable ActivityRecord starting, int configChanges, boolean preserveWindows,
            boolean notifyClients) {
        reset(starting, configChanges, preserveWindows, notifyClients);
       //省略
        for (int i = mTaskFragment.mChildren.size() - 1; i >= 0; --i) {
            final WindowContainer child = mTaskFragment.mChildren.get(i);
            final TaskFragment childTaskFragment = child.asTaskFragment();
               //省略
            } else if (child.asActivityRecord() != null) {
                setActivityVisibilityState(child.asActivityRecord(), starting, resumeTopActivity);
            }
        }
    }

这里最先就是调用了reset

void reset(ActivityRecord starting, int configChanges, boolean preserveWindows,
            boolean notifyClients) {
        mStarting = starting;
        mTop = mTaskFragment.topRunningActivity();
        // If the top activity is not fullscreen, then we need to make sure any activities under it
        // are now visible.
        mAboveTop = mTop != null;
        mContainerShouldBeVisible = mTaskFragment.shouldBeVisible(mStarting);//这里的mContainerShouldBeVisible就代表Task是否可以显示,这个地方最为关键
        mBehindFullyOccludedContainer = !mContainerShouldBeVisible;
        mConfigChanges = configChanges;
        mPreserveWindows = preserveWindows;
        mNotifyClients = notifyClients;
    }

上面调用最为关键就是mTaskFragment.shouldBeVisible(mStarting)

  boolean shouldBeVisible(ActivityRecord starting) {
        return getVisibility(starting) != TASK_FRAGMENT_VISIBILITY_INVISIBLE;
    }

哈哈这里发现又是来比较getVisibility的值,这个地方我们前面有分析过的

因为小窗pip虽然进入了pasued状态,但是visible还是可以显示的true状态
知道task显示为true以后,再接下来看setActivityVisibilityState方法:

private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,
            final boolean resumeTopActivity) {
     //省略
     //这里的mBehindFullyOccludedContainer再前面reset已经置为了false代表没有被覆盖
        r.updateVisibilityIgnoringKeyguard(mBehindFullyOccludedContainer);
        final boolean reallyVisible = r.shouldBeVisibleUnchecked();//这里会判断是否真正显示
        if (reallyVisible) {
            //可见状态,所以这里属于可见状态,导致不会进入makeInvisible
        } else {
        		//不可见调用makeInvisible
            r.makeInvisible();
        }

       //省略
    }
   //这里的 behindOccludedContainer为false,会返回visibleIgnoringKeyguard为true
     void updateVisibilityIgnoringKeyguard(boolean behindOccludedContainer) {
        visibleIgnoringKeyguard = (!behindOccludedContainer || mLaunchTaskBehind)
                && showToCurrentUser();
    }
       boolean shouldBeVisibleUnchecked() {
        final Task rootTask = getRootTask();
        //这里visibleIgnoringKeyguard所以不会进入,故shouldBeVisibleUnchecked一般返回true,代表可以显示
        if (rootTask == null || !visibleIgnoringKeyguard) { 
            return false;
        }
        if (inPinnedWindowingMode() && rootTask.isForceHidden()) {
            return false;
        }

        if (hasOverlayOverUntrustedModeEmbedded()) {
            return false;
        }
        if (mDisplayContent.isSleeping()) {
            return canTurnScreenOn();
        } else {
            return mTaskSupervisor.getKeyguardController().checkKeyguardVisibility(this);
        }
    }

这里额外补充一点会进行stop情况是因为有调用makeInvisible方法:

void makeInvisible() {
       //省略
       try{
            final boolean deferHidingClient = canEnterPictureInPicture
                    && !isState(STARTED, STOPPING, STOPPED, PAUSED);
            setDeferHidingClient(deferHidingClient);
            setVisibility(false);

            switch (getState()) {
                case STOPPING:
                case STOPPED:
                    // Reset the flag indicating that an app can enter picture-in-picture once the
                    // activity is hidden
                    supportsEnterPipOnTaskSwitch = false;
                    break;
                case RESUMED:
                case INITIALIZING:
                case PAUSING:
                case PAUSED://已经处于PASUED状态了
                case STARTED:
                    addToStopping(true /* scheduleIdle */,
                            canEnterPictureInPicture /* idleDelayed */, "makeInvisible");//这里会加入到Stop列表
                    break;

                default:
                    break;
            }
        } catch (Exception e) {
            // Just skip on any failure; we'll make it visible when it next restarts.
            Slog.w(TAG, "Exception thrown making hidden: " + intent.getComponent(), e);
        }
    }

3、pip进入动画流程部分

pip进入动画流程是怎么样

system_server端触发:

05-24 00:18:00.318   568  1263 I test22  : onTaskInfoChanged taskInfo = TaskInfo{userId=0 taskId=1015 displayId=0 isRunning=true baseIntent=Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.myapplication11/.MainActivity } baseActivity=ComponentInfo{com.example.myapplication11/com.example.myapplication11.MainActivity} topActivity=ComponentInfo{com.example.myapplication11/com.example.myapplication11.MainActivity} origActivity=null realActivity=ComponentInfo{com.example.myapplication11/com.example.myapplication11.MainActivity} numActivities=1 lastActiveTime=466473 supportsSplitScreenMultiWindow=true supportsMultiWindow=true resizeMode=2 isResizeable=true minWidth=-1 minHeight=-1 defaultMinSize=220 token=WCT{RemoteToken{38f3882 Task{1a959c8 #1015 type=standard A=10118:com.example.myapplication11 U=0 visible=true visibleRequested=true mode=pinned translucent=false sz=1}}} topActivityType=1 pictureInPictureParams=PictureInPictureParams( aspectRatio=72/35 expandedAspectRatio=null sourceRectHint=null hasSetActions=false hasSetCloseAction=false isAutoPipEnabled=false isSeamlessResizeEnabled=true title=null subtitle=null isLaunchIntoPip=false) shouldDockBigOverlays=false launchIntoPipHostTaskId=0 displayCutoutSafeInsets=null topActivityInfo=ActivityInfo{dbedb93 com.example.myapplication11.MainActivity} launchCookies=[android.os.BinderProxy@7dc77d0] positionInParent=Point(0, 0) parentTaskId=-1 isFocused=false isVisible=true isSleeping=false topActivityInSizeCompat=false topActivityEligibleForLetterboxEducation= false locusId=null displayAreaFeatureId=1 cameraCompatControlState=hidden}
05-24 00:18:00.318   568  1263 I test22  : java.lang.Exception
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.TaskOrganizerController$TaskOrganizerCallbacks.onTaskInfoChanged(TaskOrganizerController.java:155)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.TaskOrganizerController.dispatchTaskInfoChanged(TaskOrganizerController.java:817)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.TaskOrganizerController.dispatchPendingEvents(TaskOrganizerController.java:728)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:837)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:784)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:177)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:126)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:115)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.WindowSurfacePlacer.continueLayout(WindowSurfacePlacer.java:97)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.ActivityTaskManagerService.continueWindowLayout(ActivityTaskManagerService.java:4388)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.RootWindowContainer.moveActivityToPinnedRootTask(RootWindowContainer.java:2138)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.ActivityTaskManagerService.lambda$enterPictureInPictureMode$5$com-android-server-wm-ActivityTaskManagerService(ActivityTaskManagerService.java:3474)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.ActivityTaskManagerService$$ExternalSyntheticLambda3.run(Unknown Source:6)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.ActivityTaskManagerService.enterPictureInPictureMode(ActivityTaskManagerService.java:3497)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.ActivityClientController.enterPictureInPictureMode(ActivityClientController.java:740)
05-24 00:18:00.318   568  1263 I test22  : 	at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:878)
05-24 00:18:00.318   568  1263 I test22  : 	at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:124)
05-24 00:18:00.318   568  1263 I test22  : 	at android.os.Binder.execTransactInternal(Binder.java:1280)
05-24 00:18:00.318   568  1263 I test22  : 	at android.os.Binder.execTransact(Binder.java:1244)

systemui端进行动画开始构造堆栈如下:

<init>:273, PipAnimationController$PipTransitionAnimator (com.android.wm.shell.pip)
<init>:-1, PipAnimationController$PipTransitionAnimator (com.android.wm.shell.pip)
<init>:558, PipAnimationController$PipTransitionAnimator$2 (com.android.wm.shell.pip)
ofBounds:557, PipAnimationController$PipTransitionAnimator (com.android.wm.shell.pip)
getAnimator:180, PipAnimationController (com.android.wm.shell.pip)
animateResizePip:1482, PipTaskOrganizer (com.android.wm.shell.pip)
scheduleAnimateResizePip:1171, PipTaskOrganizer (com.android.wm.shell.pip)
onTaskAppeared:630, PipTaskOrganizer (com.android.wm.shell.pip)
updateTaskListenerIfNeeded:555, 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:7897, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:548, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:937, ZygoteInit (com.android.internal.os)

动画的起始bounds和结束bounds确定:
在这里插入图片描述

疑问3: pip自己app大小变化靠啥确定及触发的

systemui进程进行动画结束以后,会进行对应的setBound的设置

 2049: 05-24 00:18:00.768   747   747 I test22  : java.lang.Exception
	行 2050: 05-24 00:18:00.768   747   747 I test22  : 	at android.app.WindowConfiguration.setBounds(WindowConfiguration.java:293)
	行 2051: 05-24 00:18:00.768   747   747 I test22  : 	at android.window.WindowContainerTransaction.setBounds(WindowContainerTransaction.java:92)
	行 2052: 05-24 00:18:00.768   747   747 I test22  : 	at com.android.wm.shell.pip.PipTaskOrganizer.prepareFinishResizeTransaction(PipTaskOrganizer.java:1419)
	行 2053: 05-24 00:18:00.768   747   747 I test22  : 	at com.android.wm.shell.pip.PipTaskOrganizer.finishResize(PipTaskOrganizer.java:1346)
	行 2054: 05-24 00:18:00.768   747   747 I test22  : 	at com.android.wm.shell.pip.PipTaskOrganizer.-$$Nest$mfinishResize(Unknown Source:0)
	行 2055: 05-24 00:18:00.768   747   747 I test22  : 	at com.android.wm.shell.pip.PipTaskOrganizer$1.onPipAnimationEnd(PipTaskOrganizer.java:181)
	行 2056: 05-24 00:18:00.768   747   747 I test22  : 	at com.android.wm.shell.pip.PipAnimationController$PipTransitionAnimator.onAnimationEnd(PipAnimationController.java:307)
	行 2057: 05-24 00:18:00.768   747   747 I test22  : 	at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:600)
	行 2058: 05-24 00:18:00.768   747   747 I test22  : 	at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1333)
	行 2059: 05-24 00:18:00.768   747   747 I test22  : 	at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1575)
	行 2060: 05-24 00:18:00.768   747   747 I test22  : 	at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:307)
	行 2061: 05-24 00:18:00.768   747   747 I test22  : 	at android.animation.AnimationHandler.-$$Nest$mdoAnimationFrame(Unknown Source:0)
	行 2062: 05-24 00:18:00.768   747   747 I test22  : 	at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:86)
	行 2063: 05-24 00:18:00.768   747   747 I test22  : 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1229)
	行 2064: 05-24 00:18:00.768   747   747 I test22  : 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
	行 2065: 05-24 00:18:00.768   747   747 I test22  : 	at android.view.Choreographer.doCallbacks(Choreographer.java:899)
	行 2066: 05-24 00:18:00.768   747   747 I test22  : 	at android.view.Choreographer.doFrame(Choreographer.java:827)
	行 2067: 05-24 00:18:00.768   747   747 I test22  : 	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
	行 2068: 05-24 00:18:00.768   747   747 I test22  : 	at android.os.Handler.handleCallback(Handler.java:942)
	行 2069: 05-24 00:18:00.768   747   747 I test22  : 	at android.os.Handler.dispatchMessage(Handler.java:99)
	行 2070: 05-24 00:18:00.768   747   747 I test22  : 	at android.os.Looper.loopOnce(Looper.java:201)
	行 2071: 05-24 00:18:00.768   747   747 I test22  : 	at android.os.Looper.loop(Looper.java:288)
	行 2072: 05-24 00:18:00.768   747   747 I test22  : 	at android.app.ActivityThread.main(ActivityThread.java:7897)
	行 2073: 05-24 00:18:00.768   747   747 I test22  : 	at java.lang.reflect.Method.invoke(Native Method)
	行 2074: 05-24 00:18:00.768   747   747 I test22  : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
	行 2075: 05-24 00:18:00.768   747   747 I test22  : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:937)

然后systemserver进程会进行对应的setBounds

077: 05-24 00:18:00.768   568  1263 I test22  : java.lang.Exception
	行 2078: 05-24 00:18:00.768   568  1263 I test22  : 	at android.app.WindowConfiguration.setBounds(WindowConfiguration.java:293)
	行 2079: 05-24 00:18:00.768   568  1263 I test22  : 	at android.app.WindowConfiguration.setTo(WindowConfiguration.java:541)
	行 2080: 05-24 00:18:00.768   568  1263 I test22  : 	at android.content.res.Configuration.setTo(Configuration.java:1792)
	行 2081: 05-24 00:18:00.768   568  1263 I test22  : 	at com.android.server.wm.WindowOrganizerController.applyChanges(WindowOrganizerController.java:534)
	行 2082: 05-24 00:18:00.768   568  1263 I test22  : 	at com.android.server.wm.WindowOrganizerController.applyWindowContainerChange(WindowOrganizerController.java:1218)
	行 2083: 05-24 00:18:00.768   568  1263 I test22  : 	at com.android.server.wm.WindowOrganizerController.applyTransaction(WindowOrganizerController.java:428)
	行 2084: 05-24 00:18:00.768   568  1263 I test22  : 	at com.android.server.wm.WindowOrganizerController.applyTransaction(WindowOrganizerController.java:373)
	行 2085: 05-24 00:18:00.768   568  1263 I test22  : 	at com.android.server.wm.WindowOrganizerController.applyTransaction(WindowOrganizerController.java:179)
	行 2086: 05-24 00:18:00.768   568  1263 I test22  : 	at android.window.IWindowOrganizerController$Stub.onTransact(IWindowOrganizerController.java:204)
	行 2087: 05-24 00:18:00.768   568  1263 I test22  : 	at com.android.server.wm.WindowOrganizerController.onTransact(WindowOrganizerController.java:163)
	行 2088: 05-24 00:18:00.768   568  1263 I test22  : 	at android.os.Binder.execTransactInternal(Binder.java:1285)
	行 2089: 05-24 00:18:00.768   568  1263 I test22  : 	at android.os.Binder.execTransact(Binder.java:1244)

小窗app端:

05-24 00:18:00.803  2031  2031 I test22  : mBounds Rect(606, 1958 - 1384, 2336) @ { mBounds=Rect(606, 1958 - 1384, 2336) mAppBounds=Rect(606, 1958 - 1384, 2336) mMaxBounds=Rect(0, 0 - 1440, 2960) mDisplayRotation=ROTATION_0 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0}
05-24 00:18:00.803  2031  2031 I test22  : java.lang.Exception
05-24 00:18:00.803  2031  2031 I test22  : 	at android.app.WindowConfiguration.setBounds(WindowConfiguration.java:293)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.app.WindowConfiguration.setTo(WindowConfiguration.java:450)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.content.res.Configuration.setTo(Configuration.java:1047)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.content.res.ResourcesImpl.calcConfigChanges(ResourcesImpl.java:502)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.content.res.ResourcesImpl.updateConfiguration(ResourcesImpl.java:392)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.content.res.Resources.updateConfiguration(Resources.java:2142)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.content.res.Resources.updateSystemConfiguration(Resources.java:2155)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.app.ResourcesManager.applyConfigurationToResources(ResourcesManager.java:1362)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.app.ConfigurationController.handleConfigurationChanged(ConfigurationController.java:188)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.app.ConfigurationController.handleConfigurationChanged(ConfigurationController.java:134)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.app.ActivityThread.handleConfigurationChanged(ActivityThread.java:5996)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.app.servertransaction.ConfigurationChangeItem.execute(ConfigurationChangeItem.java:43)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.os.Handler.dispatchMessage(Handler.java:106)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.os.Looper.loopOnce(Looper.java:201)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.os.Looper.loop(Looper.java:288)
05-24 00:18:00.803  2031  2031 I test22  : 	at android.app.ActivityThread.main(ActivityThread.java:7897)
05-24 00:18:00.803  2031  2031 I test22  : 	at java.lang.reflect.Method.invoke(Native Method)
05-24 00:18:00.803  2031  2031 I test22  : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
05-24 00:18:00.803  2031  2031 I test22  : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:937)

ActivityRecord的WindowMode变化

发现在moveActivityToPinnedRootTask方法有如下注释:

     // Defer the windowing mode change until after the transition to prevent the activity
            // from doing work and changing the activity visuals while animating
            // TODO(task-org): Figure-out more structured way to do this long term.
            r.setWindowingMode(intermediateWindowingMode);

大概意思就是在进入pip动画过程种要禁止activity进行显示上面的变化,所以要设置为fullscreen的mode,等待动画完成才可以变化windowmode

ActivityRecord的windowmode相对特殊分为2个步骤:
1、进入pip时候,即进入pip的动画过程,是属于fullscreen的状态,但是task已经是pip了,所以需要ActivityRecord自己对应的override
2、当pip进入动画完成,则需要把ActivityRecord也设置成对应的windowmode为pip情况


--------- beginning of main

//ActivityRecord设置成对fullscreen,这样task的虽然已经是pip了但是ActivityRecord还是pip
06-29 16:12:14.011   567   737 I lsm11   : setWindowingMode windowingMode 1 ActivityRecord{4cde5aa u0 com.example.myapplication11/.MainActivity} t92}
06-29 16:12:14.011   567   737 I lsm11   : java.lang.Exception
06-29 16:12:14.011   567   737 I lsm11   : 	at com.android.server.wm.ConfigurationContainer.setWindowingMode(ConfigurationContainer.java:459)
06-29 16:12:14.011   567   737 I lsm11   : 	at com.android.server.wm.RootWindowContainer.moveActivityToPinnedRootTask(RootWindowContainer.java:2100)
06-29 16:12:14.011   567   737 I lsm11   : 	at com.android.server.wm.ActivityTaskManagerService.lambda$enterPictureInPictureMode$5$com-android-server-wm-ActivityTaskManagerService(ActivityTaskManagerService.java:3474)
06-29 16:12:14.011   567   737 I lsm11   : 	at com.android.server.wm.ActivityTaskManagerService$$ExternalSyntheticLambda3.run(Unknown Source:6)
06-29 16:12:14.011   567   737 I lsm11   : 	at com.android.server.wm.ActivityTaskManagerService.enterPictureInPictureMode(ActivityTaskManagerService.java:3497)
06-29 16:12:14.011   567   737 I lsm11   : 	at com.android.server.wm.ActivityClientController.enterPictureInPictureMode(ActivityClientController.java:740)
06-29 16:12:14.011   567   737 I lsm11   : 	at android.app.IActivityClientController$Stub.onTransact(IActivityClientController.java:878)
06-29 16:12:14.011   567   737 I lsm11   : 	at com.android.server.wm.ActivityClientController.onTransact(ActivityClientController.java:124)
06-29 16:12:14.011   567   737 I lsm11   : 	at android.os.Binder.execTransactInternal(Binder.java:1280)
06-29 16:12:14.011   567   737 I lsm11   : 	at android.os.Binder.execTransact(Binder.java:1244)


//ActivityRecord设置成对undefined,这样就可以直接继承task的pip了


//systemui端
06-29 17:52:59.173   749   749 I lsm11   : java.lang.Exception
06-29 17:52:59.173   749   749 I lsm11   : 	at android.window.WindowContainerTransaction.setActivityWindowingMode(WindowContainerTransaction.java:206)
06-29 17:52:59.173   749   749 I lsm11   : 	at com.android.wm.shell.pip.PipTaskOrganizer.prepareFinishResizeTransaction(PipTaskOrganizer.java:1407)
06-29 17:52:59.173   749   749 I lsm11   : 	at com.android.wm.shell.pip.PipTaskOrganizer.finishResize(PipTaskOrganizer.java:1346)
06-29 17:52:59.173   749   749 I lsm11   : 	at com.android.wm.shell.pip.PipTaskOrganizer.-$$Nest$mfinishResize(Unknown Source:0)
06-29 17:52:59.173   749   749 I lsm11   : 	at com.android.wm.shell.pip.PipTaskOrganizer$1.onPipAnimationEnd(PipTaskOrganizer.java:181)
06-29 17:52:59.173   749   749 I lsm11   : 	at com.android.wm.shell.pip.PipAnimationController$PipTransitionAnimator.onAnimationEnd(PipAnimationController.java:307)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:600)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1333)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1575)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:307)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.animation.AnimationHandler.-$$Nest$mdoAnimationFrame(Unknown Source:0)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:86)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1229)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1239)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.view.Choreographer.doCallbacks(Choreographer.java:899)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.view.Choreographer.doFrame(Choreographer.java:827)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1214)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.os.Handler.handleCallback(Handler.java:942)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.os.Handler.dispatchMessage(Handler.java:99)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.os.Looper.loopOnce(Looper.java:201)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.os.Looper.loop(Looper.java:288)
06-29 17:52:59.173   749   749 I lsm11   : 	at android.app.ActivityThread.main(ActivityThread.java:7898)
06-29 17:52:59.173   749   749 I lsm11   : 	at java.lang.reflect.Method.invoke(Native Method)
06-29 17:52:59.173   749   749 I lsm11   : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
06-29 17:52:59.173   749   749 I lsm11   : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

//system_server端

06-29 16:12:14.636   567  1451 I lsm11   : setWindowingMode windowingMode 0 ActivityRecord{4cde5aa u0 com.example.myapplication11/.MainActivity} t92}
06-29 16:12:14.636   567  1451 I lsm11   : java.lang.Exception
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.ConfigurationContainer.setWindowingMode(ConfigurationContainer.java:459)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.Task$$ExternalSyntheticLambda30.accept(Unknown Source:8)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.internal.util.function.pooled.PooledLambdaImpl.doInvoke(PooledLambdaImpl.java:281)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.internal.util.function.pooled.PooledLambdaImpl.invoke(PooledLambdaImpl.java:204)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.internal.util.function.pooled.OmniFunction.accept(OmniFunction.java:92)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.ActivityRecord.forAllActivities(ActivityRecord.java:4515)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.WindowContainer.forAllActivities(WindowContainer.java:1657)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.WindowContainer.forAllActivities(WindowContainer.java:1651)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.Task.setActivityWindowingMode(Task.java:4434)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.WindowOrganizerController.applyTaskChanges(WindowOrganizerController.java:599)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.WindowOrganizerController.applyWindowContainerChange(WindowOrganizerController.java:1222)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.WindowOrganizerController.applyTransaction(WindowOrganizerController.java:427)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.WindowOrganizerController.applyTransaction(WindowOrganizerController.java:372)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.WindowOrganizerController.applyTransaction(WindowOrganizerController.java:179)
06-29 16:12:14.636   567  1451 I lsm11   : 	at android.window.IWindowOrganizerController$Stub.onTransact(IWindowOrganizerController.java:204)
06-29 16:12:14.636   567  1451 I lsm11   : 	at com.android.server.wm.WindowOrganizerController.onTransact(WindowOrganizerController.java:163)
06-29 16:12:14.636   567  1451 I lsm11   : 	at android.os.Binder.execTransactInternal(Binder.java:1285)
06-29 16:12:14.636   567  1451 I lsm11   : 	at android.os.Binder.execTransact(Binder.java:1244)

安卓车机ADB升级实战:从单台调试到批量刷机的避坑指南 ADB(Android Debug Bridge)是安卓调试桥,采用C/S架构实现PC与设备通信。在车机升级中,ADB用于推送升级包、刷写分区、抓取日志,是OTA、U盘、产线刷机的核心工具。掌握ADB版本管理、驱动安装、无线调试等技巧,可解决设备识别、授权、断连等常见问题。本文分享车机ADB升级的完整方案,涵盖环境准备、分区刷写、批量脚本及避坑经验,助你高效完成升级任务。 阅读详情

相关推荐

简单的 Android ExoPlayer 和 PIP 模式

画中画是一种特殊类型的多窗口模式,主要用于视频播放。它允许用户在固定在屏幕一角的小窗口中观看视频,同时在应用程序之间导航或浏览主屏幕上的内容。

iCloudEnd的博客 1539

Android画中画(PIP)模式使用

学更好的别人,做更好的自己。——《微卡智享》本文长度为1679字,预计阅读6分钟前言现在手机端各大视频APP基本都有悬浮窗视频模式,我以前文章《Android制作带悬浮窗控制的录屏程序Demo》《Android实现可移动的悬浮窗》有介绍过悬浮窗的使用方式,而到了Android8.0时推出来画中画模式,就是让当前的Activity缩小后显示在其它Activity的上方,使用起来也非常的简单,本篇我们...

Vaccae的博客 5802

国民技术N32G45X低功耗问题之更改全局变量和栈在RAM中的地址

最近项目中用的MCU是国民技术的N32G45X,MCU的资源很丰富,RAM也很大,配套的库和例程也比较全,用起来还是不错的,但是在调试低功耗的时候还是费了不少劲。 首先由于项目低功耗需要,只能选择停机模式2(STOP2)。根据数据手册的描述,在此模式下外部低速时钟开启, RTC运行, R-SRAM保持,所有I/O状态保持,独立看门狗处于关闭状态,25℃的条件下电流为10个微安。 用的这款MCU的RAM是144KB,分为SRAM(128KB)和R-SRAM( Retention SRAM – 16KB),如果

狂想家 2485

android pip流程

title PIP流程。

341

全网最详细Seurat v5 流程复现(拿来即用)

本文是基于seurat v5版本的教程复现,主要依据来源于官网seurat v5建议大家有时间的话可以去官网进行详细阅读学习!本节内容在之前seurat v4的教程都很多都有提到,文章所用到的数据及代码已经给各位放在这里了,有需要自取!请点击这里哦提取码:bui1。

ZxVSaccount的博客 1万+

显示模组Bonding IC气泡问题的诊断与优化策略

本文深入分析了显示模组Bonding IC气泡问题的成因与优化策略,涵盖IC两端剥离气泡、彩虹状水汽气泡、电极下方无规律气泡及IC输入端气泡等类型。通过工艺参数优化、材料存储处理、清洁环境控制及维修品特殊处理等多维度解决方案,有效降低气泡不良率。同时介绍了纳米改性ACF材料、激光辅助排泡技术等前沿解决方案,为触控显示行业提供实用参考。

weixin_26805597的博客 420

Android画中画(PIP)进阶---Action按钮的使用

学更好的别人,做更好的自己。——《微卡智享》本文长度为1839字,预计阅读5分钟前言上一篇《Android画中画(PIP)模式使用》介绍了画中画的使用,今天这篇来讲讲Action按钮的使用,主要是广播方式更新UI及Android 12后的兼容性问题。实现效果代码实现微卡智享还是接着上一篇的程序代码,我们在这里进行处理,文章的最后会把Demo的源码地址发送上来。定义广播和常量ACTION_TEXTV...

Vaccae的博客 2548

代码详解——Transformer

对于一个序列,在 time_step 为 t 的时刻,我们的解码输出应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。当 Decoder 的输入矩阵和 Mask 矩阵输入矩阵包含 “ I have a cat” (0, 1, 2, 3, 4) 五个单词的表示向量,Mask 是一个 5×5 的矩阵。然后判断是否传入的mask, 如果有mask (mask参数值不为None),则把mask为0的位置,将对应位置的attn的值设为无穷小的负数。可以发现得到的输出和输入的K,Q,V的大小相同。

zyw2002的博客 7214

Android PIP画中画

借助 Android 手持设备的画中画 (PIP) 功能,用户可以将当前正在运行 activity 的应用缩到小窗口中显示。画中画对视频应用来说尤其有用,因为用户可以随时执行其他操作,不必打断内容播放。用户可以通过 SystemUI 操控该窗口的位置,并通过应用提供的操作(最多三项)与当前处于画中画模式的应用流畅地互动。画中画功能需要在支持它的应用中明确选择启用,并按 activity 运作(一个应用可以有多个 activity,但其中只有一个可处于画中画模式)。Activity 通过调用。

华南烹鱼宴 1343

pyautogui库详细教程,逐行注释(附项目实战:基于图像识别实现崩坏星穹铁道自动化测试)

本文包含了pyautogui的使用方法与常见问题指南,随文附带对游戏实现的自动化项目源码与说明文档

m0_53043024的博客 1万+

Ceph入门到精通-更换osd、扩容osd

【代码】Ceph入门到精通-更换osd、扩容osd。

隔壁老瓦的专栏 1548

Android 画中画PIP类基础功能概述

Android 画中画,悬浮窗口简述,方便功能查找。

lc136136的博客 823

Vivado报错-4 [Routed 35-3424] SLL Assignment failed ILP VU19P

Vivado报错[Routed 35-3424] SLL Assignment failed ILP VU19P

weixin_39896700的博客 1409

Activity 画中画PiP

从 Android 8.0(API 级别 26)开始,Android 允许以画中画 (PiP) 模式启动 **activity**。 画中画是一种特殊类型的**多窗口模式**,最常用于**视频播放**。 使用该模式,用户可以通过固定到屏幕一角的小窗口观看视频,同时在应用之间进行导航或浏览主屏幕上的内容。 画中画利用 Android 7.0 中提供的多窗口模式 API 来提供固定的视频叠加窗口。 如要将画中画添加到您的应用中,您需要注册支持画中画的 **activity**, 根据需要将 ac

datian1234的博客 1010

099、多摄融合与变焦系统:广角到长焦的无缝切换算法

本文分享了多摄融合与变焦系统开发中的实战经验和关键挑战。作者通过一个旗舰机项目案例,揭示了广角到长焦切换时画面抖动问题的根源——融合算法误将视差当作运动补偿,并提出"视差冻结窗口"的解决方案。文章总结了三大多摄融合难点:物理视差处理、亮度差异补偿和切换时机把控,详细阐述了分层架构设计、融合权重计算等核心技术。同时强调了产线校准的重要性,并给出五项实用建议:允许边缘鬼影保留、参数场景化配置、加强产线检测、完善调试接口,以及合理运用AI技术。全文展现了多摄融合技术在时间、空间和感知维度上的复杂平衡艺术。

sundong_81的博客 48

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Android小窗口模式,picture-in-picture(PIP画中画)的使用

然后设置视频对应的Rational给PIP,也就是说在进入PIP前和退出PIP后是需要做一些页面调整的,而且比如你有计算UI坐标或者动态修改控件位置的逻辑,在进入PIP之前都需要处理掉,回到正常模式再还原,否则进入PIP之后再去获取这些就不准确了,整个UI会乱掉。哎刚准备讲改变小窗口size的,我记得Android 8.0 拿到beta版本的时候还是可以调节小窗口大小的,有3种size,结果现在用最新的AndroidQ已经不能调节了,不知道google又改了啥。

cxu123321的博客 2392

efm32 入门.pdf

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

画中画(PIP)模式使用

本文介绍了Android 8.0推出的画中画(PIP)模式实现方法。通过在manifest配置activity支持PIP,使用PictureInPictureParams.Builder设置参数,包括宽高比、操作按钮等。文章详细讲解了如何判断设备是否支持PIP、进入PIP模式的方法、监听模式状态变化,并针对Android 12新增特性进行适配。相比传统悬浮窗实现方式,PIP模式更加简便,且提供了更流畅的用户体验。最后给出了完整的Kotlin实现代码示例,展示了从正常模式切换到画中画模式的全过程。

chuyouyinghe的专栏 457

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Android 原生 Picture in Picture 画中画功能避坑指南

Android PiP 模式也称之为画中画模式,允许用户在使用应用程序的同时,在屏幕的一角或一侧浮动显示另一个应用程序或视频。这使得用户可以同时进行多项任务,而不必切换应用程序或中断正在进行的任务。如下所示:(注:B站的 PiP 是自定义实现的,未使用系统 PiP)

修之竹的博客 3094

探索Android PIP模式:谷歌样例代码深度解析

在移动设备上享受多任务处理的乐趣已经成为现代人生活的一部分,而Android系统的【Picture-in-Picture(画中画)】功能正是为此设计的。是谷歌官方提供的一个示例应用,旨在帮助开发者理解和实现Android的PIP模式。通过这个开源项目,你可以了解如何在自己的应用程序中添加画中画功能,提升用户体验。 ## 技术分析 1. **API兼容性**:该示例应用适用于Android AP

gitblog_00009的博客 465

PIP模式详述

一、进入PIP模式 1、概述流程 创建pip stack → 创建新的TaskRecord → activity reparent到newTask → newTask reparent到pip stack → resumeFocusedStacksTopActivitive 2、时序图 3、相关代码解析 app端binder回调到ATMS的方法,如果有keyguard,先dismiss keyguard再进入pip // ActivityTaskManagerService @Override publ

xiaoyantan的博客 3143

Android画中画模式-看这篇就够啦

最近做做播放器,有个浮窗播放的需求,两种实现方式,一种是申请浮窗权限,创建浮窗参考flowWindow,一种是采用画中画模式(8.0以上) 关于画中画 Android 8.0 Oreo(API Level 26)允许活动启动画中画 Picture-in-picture(PIP)模式。PIP 是一种特殊类型的多窗口模式,主要用于视频播放。PIP 模式已经可用于 Android TV,而 Android 8.0 则让该功能可进一步用于其他 Android 设备。 画中画利用 Android 7.0 中的多.

Venus 的博客 1万+

Android12 窗口模式

Android 窗口模式

ocreativityo的博客 2294

前端实现画中画超简单,让网页飞出浏览器

点击上方前端Q,关注公众号回复加群,加入前端Q技术交流群Document Picture-in-Picture 介绍今天,我来介绍一个非常酷的前端功能:文档画中画 (Document Picture-in-Picture, 本文简称 PiP)。你有没有想过,网页上的任何内容能悬浮在桌面上????????? 视频流媒体的画中画功能你可能已经在视频平台(如腾讯视频、哔哩哔哩等网页)见过这种效果:视频播放时,可以...

LuckyWinty的博客 499

手机上开发Android车机应用一 预制系统apk

书接上回,在我的Pixel上刷上车机系统后,准备开发一个系统预制的ROOT权限的应用。今天记录下研究的预制系统apk的方法

weixin_43240212的博客 2235

Android7.0多窗口实现原理(二)

本文基于AOSP Android-7.1.1-R9代码进行分析。 Android N的的多窗口框架中,总共包含了三种模式。 Split-Screen Mode: 分屏模式。 Freeform Mode 自由模式:类似于Windows的窗口模式。 Picture In Picture Mode:画中画模式(PIP) 经过一段时间的研究,总结一句话:多窗口框架的核心思想是分栈和设置栈边界。本文会从系统源码角度分析分栈以及设置栈边界的步骤和原理,从而解析多窗口三种模式的实现方式。 栈 既然提到了分栈,

Jason_Lee155的博客 6232
上一篇: 安卓漏洞揭秘-android投屏scrcpy支持声音部分调研-千里马framework投屏开发
下一篇: PipMenuView原理讲解-车载车机手机安卓framework系统开发
千里马学框架
博客等级 码龄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、付费专栏及课程。

余额充值