Android P 分屏显示

分屏显示

  • 前提概要:
  • 问题1、启动左边显示仪表os、右边显示ivi.
  • 问题2、固定分屏 、不显示recent view画面
  • 问题3、显示home的时候强制修改home的大小
  • 问题4、不支持应用分屏的app,要全屏显示
  • 问题5、config配置是否支持分屏显示

前提概要:

我是做车机ivi开发的,目前有个需求是仿特斯拉的娱乐系统显示,用一个大屏左边来显示仪表os、右边来显示ivi。
我的ivi是基于Android os来发的,所以分屏方案也是基于Android的应用分屏来实现的。

但是原来Android的应用分屏不能完全满足我们的要求:
1、我们要一启动左边显示仪表os、右边显示ivi。
2、左右分屏大小要固定,不能拖拽,不支持用户进入recent view画面,选择recent app。
3、原生的Android不支持home stack分屏显示,我们需要在显示home的时候强制修改home的大小。
4、不支持应用分屏的app,要全屏显示,退出全屏app之后又要回到左边显示仪表os、右边显示ivi home。
5、config配置是否支持分屏显示

基本就是要解决上面几个问题。

问题1、启动左边显示仪表os、右边显示ivi.

首先 Android 提供了分屏的api, 调用ActivityManagerService中setTaskWindowingModeSplitScreenPrimary() 、resizeStack() 来实现分屏。

 // mLeftScreenTask 就是正在运行的要分屏的apk,SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT是分屏模式为分屏apk在上面或者右边,mSplitLeftRect是要分屏的应用占全屏大小
  mAm.setTaskWindowingModeSplitScreenPrimary(mLeftScreenTask.id,
      SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT,
      true, true, mSplitLeftRect, false);
 // 调整分屏apk的占平大小。
  mAm.resizeStack(mLeftScreenTask.stackId, mSplitLeftRect,
      false, false, false, -1);

其实我们左边显示的是任意的一个apk,只是起到占位的作用,后面会通过视频流的形式将仪表的os投影过来。

问题2、固定分屏 、不显示recent view画面

这块就注释掉Android原生的一些功能。
frameworks/base/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java

   // 显示 recent app的地方
    public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents,
            boolean animate, int growTarget) {
        /** case : aiways No need to display the recent app to give users a choice, 
        So comment out the code

        final SystemServicesProxy ssp = Recents.getSystemServices();
        final MutableBoolean isHomeStackVisible = new MutableBoolean(true);
        final boolean isRecentsVisible = Recents.getSystemServices().isRecentsActivityVisible(
                isHomeStackVisible);
        final boolean fromHome = isHomeStackVisible.value;
        final boolean launchedWhileDockingTask =
                Recents.getSystemServices().getSplitScreenPrimaryStack() != null;

        mTriggeredFromAltTab = triggeredFromAltTab;
        mDraggingInRecents = draggingInRecents;
        mLaunchedWhileDocking = launchedWhileDockingTask;
        if (mFastAltTabTrigger.isAsleep()) {
            // Fast alt-tab duration has elapsed, fall through to showing Recents and reset
            mFastAltTabTrigger.stopDozing();
        } else if (mFastAltTabTrigger.isDozing()) {
            // Fast alt-tab duration has not elapsed.  If this is triggered by a different
            // showRecents() call, then ignore that call for now.
            // TODO: We can not handle quick tabs that happen between the initial showRecents() call
            //       that started the activity and the activity starting up.  The severity of this
            //       is inversely proportional to the FAST_ALT_TAB_DELAY_MS duration though.
            if (!triggeredFromAltTab) {
                return;
            }
            mFastAltTabTrigger.stopDozing();
        } else if (triggeredFromAltTab) {
            // The fast alt-tab detector is not yet running, so start the trigger and wait for the
            // hideRecents() call, or for the fast alt-tab duration to elapse
            mFastAltTabTrigger.startDozing();
            return;
        }

        try {
            // Check if the top task is in the home stack, and start the recents activity
            final boolean forceVisible = launchedWhileDockingTask || draggingInRecents;
            if (forceVisible || !isRecentsVisible) {
                ActivityManager.RunningTaskInfo runningTask =
                        ActivityManagerWrapper.getInstance().getRunningTask();
                startRecentsActivityAndDismissKeyguardIfNeeded(runningTask,
                        isHomeStackVisible.value || fromHome, animate, growTarget);
            }
        } catch (ActivityNotFoundException e) {
            Log.e(TAG, "Failed to launch RecentsActivity", e);
        }*/
    }

frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java

    // 这个也是第一次进入分屏要显示empty view,我们不需要,就注释掉了
    public void showEmptyView(int msgResId) {
        /** case : aiways No need to display the empty view to give users , 
        So comment out the code
        mTaskStackView.setVisibility(View.INVISIBLE);
        mEmptyView.setText(msgResId);
        mEmptyView.setVisibility(View.VISIBLE);
        mEmptyView.bringToFront();
        mStackActionButton.bringToFront(); */
    }

frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java

		// 这个里面是监听,在home界面的时候会缩进分屏app的大小,我们这里要求分屏大小一直不变,就注释掉了
        @Override
        public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
                boolean isHomeStackResizable) throws RemoteException {
            /** case : When the android native function displays the home app, 
                the split screen screen needs to be indented, aiways don't need this function.
            mHomeStackResizable = isHomeStackResizable;
            updateMinimizedDockedStack(minimized, animDuration, isHomeStackResizable); */
        }

frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java

@Override
   // 这个是提供给用户自由调整分屏大小的地方,我们不需要也注释掉了
    public boolean onTouch(View v, MotionEvent event) {
        convertToScreenCoordinates(event);
        final int action = event.getAction() & MotionEvent.ACTION_MASK;
        // switch (action) {
        //     case MotionEvent.ACTION_DOWN:
        //         Log.d("DividerView", "ACTION_DOWN");
        //         mVelocityTracker = VelocityTracker.obtain();
        //         mVelocityTracker.addMovement(event);
        //         mStartX = (int) event.getX();
        //         mStartY = (int) event.getY();
        //         boolean result = startDragging(true /* animate */, true /* touching */);
        //         if (!result) {

        //             // Weren't able to start dragging successfully, so cancel it again.
        //             stopDragging();
        //         }
        //         mStartPosition = getCurrentPosition();
        //         mMoving = false;
        //         return result;
        //     case MotionEvent.ACTION_MOVE:
        //         Log.d("DividerView", "ACTION_MOVE");
        //         mVelocityTracker.addMovement(event);
        //         int x = (int) event.getX();
        //         int y = (int) event.getY();
        //         boolean exceededTouchSlop =
        //                 isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop
        //                         || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop);
        //         if (!mMoving && exceededTouchSlop) {
        //             mStartX = x;
        //             mStartY = y;
        //             mMoving = true;
        //         }
        //         if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
        //             SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget(
        //                     mStartPosition, 0 /* velocity */, false /* hardDismiss */);
        //             resizeStackDelayed(calculatePosition(x, y), mStartPosition, snapTarget);
        //         }
        //         break;
        //     case MotionEvent.ACTION_UP:
        //         Log.d("DividerView", "ACTION_UP");
        //     case MotionEvent.ACTION_CANCEL:
        //         Log.d("DividerView", "ACTION_CANCEL");
        //         mVelocityTracker.addMovement(event);

        //         x = (int) event.getRawX();
        //         y = (int) event.getRawY();

        //         mVelocityTracker.computeCurrentVelocity(1000);
        //         int position = calculatePosition(x, y);
        //         stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
        //                 : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */,
        //                 true /* log */);
        //         mMoving = false;
        //         break;
        // }
        return true;
    }

问题3、显示home的时候强制修改home的大小

