1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.emulator.multidisplay; 18 19 import android.content.Context; 20 import android.app.Service; 21 import android.content.Intent; 22 import android.os.Handler; 23 import android.os.IBinder; 24 import android.util.Log; 25 import android.hardware.display.DisplayManager; 26 import android.hardware.display.VirtualDisplay; 27 import android.view.Surface; 28 import android.os.Messenger; 29 30 31 public class MultiDisplayService extends Service { 32 private static final String TAG = "MultiDisplayService"; 33 private static final String DISPLAY_NAME = "Emulator 2D Display"; 34 private static final String[] UNIQUE_DISPLAY_ID = new String[]{"notUsed", "1234562", 35 "1234563", "1234564", 36 "1234565", "1234566", 37 "1234567", "1234568", 38 "1234569", "1234570", 39 "1234571"}; 40 private static final int MAX_DISPLAYS = 10; 41 private static final int ADD = 1; 42 private static final int DEL = 2; 43 private static final int mFlags = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | 44 DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | 45 DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT | 46 DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED | 47 1 << 6 |//DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH 48 1 << 9; //DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; 49 private DisplayManager mDisplayManager; 50 private VirtualDisplay mVirtualDisplay[]; 51 private Surface mSurface[]; 52 private Messenger mMessenger; 53 private ListenerThread mListener; 54 55 private final Handler mHandler = new Handler(); 56 57 class MultiDisplay { 58 public int width; 59 public int height; 60 public int dpi; 61 public int flag; 62 public VirtualDisplay virtualDisplay; 63 public Surface surface; 64 public boolean enabled; MultiDisplay()65 MultiDisplay() { 66 clear(); 67 } clear()68 public void clear() { 69 width = 0; 70 height = 0; 71 dpi = 0; 72 flag = 0; 73 virtualDisplay = null; 74 surface = null; 75 enabled = false; 76 } set(int w, int h, int d, int f)77 public void set(int w, int h, int d, int f) { 78 width = w; 79 height = h; 80 dpi = d; 81 flag = f; 82 enabled = true; 83 } match(int w, int h, int d, int f)84 public boolean match(int w, int h, int d, int f) { 85 return (w == width && h == height && d == dpi && f == flag); 86 } 87 } 88 private MultiDisplay mMultiDisplay[]; 89 90 @Override onCreate()91 public void onCreate() { 92 super.onCreate(); 93 94 try { 95 System.loadLibrary("emulator_multidisplay_jni"); 96 } catch (Exception e) { 97 Log.e(TAG, "Failed to loadLibrary: " + e); 98 } 99 100 mListener = new ListenerThread(); 101 mListener.start(); 102 103 mDisplayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE); 104 mMultiDisplay = new MultiDisplay[MAX_DISPLAYS + 1]; 105 for (int i = 0; i < MAX_DISPLAYS + 1; i++) { 106 mMultiDisplay[i] = new MultiDisplay(); 107 } 108 } 109 110 @Override onBind(Intent intent)111 public IBinder onBind(Intent intent) { 112 if(mMessenger == null) 113 mMessenger = new Messenger(mHandler); 114 return mMessenger.getBinder(); 115 } 116 117 @Override onStartCommand(Intent intent, int flags, int startId)118 public int onStartCommand(Intent intent, int flags, int startId) { 119 // keep it alive. 120 return START_STICKY; 121 } 122 123 class ListenerThread extends Thread { ListenerThread()124 ListenerThread() { 125 super(TAG); 126 } 127 deleteVirtualDisplay(int displayId)128 private void deleteVirtualDisplay(int displayId) { 129 if (!mMultiDisplay[displayId].enabled) { 130 return; 131 } 132 if (mMultiDisplay[displayId].virtualDisplay != null) { 133 mMultiDisplay[displayId].virtualDisplay.release(); 134 } 135 if (mMultiDisplay[displayId].surface != null) { 136 mMultiDisplay[displayId].surface.release(); 137 } 138 mMultiDisplay[displayId].clear(); 139 nativeReleaseListener(displayId); 140 } 141 createVirtualDisplay(int displayId, int w, int h, int dpi, int flag)142 private void createVirtualDisplay(int displayId, int w, int h, int dpi, int flag) { 143 mMultiDisplay[displayId].surface = nativeCreateSurface(displayId, w, h); 144 mMultiDisplay[displayId].virtualDisplay = mDisplayManager.createVirtualDisplay( 145 null /* projection */, 146 DISPLAY_NAME, w, h, dpi, 147 mMultiDisplay[displayId].surface, flag, 148 null /* callback */, 149 null /* handler */, 150 UNIQUE_DISPLAY_ID[displayId]); 151 mMultiDisplay[displayId].set(w, h, dpi, flag); 152 } 153 addVirtualDisplay(int displayId, int w, int h, int dpi, int flag)154 private void addVirtualDisplay(int displayId, int w, int h, int dpi, int flag) { 155 if (mMultiDisplay[displayId].match(w, h, dpi, flag)) { 156 return; 157 } 158 if (mMultiDisplay[displayId].virtualDisplay == null) { 159 createVirtualDisplay(displayId, w, h, dpi, flag); 160 return; 161 } 162 if (mMultiDisplay[displayId].flag != flag) { 163 deleteVirtualDisplay(displayId); 164 createVirtualDisplay(displayId, w, h, dpi, flag); 165 return; 166 } 167 if (mMultiDisplay[displayId].width != w || mMultiDisplay[displayId].height != h) { 168 nativeResizeListener(displayId, w, h); 169 } 170 // only dpi changes 171 mMultiDisplay[displayId].virtualDisplay.resize(w, h, dpi); 172 mMultiDisplay[displayId].set(w, h, dpi, flag); 173 } 174 175 @Override run()176 public void run() { 177 while(nativeOpen() <= 0) { 178 Log.e(TAG, "failed to open multiDisplay pipe, retry"); 179 } 180 while(true) { 181 int[] array = {0, 0, 0, 0, 0, 0}; 182 if (!nativeReadPipe(array)) { 183 continue; 184 } 185 switch (array[0]) { 186 case ADD: { 187 for (int j = 0; j < 6; j++) { 188 Log.d(TAG, "received " + array[j]); 189 } 190 int i = array[1]; 191 int width = array[2]; 192 int height = array[3]; 193 int dpi = array[4]; 194 int flag = (array[5] != 0) ? array[5] : mFlags; 195 if (i < 1 || i > MAX_DISPLAYS || width <=0 || height <=0 || dpi <=0 196 || flag < 0) { 197 Log.e(TAG, "invalid parameters for add/modify display"); 198 break; 199 } 200 addVirtualDisplay(i, width, height, dpi, flag); 201 break; 202 } 203 case DEL: { 204 int i = array[1]; 205 Log.d(TAG, "DEL " + i); 206 if (i < 1 || i > MAX_DISPLAYS) { 207 Log.e(TAG, "invalid parameters for delete display"); 208 break; 209 } 210 deleteVirtualDisplay(i); 211 break; 212 } 213 } 214 } 215 } 216 } 217 nativeOpen()218 private native int nativeOpen(); nativeCreateSurface(int displayId, int width, int height)219 private native Surface nativeCreateSurface(int displayId, int width, int height); nativeReadPipe(int[] arr)220 private native boolean nativeReadPipe(int[] arr); nativeReleaseListener(int displayId)221 private native boolean nativeReleaseListener(int displayId); nativeResizeListener(int displayId, int with, int height)222 private native boolean nativeResizeListener(int displayId, int with, int height); 223 } 224