pip触摸部分源码分析-pip窗口的移动,删除窗口/车载车机手机系统开发

Linux基础——“C语言高级编程” C语言中的细节你真的知道吗? 文章目录GCC简介 GCC简介 gcc 所支持后缀名解释 .c c原始程序 .C / .cc /.cxx C++原始程 阅读详情

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

pip窗口的开始移动过程种有一个删除按钮显示过程:

在这里插入图片描述
显示DismissTarget调用堆栈:


showDismissTargetMaybe:287, PipDismissTargetHandler (com.android.wm.shell.pip.phone)
onMove:828, PipTouchHandler$DefaultPipTouchGesture (com.android.wm.shell.pip.phone)
handleTouchEvent:575, PipTouchHandler (com.android.wm.shell.pip.phone)
onInputEvent:-1, PipController$$ExternalSyntheticLambda5 (com.android.wm.shell.pip.phone)
onInputEvent:76, PipInputConsumer$InputEventReceiver (com.android.wm.shell.pip.phone)
dispatchInputEvent:267, InputEventReceiver (android.view)
nativeConsumeBatchedInputEvents:-1, InputEventReceiver (android.view)
consumeBatchedInputEvents:247, InputEventReceiver (android.view)
doConsumeBatchedInput:84, BatchedInputEventReceiver (android.view)
run:113, BatchedInputEventReceiver$BatchedInputRunnable (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: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)

相关的创建DismissTarget的方法:

  public void createOrUpdateDismissTarget() {
        if (!mTargetViewContainer.isAttachedToWindow()) {
            mTargetViewContainer.cancelAnimators();

            mTargetViewContainer.setVisibility(View.INVISIBLE);
            mTargetViewContainer.getViewTreeObserver().removeOnPreDrawListener(this);
            mHasDismissTargetSurface = false;

            try {
                mWindowManager.addView(mTargetViewContainer, getDismissTargetLayoutParams());
            } catch (IllegalStateException e) {
                // This shouldn't happen, but if the target is already added, just update its layout
                // params.
                mWindowManager.updateViewLayout(
                        mTargetViewContainer, getDismissTargetLayoutParams());
            }
        } else {
            mWindowManager.updateViewLayout(mTargetViewContainer, getDismissTargetLayoutParams());
        }
    }

pip窗口触摸事件的接受部分解析:

从上面的删除按钮窗口展示堆栈可以看出pip窗口的触摸事件传递:

onInputEvent:-1, PipController$$ExternalSyntheticLambda5 (com.android.wm.shell.pip.phone)
onInputEvent:76, PipInputConsumer$InputEventReceiver (com.android.wm.shell.pip.phone)
dispatchInputEvent:267, InputEventReceiver (android.view)

其实核心是PipInputConsumer类,这里可以对PipInputConsumer进行详细分析
PipInputConsumer可以接受触摸事件的核心是靠调用了这个注册方法:

    public void registerInputConsumer() {
        if (mInputEventReceiver != null) {
            return;
        }
        final InputChannel inputChannel = new InputChannel();//构建对应的InputChannel
        try {
            // TODO(b/113087003): Support Picture-in-picture in multi-display.
            mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
            //调用到wms的createInputConsumer方法
            mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
        } catch (RemoteException e) {
            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: Failed to create input consumer, %s", TAG, e);
        }
        mMainExecutor.execute(() -> {
            mInputEventReceiver = new InputEventReceiver(inputChannel,
                Looper.myLooper(), Choreographer.getSfInstance());
            if (mRegistrationListener != null) {
                mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
            }
        });
    }

