Android双屏异显的实现
概述
Android實現(xiàn)雙屏異顯的實現(xiàn)方式有2種。
方式一:在Android4.2及以上平臺上,按照標(biāo)準(zhǔn)Android SDK提供的API,使用Presentation類,將一個APP的相關(guān)內(nèi)容顯示到指定的屏幕上,具體請參考https://developer.android.com/reference/android/app/Presentation.html。這種方式實現(xiàn)的是應(yīng)用內(nèi)的異顯,也是View級別的異顯。
方式二:通過修改Framework層的am,wm,display相關(guān)代碼,從而在不同的顯示設(shè)備上運行不同的應(yīng)用,這種多任務(wù)的雙屏異顯方法實現(xiàn)了不同應(yīng)用之間的異顯,本文重點講解這種雙屏異顯方法的實現(xiàn)方式。這種實現(xiàn)方式是基于某芯片廠商系列芯片,Android 6.0平臺開發(fā)的。
這需要解決如下幾個問題:
1.如何獲取所有的TaskID?
在IActivityManager.java添加接口,public List<Integer> getAllTaskIds() throws RemoteException。
ActivityManagerNative.java種實現(xiàn)了IActivityManger接口,具體實現(xiàn)如下:
?? ?@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.如何確保兩個應(yīng)用同時運行,同時保持Resume狀態(tài)?如何確保副屏Activity不會隨著主屏應(yīng)用同時銷毀?在ActivityStack.java下activityPausedLocked方法添加如下代碼:
? ? if(r.task != null && r.task.taskId == mService.getSecondDisplayTaskId())
? ? ? ? return;
上述代碼禁止副屏應(yīng)用進入Pased狀態(tài),副屏應(yīng)用將一直保持Resume狀態(tài)
3.主屏與副屏的應(yīng)用如何切換,同顯與異顯如何切換?這是通過操作主屏與副屏的窗口實現(xiàn)的,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?
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!
總結(jié)
以上是生活随笔為你收集整理的Android双屏异显的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android7.1 Presentat
- 下一篇: VNC over reverse SSH