• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                                       1 << 6 |//DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
47                                       1 << 9; //DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
48     private DisplayManager mDisplayManager;
49     private VirtualDisplay mVirtualDisplay[];
50     private Surface mSurface[];
51     private Messenger mMessenger;
52     private ListenerThread mListener;
53 
54     private final Handler mHandler = new Handler();
55 
56     class MultiDisplay {
57         public int width;
58         public int height;
59         public int dpi;
60         public int flag;
61         public VirtualDisplay virtualDisplay;
62         public Surface surface;
63         public boolean enabled;
MultiDisplay()64         MultiDisplay() {
65             clear();
66         }
clear()67         public void clear() {
68             width = 0;
69             height = 0;
70             dpi = 0;
71             flag = 0;
72             virtualDisplay = null;
73             surface = null;
74             enabled = false;
75         }
set(int w, int h, int d, int f)76         public void set(int w, int h, int d, int f) {
77             width = w;
78             height = h;
79             dpi = d;
80             flag = f;
81             enabled = true;
82         }
match(int w, int h, int d, int f)83         public boolean match(int w, int h, int d, int f) {
84             return (w == width && h == height && d == dpi && f == flag);
85         }
86     }
87     private MultiDisplay mMultiDisplay[];
88 
89     @Override
onCreate()90     public void onCreate() {
91         super.onCreate();
92 
93         try {
94             System.loadLibrary("emulator_multidisplay_jni");
95         } catch (Exception e) {
96             Log.e(TAG, "Failed to loadLibrary: " + e);
97         }
98 
99         mListener = new ListenerThread();
100         mListener.start();
101 
102         mDisplayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE);
103         mMultiDisplay = new MultiDisplay[MAX_DISPLAYS + 1];
104         for (int i = 0; i < MAX_DISPLAYS + 1; i++) {
105             mMultiDisplay[i] = new MultiDisplay();
106         }
107     }
108 
109     @Override
onBind(Intent intent)110     public IBinder onBind(Intent intent) {
111         if(mMessenger == null)
112             mMessenger = new Messenger(mHandler);
113         return mMessenger.getBinder();
114     }
115 
116     @Override
onStartCommand(Intent intent, int flags, int startId)117     public int onStartCommand(Intent intent, int flags, int startId) {
118         // keep it alive.
119         return START_STICKY;
120     }
121 
122     class ListenerThread extends Thread {
ListenerThread()123         ListenerThread() {
124             super(TAG);
125         }
126 
deleteVirtualDisplay(int displayId)127         private void deleteVirtualDisplay(int displayId) {
128             if (!mMultiDisplay[displayId].enabled) {
129                 return;
130             }
131             if (mMultiDisplay[displayId].virtualDisplay != null) {
132                 mMultiDisplay[displayId].virtualDisplay.release();
133             }
134             if (mMultiDisplay[displayId].surface != null) {
135                 mMultiDisplay[displayId].surface.release();
136             }
137             mMultiDisplay[displayId].clear();
138             nativeReleaseListener(displayId);
139         }
140 
createVirtualDisplay(int displayId, int w, int h, int dpi, int flag)141         private void createVirtualDisplay(int displayId, int w, int h, int dpi, int flag) {
142             mMultiDisplay[displayId].surface = nativeCreateSurface(displayId, w, h);
143             mMultiDisplay[displayId].virtualDisplay = mDisplayManager.createVirtualDisplay(
144                                               null /* projection */,
145                                               DISPLAY_NAME, w, h, dpi,
146                                               mMultiDisplay[displayId].surface, flag,
147                                               null /* callback */,
148                                               null /* handler */,
149                                               UNIQUE_DISPLAY_ID[displayId]);
150             mMultiDisplay[displayId].set(w, h, dpi, flag);
151         }
152 
addVirtualDisplay(int displayId, int w, int h, int dpi, int flag)153         private void addVirtualDisplay(int displayId, int w, int h, int dpi, int flag) {
154             if (mMultiDisplay[displayId].match(w, h, dpi, flag)) {
155                 return;
156             }
157             if (mMultiDisplay[displayId].virtualDisplay == null) {
158                 createVirtualDisplay(displayId, w, h, dpi, flag);
159                 return;
160             }
161             if (mMultiDisplay[displayId].flag != flag) {
162                 deleteVirtualDisplay(displayId);
163                 createVirtualDisplay(displayId, w, h, dpi, flag);
164                 return;
165             }
166             if (mMultiDisplay[displayId].width != w || mMultiDisplay[displayId].height != h) {
167                 nativeResizeListener(displayId, w, h);
168             }
169             // only dpi changes
170             mMultiDisplay[displayId].virtualDisplay.resize(w, h, dpi);
171             mMultiDisplay[displayId].set(w, h, dpi, flag);
172         }
173 
174         @Override
run()175         public void run() {
176             while(nativeOpen() <= 0) {
177                 Log.e(TAG, "failed to open multiDisplay pipe, retry");
178             }
179             while(true) {
180                 int[] array = {0, 0, 0, 0, 0, 0};
181                 if (!nativeReadPipe(array)) {
182                     continue;
183                 }
184                 switch (array[0]) {
185                     case ADD: {
186                         for (int j = 0; j < 6; j++) {
187                             Log.d(TAG, "received " + array[j]);
188                         }
189                         int i = array[1];
190                         int width = array[2];
191                         int height = array[3];
192                         int dpi = array[4];
193                         int flag = (array[5] != 0) ? array[5] : mFlags;
194                         if (i < 1 || i > MAX_DISPLAYS || width <=0 || height <=0 || dpi <=0
195                             || flag < 0) {
196                             Log.e(TAG, "invalid parameters for add/modify display");
197                             break;
198                         }
199                         addVirtualDisplay(i, width, height, dpi, flag);
200                         break;
201                     }
202                     case DEL: {
203                         int i = array[1];
204                         Log.d(TAG, "DEL " + i);
205                         if (i < 1 || i > MAX_DISPLAYS) {
206                             Log.e(TAG, "invalid parameters for delete display");
207                             break;
208                         }
209                         deleteVirtualDisplay(i);
210                         break;
211                     }
212                 }
213             }
214         }
215     }
216 
nativeOpen()217     private native int nativeOpen();
nativeCreateSurface(int displayId, int width, int height)218     private native Surface nativeCreateSurface(int displayId, int width, int height);
nativeReadPipe(int[] arr)219     private native boolean nativeReadPipe(int[] arr);
nativeReleaseListener(int displayId)220     private native boolean nativeReleaseListener(int displayId);
nativeResizeListener(int displayId, int with, int height)221     private native boolean nativeResizeListener(int displayId, int with, int height);
222 }
223