接下来重点看createInputConsumer

 public void createInputConsumer(IBinder token, String name, int displayId,
            InputChannel inputChannel) {

        synchronized (mGlobalLock) {
            DisplayContent display = mRoot.getDisplayContent(displayId);
            if (display != null) {
                display.getInputMonitor().createInputConsumer(token, name, inputChannel,
                        Binder.getCallingPid(), Binder.getCallingUserHandle());
            }
        }
    }
    //有调用到了InputMonitor的createInputConsumer
    void createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid,
            UserHandle clientUser) {
       //这个地方是核心关键,会创建对应的InputConsumerImpl
        final InputConsumerImpl consumer = new InputConsumerImpl(mService, token, name,
                inputChannel, clientPid, clientUser, mDisplayId);
        switch (name) {
            case INPUT_CONSUMER_WALLPAPER:
       
                break;
            case INPUT_CONSUMER_PIP:
        
                break;
            case INPUT_CONSUMER_RECENTS_ANIMATION:
                consumer.mWindowHandle.inputConfig &= ~InputConfig.NOT_FOCUSABLE;
                break;
        
        }
        //添加这个name为INPUT_CONSUMER_PIP的Consumer
        addInputConsumer(name, consumer);
    }
//下面重点分析一下InputConsumerImpl这个构造
InputConsumerImpl(WindowManagerService service, IBinder token, String name,
            InputChannel inputChannel, int clientPid, UserHandle clientUser, int displayId) {
    //调用InputManager创建相关的inputchannel,而且把inputchannel拷贝回systemui构造的inputchannel,这样inputchannel就可以通讯接受事件了

        mClientChannel = mService.mInputManager.createInputChannel(name);
        if (inputChannel != null) {
            mClientChannel.copyTo(inputChannel);
        }

       //省略
    }

综上就清楚了pip的触摸事件其实是自己使用独立的inputchannel进行的接受,和pip这个activity的窗口inputchannel没有啥关系。

pip窗口被拖拽跟手移动情况下:

相关移动其实移动的都是leash图层,都不是对相关pip的Task进行相关的bounds更新:


scheduleUserResizePip:1235, PipTaskOrganizer (com.android.wm.shell.pip)
scheduleUserResizePip:1212, PipTaskOrganizer (com.android.wm.shell.pip)
movePip:278, PipMotionHelper (com.android.wm.shell.pip.phone)
onMove:845, PipTouchHandler$DefaultPipTouchGesture (com.android.wm.shell.pip.phone)
handleTouchEvent:575, PipTouchHandler (com.android.wm.shell.pip.phone)
onInputEvent:-1, PipController$$ExternalSyntheticLambda5 (com.android.wm.shell.pip.phone)
onInputEvent:76, PipInputConsumer$InputEventReceiver (com.android.wm.shell.pip.phone)
dispatchInputEvent:267, InputEventReceiver (android.view)
nativeConsumeBatchedInputEvents:-1, InputEventReceiver (android.view)
consumeBatchedInputEvents:247, InputEventReceiver (android.view)
doConsumeBatchedInput:84, BatchedInputEventReceiver (android.view)
run:113, BatchedInputEventReceiver$BatchedInputRunnable (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: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)

相关的移动更新代码:

public void scheduleUserResizePip(Rect startBounds, Rect toBounds, float degrees,
            Consumer<Rect> updateBoundsCallback) {
   //省略
        final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
        //核心关键点就是对mLeash在scale方法中进行相关的图层位置进行更新
        mSurfaceTransactionHelper
                .scale(tx, mLeash, startBounds, toBounds, degrees)
                .round(tx, mLeash, startBounds, toBounds);
        if (mPipMenuController.isMenuVisible()) {
            mPipMenuController.movePipMenu(mLeash, tx, toBounds);
        } else {
            tx.apply();
        }
        if (updateBoundsCallback != null) {
            updateBoundsCallback.accept(toBounds);
        }
    }
//scale方法
    public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
            Rect sourceBounds, Rect destinationBounds, float degrees) {
        mTmpSourceRectF.set(sourceBounds);
        mTmpSourceRectF.offsetTo(0, 0);
        mTmpDestinationRectF.set(destinationBounds);
        mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
        mTmpTransform.postRotate(degrees,
                mTmpDestinationRectF.centerX(), mTmpDestinationRectF.centerY());
        //对图层进行相关的matrix进行设置,这里面就是相关的偏移等
        tx.setMatrix(leash, mTmpTransform, mTmpFloat9);
        return this;
    }

结下来分析一下松手后,才会真正对Task的Bounds进行设置相关堆栈
松手后会进行一个简单的pip窗口移动动画:

