概述

Android实现双屏异显的实现方式有2种。

方式一:在Android4.2及以上平台上,按照标准Android SDK提供的API,使用Presentation类,将一个APP的相关内容显示到指定的屏幕上,具体请参考https://developer.android.com/reference/android/app/Presentation.html。这种方式实现的是应用内的异显,也是View级别的异显。

方式二:通过修改Framework层的am,wm,display相关代码,从而在不同的显示设备上运行不同的应用,这种多任务的双屏异显方法实现了不同应用之间的异显,本文重点讲解这种双屏异显方法的实现方式。这种实现方式是基于某芯片厂商系列芯片,Android 6.0平台开发的。

这需要解决如下几个问题:

1.如何获取所有的TaskID?

在IActivityManager.java添加接口,public List<Integer> getAllTaskIds() throws RemoteException。

ActivityManagerNative.java种实现了IActivityManger接口,具体实现如下:

@Override
    public List<Integer> getAllTaskIds() throws RemoteException{
            List<Integer> taskIds = new ArrayList<Integer>();
        List<StackInfo> stackInfos = getAllStackInfos();
        if(stackInfos != null && stackInfos.size() > 0){
            for(StackInfo info : stackInfos){
            int[] taskIdArray = info.taskIds;
            reverseArray(taskIdArray);
            if(taskIdArray != null && taskIdArray.length > 0){
               for(int taskId : taskIdArray)
                taskIds.add(taskId);
            }
            }
        }
        return taskIds;
    }

2.如何确保两个应用同时运行,同时保持Resume状态?如何确保副屏Activity不会随着主屏应用同时销毁?在ActivityStack.java下activityPausedLocked方法添加如下代码:
    if(r.task != null && r.task.taskId == mService.getSecondDisplayTaskId())
        return;
上述代码禁止副屏应用进入Pased状态,副屏应用将一直保持Resume状态

3.主屏与副屏的应用如何切换,同显与异显如何切换?这是通过操作主屏与副屏的窗口实现的,WindowManagerService.java添加如下代码:

public void setOnlyShowInExtendDisplay(Session session,IWindow client,int transit){
        
        long origId = Binder.clearCallingIdentity();
        synchronized(mWindowMap){
            if(mDisplayContents == null || mDisplayContents.size() <= 1){
            return;
        }
        final int displayCount = mDisplayContents.size();
        DisplayContent defaultContent = getDefaultDisplayContentLocked();
        int displayId = 0;
        DisplayContent secondDisplayContent = null;
        for(int i = 0; i < displayCount;i++){
            final DisplayContent content = mDisplayContents.valueAt(i);
            if(content != defaultContent){
                secondDisplayContent = content;
                displayId = secondDisplayContent.getDisplayId();
                break;
            }
        }
        if(secondDisplayContent == null){
            return;
        }
        if(!okToDisplay()){
            return;
        }
        WindowState current = windowForClientLocked(session, client, false); 
        if(isHomeWindow(current)){
            return;
        }
        AppWindowToken wtoken = current.mAppToken;
        if(wtoken == null){
            return;
        }
 
        
            
        int groupId = wtoken.mTask.mTaskId;
        mH.sendMessage(mH.obtainMessage(H.DO_TASK_DISPLAY_CHANGED, groupId, -1));
        }
        Binder.restoreCallingIdentity(origId);
    }
    
 
    /**
    move window to second display
    */
     public void moveTransitionToSecondDisplay(int groupId,int transit){
        //if(!isShowDualScreen()){
        //    mSecondTaskIds.clear();
        //}
        //Settings.System.putInt(mContext.getContentResolver(), Settings.DUAL_SCREEN_ICON_USED, 0);
        List<Integer> allTaskIds = null;
        try{
            allTaskIds = mActivityManager.getAllTaskIds();
        }catch (Exception e){
            Log.i("DualScreen", "WindowManagerService->getAllTaskIds->e:" + e);
        }
        
        if(allTaskIds == null || allTaskIds.size() < 2)
            return;
        
        if(isShowDualScreen()){
            moveWindowToSecondDisplayWithDualShow();
            return;
        }
        
        
        long origId = Binder.clearCallingIdentity();
        int curMoveTaskId = -1;
        synchronized(mWindowMap){
            if(mDisplayContents == null || mDisplayContents.size() <= 1){
                return;
            }
            final int displayCount = mDisplayContents.size();
            DisplayContent defaultContent = getDefaultDisplayContentLocked();
            int displayId = 0;
            DisplayContent secondDisplayContent = null;
            for(int i = 0; i < displayCount;i++){
                final DisplayContent content = mDisplayContents.valueAt(i);
                if(content != defaultContent){
                    secondDisplayContent = content;
                    displayId = secondDisplayContent.getDisplayId();
                    
                    break;
                }
            }
 
            if(secondDisplayContent == null){
                return;
            }
            if(!okToDisplay()){
                return;
            }
            SurfaceControl.openTransaction();
            WindowState win = null;
            WindowList defaultWindows = defaultContent.getWindowList();
            
            try{
                WindowList secondDisplayAddList = new WindowList();
                WindowList secondDisplayWindows = secondDisplayContent.getWindowList();
                
                int topTaskId = -1;
                if(allTaskIds != null && allTaskIds.size() > 0){
                    topTaskId = allTaskIds.get(0);
                    //mSecondTaskIds.add(topTaskId);
                }
                
                for(int i= defaultWindows.size()-1;i>=0;i--){
                    win = defaultWindows.get(i);
                    if(win == null){
                        continue;
                    }
                    if (win.mAppToken == null){
                        continue;
                    }
                
                    if(win.mAppToken.mTask == null){
                        continue;
                    }
                    int windowTaskId = win.mAppToken.mTask.mTaskId;
                    if(windowTaskId == topTaskId){
                        win.setPrimaryDisplay(true);
                        defaultWindows.remove(win);
                        mTempWindowList.add(win);
                        win.mDisplayContent = secondDisplayContent;
                        if(win.mWinAnimator != null){
                            int layerStack = secondDisplayContent.getDisplay().getLayerStack();
                            if(win.mWinAnimator.mSurfaceControl!= null){
                                win.mWinAnimator.mSurfaceControl.setLayerStack(layerStack);
                            }
 
                        }
                        secondDisplayAddList.add(0,win);
                    }
 
                }
                secondDisplayWindows.clear();
                secondDisplayWindows.addAll(secondDisplayAddList);            
                
                for (int i = 0; i < displayCount; i++) {
                    final DisplayContent content = mDisplayContents.valueAt(i);
                    assignLayersLocked(content.getWindowList());
                    content.layoutNeeded = true;
                }
                Log.i("DualScreen", "WindowManagerService->allTaskIds:" + allTaskIds);
                ArrayList<ActivityStack> allStacks = getAllStacks();
                Log.i("DualScreen", "moveTransitionToSecondDisplay->allStacks:" + allStacks);
                boolean isFind = false;
                for(int i = allStacks.size() - 1; i >= 0; --i){
                    ActivityStack itemStack = allStacks.get(i);
                    //ArrayList<TaskRecord> getAllTasks()
                    List<TaskRecord> itemTasks = itemStack.getAllTasks();
                    if(itemTasks != null && itemTasks.size() > 0){
                        for(int k = itemTasks.size() - 1; k >= 0; --k){
                            TaskRecord itemTask = itemTasks.get(k);
                            List<ActivityRecord> itemActivities = itemTask.mActivities;
                            for(int j = itemActivities.size() - 1; j >= 0; --j){
                                ActivityRecord itemActivity = itemActivities.get(j);
                                if(/*itemActivity.state == ActivityState.RESUMED && */itemTask.taskId != topTaskId){
                                    curMoveTaskId = itemTask.taskId;
                                    isFind = true;
                                    break;
                                }
                                    
                            }
                            if(isFind)
                                break;
                        }
                    }
                    if(isFind)
                        break;
                }
                mSecondDisplayTaskId = topTaskId;
                Log.i("DualScreen", "WindowManagerService->curMoveTaskId:" + curMoveTaskId);
                misMovingToSecond = true;
                Settings.System.putInt(mContext.getContentResolver(), Settings.DUAL_SCREEN_ICON_USED, 1);
                switchFocusWindow(curMoveTaskId);
                updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, false);
                mAppTransition.setReady();
                performLayoutAndPlaceSurfacesLocked();
            }finally{
                SurfaceControl.closeTransaction();
            }
            
            //shouldAppMoveBack(-1);
        }
        
        Binder.restoreCallingIdentity(origId);
        
    }
    
    
    public void moveWindowToSecondDisplayWithDualShow(){
        long origId = Binder.clearCallingIdentity();
        int secondDisplayTaskId = getSecondDisplayTaskId();
        int currentFocusedTaskId = -1;
        int curMoveTaskId = secondDisplayTaskId;
        if(mFocusedApp != null && mFocusedApp.mTask != null)
            currentFocusedTaskId = mFocusedApp.mTask.mTaskId;
        Log.i("DualScreen", "WindowManagerService->moveWindowToSecondDisplayWithDualShow->currentFocusedTaskId:" + currentFocusedTaskId);
        //mSecondDisplayTaskId = currentFocusedTaskId;
        synchronized(mWindowMap){
            if(mDisplayContents == null || mDisplayContents.size() <= 1){
                return;
            }
            final int displayCount = mDisplayContents.size();
            DisplayContent defaultContent = getDefaultDisplayContentLocked();
            int displayId = 0;
            DisplayContent secondDisplayContent = null;
            for(int i = 0; i < displayCount;i++){
                final DisplayContent content = mDisplayContents.valueAt(i);
                if(content != defaultContent){
                    secondDisplayContent = content;
                    displayId = secondDisplayContent.getDisplayId();
                    Log.d("DualScreen", "WindowManagerService->moveWindowToSecondDisplayWithDualShow->secondDisplayId:" + displayId);
                    break;
                }
            }
 
            if(secondDisplayContent == null){
                return;
            }
            if(!okToDisplay()){
                return;
            }
            SurfaceControl.openTransaction();
            WindowState win = null;
            try{
                WindowList secondDisplayAddList = new WindowList();
                WindowList defaultDisplayAddList = new WindowList();
                WindowList secondDisplayWindows = secondDisplayContent.getWindowList();
                WindowList defaultWindows = defaultContent.getWindowList();
                
                if(mTempWindowList != null && mTempWindowList.size() > 0)
                    defaultWindows.addAll(mTempWindowList);
                mTempWindowList.clear();
                
                for(int i= defaultWindows.size()-1;i>=0;i--){
                    win = defaultWindows.get(i);
                    if(win == null){
                        continue;
                    }
                    if (win.mAppToken == null){
                        continue;
                    }
                
                    if(win.mAppToken.mTask == null){
                        continue;
                    }
                    int windowTaskId = win.mAppToken.mTask.mTaskId;
                    if(windowTaskId == currentFocusedTaskId){
                        defaultWindows.remove(win);
                        win.mDisplayContent = secondDisplayContent;
                        if(win.mWinAnimator != null){
                            int layerStack = secondDisplayContent.getDisplay().getLayerStack();
                            if(win.mWinAnimator.mSurfaceControl!= null){
                                win.mWinAnimator.mSurfaceControl.setLayerStack(layerStack);
                            }
                            
                        }
                        secondDisplayAddList.add(0,win);
                    }
 
                }
                
                
                for(int i= secondDisplayWindows.size()-1;i>=0;i--){
                    win = secondDisplayWindows.get(i);
                    if(win == null){
                        continue;
                    }
                    if (win.mAppToken == null){
                        continue;
                    }
                
                    if(win.mAppToken.mTask == null){
                        continue;
                    }
                    int windowTaskId = win.mAppToken.mTask.mTaskId;
                    if(windowTaskId == secondDisplayTaskId){
                        secondDisplayWindows.remove(win);
                        win.mDisplayContent = defaultContent;
                        if(win.mWinAnimator != null){
                            int layerStack = defaultContent.getDisplay().getLayerStack();
                            if(win.mWinAnimator.mSurfaceControl!= null){
                                win.mWinAnimator.mSurfaceControl.setLayerStack(layerStack);
                            }
                            
                        }
                        defaultDisplayAddList.add(0,win);
                    }
 
                }
                
                //secondDisplayWindows.clear();
                secondDisplayWindows.addAll(0,secondDisplayAddList);
                //defaultWindows.clear();
                defaultWindows.addAll(0, defaultDisplayAddList);
                for (int i = 0; i < displayCount; i++) {
                    final DisplayContent content = mDisplayContents.valueAt(i);
                    assignLayersLocked(content.getWindowList());
                    content.layoutNeeded = true;
                }
                //Log.i("DualScreen", "WindowManagerService->moveWindowToSecondDisplayWithDualShow->allTaskIds:" + allTaskIds);
                ArrayList<ActivityStack> allStacks = getAllStacks();
                Log.i("DualScreen", "WindowManagerService->moveWindowToSecondDisplayWithDualShow->allStacks:" + allStacks);
                mSecondDisplayTaskId = currentFocusedTaskId;
                Log.i("DualScreen", "WindowManagerService->moveWindowToSecondDisplayWithDualShow->curMoveTaskId:" + curMoveTaskId);
                misMovingToSecond = true;
                Settings.System.putInt(mContext.getContentResolver(), Settings.DUAL_SCREEN_ICON_USED, 1);
                switchFocusWindow(curMoveTaskId);
                updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, false);
                mAppTransition.setReady();
                performLayoutAndPlaceSurfacesLocked();
            }finally{
                SurfaceControl.closeTransaction();
            }
            
            //shouldAppMoveBack(-1);
        }
        
        Binder.restoreCallingIdentity(origId);
    }