这个问题是home stack是一个独立的apk stack,和其他的apk不一样,Android原生的是不支持home 分屏的,所以我们这边在phoneWindowManager里面强制修改了home的显示大小
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

    private void layoutScreenDecorWindows(DisplayFrames displayFrames, Rect pf, Rect df, Rect dcf) {
     .........
       // 判断如果是home apk就强制显示为HOME_WIDTH
	   if(win.getAttrs().packageName.equals(HOME_PACKAGE_NAME))
	    {
	        Slog.v(TAG,"laucher,displayFrames.mDisplayCutout:"+displayFrames.mDisplayCutout);
	     	// dcf.right = HOME_WIDTH;
	     	// of.right = HOME_WIDTH;
	      //   df.right = HOME_WIDTH;
	      //   pf.right = HOME_WIDTH;
	      //   cf.right = HOME_WIDTH;
	      //   vf.right = HOME_WIDTH;

			dcf.left = HOME_WIDTH;
	     	of.left = HOME_WIDTH;
	        df.left = HOME_WIDTH;
	        pf.left = HOME_WIDTH;
	        cf.left = HOME_WIDTH;
	        vf.left = HOME_WIDTH;

	    }

        win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf, displayFrames.mDisplayCutout,
                parentFrameWasClippedByDisplayCutout);
    .......
  }

问题4、不支持应用分屏的app,要全屏显示

每一个应用的androidmanifest.xml 中可通过android:resizeableActivity=“true” 或 "false"来配置,是否支持分屏。
而我们可以通过监听 onActivityDismissingDockedStack来关闭分屏模式。


    private TaskStackListener mTaskStackListener =
            new TaskStackListener() {
        @Override
        public void onTaskStackChanged() {

            ActivityManager.StackInfo topStack = getTopStackInfo();
            Log.d(TAG, "onTaskStackChanged topStack.stackId: " + topStack.stackId);
            Log.d(TAG, "onTaskStackChanged topStack name: " + topStack.topActivity.toString());
            if (topStack != null) {
                mCurrentTask = getTaskInfoByActivityName(topStack.topActivity);

                if (topStack.topActivity.getPackageName().equals(LEFT_SCREEN_PKG_NAME)) {
                    mLeftScreenTask = mCurrentTask;
                }

                if (mCurrentTask.resizeMode != ActivityInfo.RESIZE_MODE_UNRESIZEABLE) {
                        showSplitScreen();
                }
            }

            //first to start left screen apk;
            if (mLeftScreenTask == null) {
                startLeftScreenActivty();
            }
        }

        @Override
        public void onTaskCreated(int taskId, ComponentName componentName) {
            Log.d(TAG, "onTaskCreated taskId: " + taskId);
            Log.d(TAG, "onTaskCreated componentName: " + componentName.toString());
                mCurrentTask = getTaskInfoByTaskId(taskId);
            Log.d(TAG, "onTaskCreated getPackageName: " + mCurrentTask.topActivity.getPackageName());
                if (mCurrentTask.topActivity.getPackageName().equals(LEFT_SCREEN_PKG_NAME)) {
                    mLeftScreenTask = mCurrentTask;
                    showSplitScreen();
                }            
        }

        @Override
        public void onTaskMovedToFront(int taskId) {
            Log.d(TAG, "onTaskMovedToFront taskId: " + taskId);
        }

        public void onActivityForcedResizable(String packageName, int taskId,
                int reason) {
                Log.d(TAG, "onActivityForcedResizable -> packageName:" + packageName);
        }

        @Override
        public void onActivityDismissingDockedStack() {
            Log.d(TAG, "onActivityDismissingDockedStack");
            hideSplitScreen();   // 关闭分屏
        }

        @Override
        public void onActivityLaunchOnSecondaryDisplayFailed() {
        }
    };

问题5、config配置是否支持分屏显示

frameworks/base/core/res/res/values/config.xml 里面有一个配置项
    <!-- True if the device supports at least one form of multi-window.
         E.g. freeform, split-screen, picture-in-picture. -->
    <bool name="config_supportsMultiWindow">true</bool>

    <!-- True if the device supports split screen as a form of multi-window. -->
    <bool name="config_supportsSplitScreenMultiWindow">true</bool>

    <!-- True if the device supports running activities on secondary displays. -->
    <bool name="config_supportsMultiDisplay">true</bool>

原生的是支持分屏的,但是我们用别的设备时,在device下对 config_supportsSplitScreenMultiWindow做了overlay设置成了false。搞的我们去跟踪源码才找到这个配置项被改为了false,导致不能分屏

<bool name="config_supportsSplitScreenMultiWindow">false</bool>

你可能感兴趣的:(android,android,分屏)