startBoundsAnimator:614, PipMotionHelper (com.android.wm.shell.pip.phone)
movetoTarget:451, PipMotionHelper (com.android.wm.shell.pip.phone)
flingToSnapTarget:405, PipMotionHelper (com.android.wm.shell.pip.phone)
onUp:889, PipTouchHandler$DefaultPipTouchGesture (com.android.wm.shell.pip.phone)
handleTouchEvent:587, PipTouchHandler (com.android.wm.shell.pip.phone)
onInputEvent:-1, PipController$$ExternalSyntheticLambda5 (com.android.wm.shell.pip.phone)
onInputEvent:76, PipInputConsumer$InputEventReceiver (com.android.wm.shell.pip.phone)
dispatchInputEvent:267, InputEventReceiver (android.view)
nativePollOnce:-1, MessageQueue (android.os)
next:335, MessageQueue (android.os)
loopOnce:161, 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)

动画播放完成后进行相关bounds设置:

07-02 16:09:40.678   748   748 I lsm11   : applyTransaction 1  t = WindowContainerTransaction { changes = {android.os.BinderProxy@f5e9dbd={bounds:Rect(61, 690 - 839, 1068),hasBoundsTransaction,}} hops = [] errorCallbackToken=null taskFragmentOrganizer=null }
07-02 16:09:40.678   748   748 I lsm11   : java.lang.Exception
07-02 16:09:40.678   748   748 I lsm11   : 	at android.window.WindowOrganizer.applyTransaction(WindowOrganizer.java:53)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.pip.PipTaskOrganizer.applyFinishBoundsResize(PipTaskOrganizer.java:1436)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.pip.PipTaskOrganizer.finishResize(PipTaskOrganizer.java:1383)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.pip.PipTaskOrganizer.scheduleFinishResizePip(PipTaskOrganizer.java:1279)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.pip.PipTaskOrganizer.scheduleFinishResizePip(PipTaskOrganizer.java:1261)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.pip.PipTaskOrganizer.scheduleFinishResizePip(PipTaskOrganizer.java:1253)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.pip.phone.PipMotionHelper.onBoundsPhysicsAnimationEnd(PipMotionHelper.java:657)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.pip.phone.PipMotionHelper.$r8$lambda$QFpQr4PSFRGfS8YBsx6HKEKo4u4(Unknown Source:0)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.pip.phone.PipMotionHelper$$ExternalSyntheticLambda4.run(Unknown Source:2)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.animation.PhysicsAnimator$withEndActions$1$1.invoke(PhysicsAnimator.kt:445)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.animation.PhysicsAnimator$withEndActions$1$1.invoke(PhysicsAnimator.kt:445)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.animation.PhysicsAnimator$InternalListener.onInternalAnimationEnd$frameworks__base__libs__WindowManager__Shell__android_common__WindowManager_Shell(PhysicsAnimator.kt:776)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.animation.PhysicsAnimator$configureDynamicAnimation$2$1.invoke(PhysicsAnimator.kt:672)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.animation.PhysicsAnimator$configureDynamicAnimation$2$1.invoke(PhysicsAnimator.kt:671)
07-02 16:09:40.678   748   748 I lsm11   : 	at kotlin.collections.CollectionsKt__MutableCollectionsKt.filterInPlace$CollectionsKt__MutableCollectionsKt(MutableCollections.kt:285)
07-02 16:09:40.678   748   748 I lsm11   : 	at kotlin.collections.CollectionsKt__MutableCollectionsKt.removeAll(MutableCollections.kt:269)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.animation.PhysicsAnimator$configureDynamicAnimation$2.onAnimationEnd(PhysicsAnimator.kt:671)
07-02 16:09:40.678   748   748 I lsm11   : 	at androidx.dynamicanimation.animation.DynamicAnimation.endAnimationInternal(DynamicAnimation.java:715)
07-02 16:09:40.678   748   748 I lsm11   : 	at androidx.dynamicanimation.animation.DynamicAnimation.doAnimationFrame(DynamicAnimation.java:690)
07-02 16:09:40.678   748   748 I lsm11   : 	at androidx.dynamicanimation.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:170)
07-02 16:09:40.678   748   748 I lsm11   : 	at androidx.dynamicanimation.animation.AnimationHandler$AnimationCallbackDispatcher.dispatchAnimationFrame(AnimationHandler.java:71)
07-02 16:09:40.678   748   748 I lsm11   : 	at androidx.dynamicanimation.animation.AnimationHandler.lambda$new$0(AnimationHandler.java:93)
07-02 16:09:40.678   748   748 I lsm11   : 	at androidx.dynamicanimation.animation.AnimationHandler.$r8$lambda$YiBk3K09ifLdAPQDzrOxNk7Tzy0(Unknown Source:0)
07-02 16:09:40.678   748   748 I lsm11   : 	at androidx.dynamicanimation.animation.AnimationHandler$$ExternalSyntheticLambda0.run(Unknown Source:2)
07-02 16:09:40.678   748   748 I lsm11   : 	at com.android.wm.shell.pip.phone.PipMotionHelper$1.lambda$postFrameCallback$0(PipMotionHelper.java:100)