4.副屏页面如何全屏显示?修改PhoneWindowManager.java下layoutWindowLw方法添加代码如下:

pf.top = df.top = of.top = cf.top = vf.top = 0;
     pf.right = df.right = of.right = cf.right = vf.right = width;
     pf.bottom = df.bottom = of.bottom = cf.bottom = vf.bottom = height;

--------------------- 
作者:默默等待__007 
来源:CSDN 
原文:https://blog.csdn.net/u011365633/article/details/55001840 
版权声明:本文为博主原创文章,转载请附上博文链接!

Android双屏异显的实现相关推荐

  1. android双屏异显获取副屏参数,Android 双屏 异显 插件 双屏(副屏)异显,主副屏通讯...

    更新记录 1.2.0(2021-04-12) 优化副屏视频播放功能. 1.1.0(2020-07-01) 新增,视频列表播放,可以在副屏播放一些广告视频等等. 查看更多 平台兼容性 Android i ...

  2. Android 双屏异显(Presentation) 开发,将第二个页面投屏到副屏上

    1. 背景 最近开发的一个项目,有两个屏幕,需要将第二个页面投屏到副屏上, 这就需要用到Android的双屏异显(Presentation)技术了,研究了一下,这里做下笔记. 我们那个副屏是一块汽车的 ...

  3. 【Android双屏异显】如何真正的实现Android双屏异显

    最近在做一个Android双屏异显的项目,要实现一台Android设备通过HDMI连接两个显示器,然后在一个App中同时显示两个不同的画面. 标题实际上Android并不存在真正的像Windows一样 ...

  4. Android双屏异显另辟蹊径---minui的移植

    minui介绍 minui是Android自带的一个画图工具,可以绘制一些简单的图形和图像,显示png图片,显示字符串等. 在Android设备中譬如,关机充电动画,自动测试程序,recovery模式 ...

  5. Android 双屏异显(兼容android8)

    1.双屏判断(是否支持双屏异显) 2.权限申请(android 6 以后需要申请权限) 3.客显实例化 (客显布局) public void initDiffDisplay() {try {Displ ...

  6. Android双屏异显

    和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一.设置Simulate secondary displays 二.实现副屏异显 三.实现效果 Andr ...

  7. Android 双屏异显

    背景: 日常生活中,有时候会遇到 Android 设备连接两个屏幕进行显示的问题,比如酒店登记信息时,一个屏幕用于员工操作,一个屏幕显示相关信息供顾客查看.这里就涉及到 Android 的双屏异显的问 ...

  8. android 分屏投影,Android 双屏异显实现的三种方式

    在各种产品脑洞大开的时代,需求也是日益新异,笔者最近开发了一套双屏异显app.现在做一些总结 1.双屏异显第一种实现方式(官方提供的Presentation) Android 提供了一个叫 Prese ...

  9. 【转载】Android 双屏异显方案

    一.技术的背景 随着电梯广告传媒行业的飞速发展,双屏广告机应运而生,客户可以根据自己的需求,制作两个屏幕的内容,分别播放适合屏幕显示方式播放的内容,如上面播放视频,下面播放图片,使得宣传的效果多样化. ...

最新文章

  1. 微软算法100题11 求二叉树中两节点之间的最大距离
  2. IEEE signal processing letters 投稿经验
  3. jQuery异步上传文件
  4. VC6如何使用VS2005中的CImage类功能
  5. CNVD-C-2019-48814 漏洞
  6. Java案例-用户注册邮箱验证将邮箱激活码存入redis功能实现
  7. 以非泛型方式调用泛型方法(三)
  8. springcloud 入门 10 (eureka高可用)
  9. oracle导出审计表,Oracle审计表AUD$处理方法
  10. matlab 控制实验指导,智能控制系统-实验指导书-实验一-BP算法的MATLAB实现
  11. 数据:以太坊2.0合约余额新增6976 ETH
  12. 三层交换机配置DHCP的解决方案
  13. 学习记录:由技术而产品,由产品而商务
  14. python写诗代码_pyTorch实现AI写诗:开放源码
  15. tolua unity 报错_关于LUA+Unity开发_toLua篇【二】
  16. c语言中pinMode的作用,Arduino编程基础与常用函数(详细)解析
  17. MIMIC数据库数据提取教程-提取时间维度数据
  18. java线程池中的Worker解析
  19. 计算机科学技术学院迎新晚会主题,我校计算机科学与技术学院举行迎新晚会
  20. WebRTC系列--视频编码控制之BALANCED(分辨率与帧率平衡模式)

热门文章

  1. 3D 服务器端以向量计算为主的角色位置的算法
  2. 【电信增值业务学习笔记】10基于业务节点的增值业务提供技术
  3. 使用sprc097的DSP281x_usDelay.asm
  4. 如何利用ESP8266模块实现远程控制
  5. leetcode刷题实录:2
  6. R学习_multitaper包解析1:子函数centre,dpss
  7. linux常用关机、重启、注销命令
  8. 【MSTR产品】获取当前登陆用户的login_id
  9. SIFT四部曲之——构建关键点特征描述符
  10. Jupyter notebook入门教程(下)