pip窗口靠近删除按钮要被删除动画部分:

在这里插入图片描述

相关调用堆栈

animateIntoDismissTarget:301, PipMotionHelper (com.android.wm.shell.pip.phone)
lambda$init$1:126, PipDismissTargetHandler (com.android.wm.shell.pip.phone)
$r8$lambda$7QUxuWTiiuYb4BpTVK2nS5TXgZA:-1, PipDismissTargetHandler (com.android.wm.shell.pip.phone)
invoke:-1, PipDismissTargetHandler$$ExternalSyntheticLambda1 (com.android.wm.shell.pip.phone)
maybeConsumeMotionEvent:390, MagnetizedObject (com.android.wm.shell.common.magnetictarget)
maybeConsumeMotionEvent:181, PipDismissTargetHandler (com.android.wm.shell.pip.phone)
handleTouchEvent:549, PipTouchHandler (com.android.wm.shell.pip.phone)
onInputEvent:-1, PipController$$ExternalSyntheticLambda5 (com.android.wm.shell.pip.phone)
onInputEvent:76, PipInputConsumer$InputEventReceiver (com.android.wm.shell.pip.phone)
dispatchInputEvent:267, InputEventReceiver (android.view)
nativeConsumeBatchedInputEvents:-1, InputEventReceiver (android.view)
consumeBatchedInputEvents:247, InputEventReceiver (android.view)
doConsumeBatchedInput:84, BatchedInputEventReceiver (android.view)
run:113, BatchedInputEventReceiver$BatchedInputRunnable (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: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)

对应pip窗口缩小动画方法:


   /** Animates the PIP into the dismiss target, scaling it down. */
    void animateIntoDismissTarget(
            MagnetizedObject.MagneticTarget target,
            float velX, float velY,
            boolean flung, Function0<Unit> after) {
        final PointF targetCenter = target.getCenterOnScreen();

        // PIP should fit in the circle
        final float dismissCircleSize = mContext.getResources().getDimensionPixelSize(
                R.dimen.dismiss_circle_size);

        final float width = getBounds().width();
        final float height = getBounds().height();
        final float ratio = width / height;

        // Width should be a little smaller than the circle size.
        final float desiredWidth = dismissCircleSize * DISMISS_CIRCLE_PERCENT;
        final float desiredHeight = desiredWidth / ratio;
        final float destinationX = targetCenter.x - (desiredWidth / 2f);
        final float destinationY = targetCenter.y - (desiredHeight / 2f);

        // If we're already in the dismiss target area, then there won't be a move to set the
        // temporary bounds, so just initialize it to the current bounds.
        if (!mPipBoundsState.getMotionBoundsState().isInMotion()) {
            mPipBoundsState.getMotionBoundsState().setBoundsInMotion(getBounds());
        }
        mTemporaryBoundsPhysicsAnimator
                .spring(FloatProperties.RECT_X, destinationX, velX, mAnimateToDismissSpringConfig)
                .spring(FloatProperties.RECT_Y, destinationY, velY, mAnimateToDismissSpringConfig)
                .spring(FloatProperties.RECT_WIDTH, desiredWidth, mAnimateToDismissSpringConfig)
                .spring(FloatProperties.RECT_HEIGHT, desiredHeight, mAnimateToDismissSpringConfig)
                .withEndActions(after);
//直接启动动画
        startBoundsAnimator(destinationX, destinationY);
    }

删除窗口图标的动画关键条件maybeConsumeMotionEvent:

fun maybeConsumeMotionEvent(ev: MotionEvent): Boolean {
     //省略
        val targetObjectIsInMagneticFieldOf = associatedTargets.firstOrNull { target ->
           //当前motionevent的x,y和删除按钮中心x,y距离计算是否已经小于阈值
            val distanceFromTargetCenter = hypot(
                    ev.rawX - target.centerOnScreen.x,
                    ev.rawY - target.centerOnScreen.y)
            distanceFromTargetCenter < target.magneticFieldRadiusPx
        }

        // If we aren't currently stuck to a target, and we're in the magnetic field of a target,
        // we're newly stuck.
        val objectNewlyStuckToTarget =
                !objectStuckToTarget && targetObjectIsInMagneticFieldOf != null

        // If we are currently stuck to a target, we're in the magnetic field of a target, and that
        // target isn't the one we're currently stuck to, then touch events have moved into a
        // adjacent target's magnetic field.
        val objectMovedIntoDifferentTarget =
                objectStuckToTarget &&
                        targetObjectIsInMagneticFieldOf != null &&
                        targetObjectIsStuckTo != targetObjectIsInMagneticFieldOf

        if (objectNewlyStuckToTarget || objectMovedIntoDifferentTarget) {
            velocityTracker.computeCurrentVelocity(1000)
            val velX = velocityTracker.xVelocity
            val velY = velocityTracker.yVelocity

            // If the object is moving too quickly within the magnetic field, do not stick it. This
            // only applies to objects newly stuck to a target. If the object is moved into a new
            // target, it wasn't moving at all (since it was stuck to the previous one).
            if (objectNewlyStuckToTarget && abs(velX) > stickToTargetMaxXVelocity) {
                return false
            }

            // This touch event is newly within the magnetic field - let the listener know, and
            // animate sticking to the magnet.
            targetObjectIsStuckTo = targetObjectIsInMagneticFieldOf
            cancelAnimations()
            magnetListener.onStuckToTarget(targetObjectIsInMagneticFieldOf!!)
            animateStuckToTarget(targetObjectIsInMagneticFieldOf, velX, velY, false, null)

            vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
        } 
        //省略
        return objectStuckToTarget // Always consume touch events if the object is stuck.
    }
《网络安全自学教程》- OSI七层模型分层及作用,数据封装与解封过程,数据传输过程。 OSI分哪七层,每层的作用是什么,解释数据在七层模型中是怎样传输的,封包和解封过程,数据包在每一层是怎么封装和解封的。 阅读详情

相关推荐

基于睿抗智能小车省赛第一题兵人识别的学习5.25

先用pip uninstall numpy卸载,再在后面输入pip install numpy==1.23安装版本为1.23的numpy。首先安装Anaconda环境;pycharm方便使用,安装yolov5以及一大堆数据包;由于python中的numpy插件包版本过高,训练失败,所以要安装一个版本低的包。每次运行都要先运行虚拟环境,输入:conda activate。图中所有精度大概在0.768-0.99之间。这里指定安装numpy1.23.。训练完成会得到一个衡量精度的指标。等待99张图片训练完成。

Haili_的博客 1299

android 画中画模式自定义,画中画  |  Android 开源项目  |  Android Open Source Project...

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

weixin_33445134的博客 944

新装Win10/Win11后VMware虚拟机连不上网?手把手教你排查‘网络信息不可用’(从服务检查到网段配置)

本文详细介绍了在Windows 10/11系统上安装VMware Workstation后虚拟机无法联网的排查方法。从检查VMware NAT Service、DHCP Service等关键服务状态,到重置虚拟网络编辑器配置,再到内核设备驱动问题解决,手把手教你解决‘网络信息不可用’问题。特别针对VMCI驱动故障提供了实用解决方案,帮助用户快速恢复虚拟机网络连接。

weixin_28736335的博客 770

android pip流程

title PIP流程。

341

【人工智能之深度学习】21. 自动驾驶感知实战:YOLOv4复杂天气优化方案(BDD100K全代码+效果对比)

摘要:自动驾驶摄像头在雨雾天气下易受图像模糊、目标遮挡影响,导致YOLOv4检测精度骤降。本文基于BDD100K公开数据集(含多天气场景),设计三阶段优化方案:1)物理建模生成雨雾效果(雨滴线条+大气散射模型),将恶劣天气样本占比从20%提升至40%;2)在YOLOv4颈部嵌入CBAM注意力机制,强化模糊区域特征提取;3)L1剪枝(30%)+TensorRT量化实现轻量化。需特别说明:本文为教学虚拟案例,不可直接用于车载部署,实际落地需结合多传感器融合与ISO 26262认证。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1684

PS射击游戏射线检测优化:原理、工程与全链路高性能实现

射线池:减少GC,提升批量检测效率。分层检测:先粗后细,远距离射击高效判定。批量检测:并行处理,适合大量射线场景。空间结构:进一步加速大场景检测。下面继续深入射线检测优化,补充更多实用细节和进阶技巧,包括空间分区加速、射线检测多线程/异步化、射线合并与分帧、射线池通用模板、常见性能陷阱与调优建议等。对于极端性能需求,可自定义轻量级物理系统,仅检测关键对象(如玩家、子弹),跳过复杂物理引擎。结合AABB、OBB、球体等简单碰撞体,射线-包围体检测极快。空间分区+分层检测是大场景射线优化核心。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 434

Pip小窗模式到全屏模式源码分析-android framework车载车机手机系统开发

这里发现较为简单,功能就是响应一下onClick,然后启动hideMenu,会启动一个动画进行hide。

liaosongmao1的专栏 635

10、X射线聚焦与光学元件技术解析

本文深入解析了X射线聚焦与光学元件技术,重点讨论了椭圆镜的聚焦原理及局限性,多层镜的设计优化及其突破性应用,以及X射线波导的基础理论和模式求解方法。文章还总结了这些技术的优势、局限及其在材料科学、生物学和医学等领域的广泛应用前景。通过理论推导与技术改进,这些光学元件为X射线成像技术的发展提供了重要支撑。

pz890123的博客 121

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

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

gitblog_00009的博客 465

基于深度学习的农作物病虫害检测识别系统:YOLOv8 + UI界面 + 数据集

该系统的目标是使用YOLOv8模型自动检测农作物的病虫害,并通过UI界面提供实时反馈。用户可以通过上传图像,系统会输出图像中是否存在病虫害以及具体种类。数据集准备与处理:收集并准备包含农作物病虫害图像的数据集,并进行标注和数据增强。YOLOv8模型训练:使用YOLOv8训练农作物病虫害检测模型。UI界面设计与开发:开发一个用户友好的界面,支持上传图像并展示检测结果。系统测试与优化:评估模型的准确性、实时性,并对系统进行优化。

YOLO 883

使用 MATLAB/Simulink 构建一个基于PID控制的直流电机速度调节系统模型

直流电机(DC Motor)因其结构简单、成本低廉、易于控制等特点,广泛应用于各种工业自动化和家用电器中。PID控制器作为最常用的控制策略之一,在直流电机的速度调节系统中具有重要应用价值。通过合理调整比例(P)、积分(I)、微分(D)三个参数,可以实现对电机速度的精确控制。本教程将带你使用构建一个基于PID控制的直流电机速度调节系统模型,涵盖电机模型构建、PID控制器设计、系统仿真与调试等多个方面。本文介绍了如何使用构建一个基于PID控制的直流电机速度调节系统模型。

amy_mhd的博客 217

Flutter PIP 插件 ---- 新增PipActivity,Android 11以下支持自动进入PIP Mode

PIP功能从Android 8 引入,但是autoEnter功能从Android 12才开始支持,那么不支持的版本呢就需要通过监听主动调用才能进入PIP Mode,在之前的版本中因为没有转发,导致我们只能在dart中通过flutter的事件,在应用进入后台是主动调用的方式进入PIP Mode,但实际测下来,似乎无法区分通知栏下滑的通知,这导致即使应用在前台,当用户下滑通知栏的时候依然会自动进入PIP Mode。

1938

PCL 改进的RANSAC算法实现点云粗配准【2024最新版】

一种改进的RANSAC点云粗配准算法,具体改进见论文:“Pose Estimation using Local Structure-Specific Shape and Appearance Context”

点云侠的博客 37万+

基于子窗口实现应用内悬浮窗

hongxiaomeng的博客 1058

老版QQ原生表情gif动态

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

efm32 入门.pdf

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

Android 16系统源码_分屏模式(二)全屏分屏模式层级树信息

通过对比全屏和分屏模式下的窗口层级树信息,理解分屏模式的实现思路。

AfinalStone的专栏 5517

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

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

pip包详解

pip 打包

紫青宝剑的博客 2051

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

画中画 控件 android,画中画  |  Android 开源项目  |  Android Open Source Project

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

weixin_42512613的博客 471

pip-pop源码阅读

感觉还是很多地方没有读懂,这个库是做什么的都不大清楚。阅读的话还是从自己经常使用的库开始比较好。#!/usr/bin/env python # -*- coding: utf-8 -*- """Usage: pip-diff (--fresh | --stale) &lt;reqfile1&gt; &lt;reqfile2&gt; [--exclude &lt;package&gt;...]...

ZERO 1681

Android系统源码分析--Activity的finish过程

上一篇我们分析了Activity的启动流程,由于代码量很大,还是没有分析的很详细,但是基本流程都出来了,更详细的东西还是要去看源码。这一章来分析Activity的finish过程,分析一下finish的过程到底做了哪些处理,最后对Activity的整个启动过程以及finish过程绘制流程图,以方便我们记忆。 finish代码分析 // /frameworks/base/core/java/android/app/Activity.java /** * Call this .

a2923790861的博客 2373

Android 8.0 SystemUI(一):图文并茂的介绍 :D

我擅长什么? 当我想到这个这个问题的时候,脑子里是一片空白的:哎呀,我什么都知道点,可是说擅长的,还真没拿的出手的,这怎么行! 于是就有了SystemUI系列的文章。 —— 猿湿Xoong 一、本文结构 二、什么是SystemUI? 作为Android系统核心应用,SystemUI负责反馈系统及应用状态并与用户保持大量的交互。耳熟能详的三栏:StatusBar(状态栏)、Navigatio...

weixin_34247155的博客 851

Android8.0画中画(PIP)探究

    Android8.0新特性中,有个画中画的东西。全称pictrue-in-pictrue. 废话少说,先上效果:     代码很简单,大家可以移步谷歌官方文档看看。   上一下这个demo的源码点击下载...

micotale的博客 2585

基于Android10的Activity的启动流程简析

启动Activity 调用Activity的startActivity,最终都会调用startActivityForResult Instrumentation instrumentation#execStartActivity ActivityTaskManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.r

猿小蔡的博客 977

pip模块卸载源码分析

查看\Lib\site-packages\pip\_internal\req\req_uninstall.py中重要代码 卸载规律如下: 1、非本地库不删 2、stdlib和platstdlib中的标准库不删 3、存在module.egg-info文件夹删除 注意:卸载的顺序是有关系的,因为在2个相同包的情况下,pip需要卸载当前检测到的版本 删除installed-files.tx...

liuxiang15的博客 721

pip安装源码编译

在Python环境中用pip安装包pip install package_name,有时需要先对源码编译、生成wheel文件,这时需要编译工具Microsoft Visual C++ Build Tools 2015(VC++ 14.0)或者Visual Studio 2015(VC++ 14.0) ...

Always On The Way 3304

pip-pop源码分析

pip-pop源码分析

cslqm 1924

pip相关问题解决(2)-修改源码

先抛出Python错误: AttributeError: module 'pip' has no attribute 'main' 我一开始是在cmd命令行模式运行的pip install X包,没有问题,但是这样是把X包下载配置到我电脑原有的python环境中,我目前比较习惯用Anaconda里的jupyter编程,而Anaconda的python环境是另一个环境,于是我就到A...

Amigo_1997的博客 984
上一篇: android Q /R/S/T onTopResumedActivityChanged方法解析
下一篇: android framework车载桌面CarLauncher的TaskView详细源码分析
千里马学框架
博客等级 码龄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、付费专栏及课程。

余额充值