blob: a18352ce931a1c644f21841c1c1ea51c0ee9e50f [file] [log] [blame]
Jeff Brownbd6e1502012-08-28 03:27:37 -07001/*
2 * Copyright (C) 2012 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
17package com.android.server.display;
18
Jeff Browncbad9762012-09-04 21:57:59 -070019import com.android.internal.util.DumpUtils;
20import com.android.internal.util.IndentingPrintWriter;
21
Jeff Brownbd6e1502012-08-28 03:27:37 -070022import android.content.Context;
23import android.database.ContentObserver;
Craig Mautnerd5523dc2012-10-02 13:49:22 -070024import android.graphics.SurfaceTexture;
Jeff Brown4ed8fe72012-08-30 18:18:29 -070025import android.os.Handler;
Jeff Brownbd6e1502012-08-28 03:27:37 -070026import android.os.IBinder;
27import android.provider.Settings;
28import android.util.DisplayMetrics;
29import android.util.Slog;
Jeff Brown92130f62012-10-24 21:28:33 -070030import android.view.Display;
Jeff Brownbd6e1502012-08-28 03:27:37 -070031import android.view.Gravity;
Jeff Brownbd6e1502012-08-28 03:27:37 -070032import android.view.Surface;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080033import android.view.SurfaceControl;
Jeff Brownbd6e1502012-08-28 03:27:37 -070034
35import java.io.PrintWriter;
36import java.util.ArrayList;
37import java.util.regex.Matcher;
38import java.util.regex.Pattern;
39
40/**
41 * A display adapter that uses overlay windows to simulate secondary displays
42 * for development purposes. Use Development Settings to enable one or more
43 * overlay displays.
44 * <p>
Jeff Brown4ed8fe72012-08-30 18:18:29 -070045 * This object has two different handlers (which may be the same) which must not
46 * get confused. The main handler is used to posting messages to the display manager
47 * service as usual. The UI handler is only used by the {@link OverlayDisplayWindow}.
48 * </p><p>
49 * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
Jeff Brownbd6e1502012-08-28 03:27:37 -070050 * </p>
51 */
Jeff Brown4ed8fe72012-08-30 18:18:29 -070052final class OverlayDisplayAdapter extends DisplayAdapter {
53 static final String TAG = "OverlayDisplayAdapter";
54 static final boolean DEBUG = false;
Jeff Brownbd6e1502012-08-28 03:27:37 -070055
56 private static final int MIN_WIDTH = 100;
57 private static final int MIN_HEIGHT = 100;
58 private static final int MAX_WIDTH = 4096;
59 private static final int MAX_HEIGHT = 4096;
60
61 private static final Pattern SETTING_PATTERN =
62 Pattern.compile("(\\d+)x(\\d+)/(\\d+)");
63
Jeff Brown4ed8fe72012-08-30 18:18:29 -070064 private final Handler mUiHandler;
65 private final ArrayList<OverlayDisplayHandle> mOverlays =
66 new ArrayList<OverlayDisplayHandle>();
Jeff Brownbd6e1502012-08-28 03:27:37 -070067 private String mCurrentOverlaySetting = "";
68
Jeff Brown66692502012-10-18 16:13:44 -070069 // Called with SyncRoot lock held.
Jeff Brown4ed8fe72012-08-30 18:18:29 -070070 public OverlayDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
71 Context context, Handler handler, Listener listener, Handler uiHandler) {
72 super(syncRoot, context, handler, listener, TAG);
73 mUiHandler = uiHandler;
Jeff Brownbd6e1502012-08-28 03:27:37 -070074 }
75
76 @Override
Jeff Brown4ed8fe72012-08-30 18:18:29 -070077 public void dumpLocked(PrintWriter pw) {
78 super.dumpLocked(pw);
Jeff Browncbad9762012-09-04 21:57:59 -070079
Jeff Brownbd6e1502012-08-28 03:27:37 -070080 pw.println("mCurrentOverlaySetting=" + mCurrentOverlaySetting);
81 pw.println("mOverlays: size=" + mOverlays.size());
Jeff Brown4ed8fe72012-08-30 18:18:29 -070082 for (OverlayDisplayHandle overlay : mOverlays) {
83 overlay.dumpLocked(pw);
Jeff Brownbd6e1502012-08-28 03:27:37 -070084 }
85 }
86
87 @Override
Jeff Brown4ed8fe72012-08-30 18:18:29 -070088 public void registerLocked() {
89 super.registerLocked();
Jeff Browncbad9762012-09-04 21:57:59 -070090
91 getHandler().post(new Runnable() {
92 @Override
93 public void run() {
94 getContext().getContentResolver().registerContentObserver(
Jeff Brownd4935962012-09-25 13:27:20 -070095 Settings.Global.getUriFor(Settings.Global.OVERLAY_DISPLAY_DEVICES),
96 true, new ContentObserver(getHandler()) {
97 @Override
98 public void onChange(boolean selfChange) {
99 updateOverlayDisplayDevices();
100 }
101 });
Jeff Browncbad9762012-09-04 21:57:59 -0700102
Jeff Brownd4935962012-09-25 13:27:20 -0700103 updateOverlayDisplayDevices();
Jeff Browncbad9762012-09-04 21:57:59 -0700104 }
105 });
Jeff Brownbd6e1502012-08-28 03:27:37 -0700106 }
107
Jeff Brownd4935962012-09-25 13:27:20 -0700108 private void updateOverlayDisplayDevices() {
109 synchronized (getSyncRoot()) {
110 updateOverlayDisplayDevicesLocked();
111 }
112 }
113
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700114 private void updateOverlayDisplayDevicesLocked() {
Jeff Brownd4935962012-09-25 13:27:20 -0700115 String value = Settings.Global.getString(getContext().getContentResolver(),
116 Settings.Global.OVERLAY_DISPLAY_DEVICES);
Jeff Brownbd6e1502012-08-28 03:27:37 -0700117 if (value == null) {
118 value = "";
119 }
120
121 if (value.equals(mCurrentOverlaySetting)) {
122 return;
123 }
124 mCurrentOverlaySetting = value;
125
126 if (!mOverlays.isEmpty()) {
127 Slog.i(TAG, "Dismissing all overlay display devices.");
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700128 for (OverlayDisplayHandle overlay : mOverlays) {
129 overlay.dismissLocked();
Jeff Brownbd6e1502012-08-28 03:27:37 -0700130 }
131 mOverlays.clear();
132 }
133
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700134 int count = 0;
Jeff Brownbd6e1502012-08-28 03:27:37 -0700135 for (String part : value.split(";")) {
Jeff Brownbd6e1502012-08-28 03:27:37 -0700136 Matcher matcher = SETTING_PATTERN.matcher(part);
137 if (matcher.matches()) {
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700138 if (count >= 4) {
139 Slog.w(TAG, "Too many overlay display devices specified: " + value);
140 break;
141 }
Jeff Brownbd6e1502012-08-28 03:27:37 -0700142 try {
143 int width = Integer.parseInt(matcher.group(1), 10);
144 int height = Integer.parseInt(matcher.group(2), 10);
145 int densityDpi = Integer.parseInt(matcher.group(3), 10);
146 if (width >= MIN_WIDTH && width <= MAX_WIDTH
147 && height >= MIN_HEIGHT && height <= MAX_HEIGHT
148 && densityDpi >= DisplayMetrics.DENSITY_LOW
149 && densityDpi <= DisplayMetrics.DENSITY_XXHIGH) {
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700150 int number = ++count;
151 String name = getContext().getResources().getString(
152 com.android.internal.R.string.display_manager_overlay_display_name,
153 number);
154 int gravity = chooseOverlayGravity(number);
155
Jeff Brownbd6e1502012-08-28 03:27:37 -0700156 Slog.i(TAG, "Showing overlay display device #" + number
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700157 + ": name=" + name + ", width=" + width + ", height=" + height
Jeff Brownbd6e1502012-08-28 03:27:37 -0700158 + ", densityDpi=" + densityDpi);
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700159
160 mOverlays.add(new OverlayDisplayHandle(name,
161 width, height, densityDpi, gravity));
Jeff Brownbd6e1502012-08-28 03:27:37 -0700162 continue;
163 }
164 } catch (NumberFormatException ex) {
165 }
166 } else if (part.isEmpty()) {
167 continue;
168 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700169 Slog.w(TAG, "Malformed overlay display devices setting: " + value);
Jeff Brownbd6e1502012-08-28 03:27:37 -0700170 }
171 }
172
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700173 private static int chooseOverlayGravity(int overlayNumber) {
174 switch (overlayNumber) {
175 case 1:
176 return Gravity.TOP | Gravity.LEFT;
177 case 2:
178 return Gravity.BOTTOM | Gravity.RIGHT;
179 case 3:
180 return Gravity.TOP | Gravity.RIGHT;
181 case 4:
182 default:
183 return Gravity.BOTTOM | Gravity.LEFT;
Jeff Brownbd6e1502012-08-28 03:27:37 -0700184 }
Jeff Brownbd6e1502012-08-28 03:27:37 -0700185 }
186
187 private final class OverlayDisplayDevice extends DisplayDevice {
188 private final String mName;
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700189 private final int mWidth;
190 private final int mHeight;
Jeff Brownbd6e1502012-08-28 03:27:37 -0700191 private final float mRefreshRate;
192 private final int mDensityDpi;
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700193
Jeff Browncbad9762012-09-04 21:57:59 -0700194 private Surface mSurface;
Craig Mautnerd5523dc2012-10-02 13:49:22 -0700195 private SurfaceTexture mSurfaceTexture;
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700196 private DisplayDeviceInfo mInfo;
Jeff Brownbd6e1502012-08-28 03:27:37 -0700197
198 public OverlayDisplayDevice(IBinder displayToken, String name,
Jeff Browncbad9762012-09-04 21:57:59 -0700199 int width, int height, float refreshRate, int densityDpi,
Craig Mautnerd5523dc2012-10-02 13:49:22 -0700200 SurfaceTexture surfaceTexture) {
Jeff Brownbd6e1502012-08-28 03:27:37 -0700201 super(OverlayDisplayAdapter.this, displayToken);
202 mName = name;
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700203 mWidth = width;
204 mHeight = height;
Jeff Brownbd6e1502012-08-28 03:27:37 -0700205 mRefreshRate = refreshRate;
206 mDensityDpi = densityDpi;
Craig Mautnerd5523dc2012-10-02 13:49:22 -0700207 mSurfaceTexture = surfaceTexture;
Jeff Brownbd6e1502012-08-28 03:27:37 -0700208 }
209
Craig Mautnerd5523dc2012-10-02 13:49:22 -0700210 public void clearSurfaceTextureLocked() {
211 if (mSurfaceTexture != null) {
212 mSurfaceTexture = null;
213 }
Jeff Browncbad9762012-09-04 21:57:59 -0700214 sendTraversalRequestLocked();
Jeff Brownbd6e1502012-08-28 03:27:37 -0700215 }
216
217 @Override
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700218 public void performTraversalInTransactionLocked() {
Craig Mautnerd5523dc2012-10-02 13:49:22 -0700219 if (mSurfaceTexture != null) {
220 if (mSurface == null) {
221 mSurface = new Surface(mSurfaceTexture);
222 }
223 setSurfaceInTransactionLocked(mSurface);
224 } else {
225 setSurfaceInTransactionLocked(null);
226 if (mSurface != null) {
227 mSurface.destroy();
228 mSurface = null;
229 }
230 }
Jeff Brownbd6e1502012-08-28 03:27:37 -0700231 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700232
233 @Override
234 public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
235 if (mInfo == null) {
236 mInfo = new DisplayDeviceInfo();
237 mInfo.name = mName;
238 mInfo.width = mWidth;
239 mInfo.height = mHeight;
240 mInfo.refreshRate = mRefreshRate;
241 mInfo.densityDpi = mDensityDpi;
242 mInfo.xDpi = mDensityDpi;
243 mInfo.yDpi = mDensityDpi;
Jeff Brown77aebfd2012-10-01 21:07:03 -0700244 mInfo.flags = 0;
Jeff Brown92130f62012-10-24 21:28:33 -0700245 mInfo.type = Display.TYPE_OVERLAY;
Jeff Brownd728bf52012-09-08 18:05:28 -0700246 mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700247 }
248 return mInfo;
249 }
250 }
251
252 /**
253 * Functions as a handle for overlay display devices which are created and
254 * destroyed asynchronously.
255 *
256 * Guarded by the {@link DisplayManagerService.SyncRoot} lock.
257 */
258 private final class OverlayDisplayHandle implements OverlayDisplayWindow.Listener {
259 private final String mName;
260 private final int mWidth;
261 private final int mHeight;
262 private final int mDensityDpi;
263 private final int mGravity;
264
265 private OverlayDisplayWindow mWindow;
266 private OverlayDisplayDevice mDevice;
267
268 public OverlayDisplayHandle(String name,
269 int width, int height, int densityDpi, int gravity) {
270 mName = name;
271 mWidth = width;
272 mHeight = height;
273 mDensityDpi = densityDpi;
274 mGravity = gravity;
275
276 mUiHandler.post(mShowRunnable);
277 }
278
279 public void dismissLocked() {
280 mUiHandler.removeCallbacks(mShowRunnable);
281 mUiHandler.post(mDismissRunnable);
282 }
283
284 // Called on the UI thread.
285 @Override
Craig Mautnerd5523dc2012-10-02 13:49:22 -0700286 public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) {
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700287 synchronized (getSyncRoot()) {
Mathias Agopian3866f0d2013-02-11 22:08:48 -0800288 IBinder displayToken = SurfaceControl.createDisplay(mName, false);
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700289 mDevice = new OverlayDisplayDevice(displayToken, mName,
Craig Mautnerd5523dc2012-10-02 13:49:22 -0700290 mWidth, mHeight, refreshRate, mDensityDpi, surfaceTexture);
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700291
292 sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
293 }
294 }
295
296 // Called on the UI thread.
297 @Override
298 public void onWindowDestroyed() {
299 synchronized (getSyncRoot()) {
300 if (mDevice != null) {
Craig Mautnerd5523dc2012-10-02 13:49:22 -0700301 mDevice.clearSurfaceTextureLocked();
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700302 sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
303 }
304 }
305 }
306
307 public void dumpLocked(PrintWriter pw) {
Jeff Browncbad9762012-09-04 21:57:59 -0700308 pw.println(" " + mName + ":");
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700309 pw.println(" mWidth=" + mWidth);
310 pw.println(" mHeight=" + mHeight);
311 pw.println(" mDensityDpi=" + mDensityDpi);
312 pw.println(" mGravity=" + mGravity);
313
314 // Try to dump the window state.
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700315 if (mWindow != null) {
Jeff Browncbad9762012-09-04 21:57:59 -0700316 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
317 ipw.increaseIndent();
318 DumpUtils.dumpAsync(mUiHandler, mWindow, ipw, 200);
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700319 }
320 }
321
322 // Runs on the UI thread.
323 private final Runnable mShowRunnable = new Runnable() {
324 @Override
325 public void run() {
326 OverlayDisplayWindow window = new OverlayDisplayWindow(getContext(),
327 mName, mWidth, mHeight, mDensityDpi, mGravity,
328 OverlayDisplayHandle.this);
329 window.show();
330
331 synchronized (getSyncRoot()) {
332 mWindow = window;
333 }
334 }
335 };
336
337 // Runs on the UI thread.
338 private final Runnable mDismissRunnable = new Runnable() {
339 @Override
340 public void run() {
341 OverlayDisplayWindow window;
342 synchronized (getSyncRoot()) {
343 window = mWindow;
344 mWindow = null;
345 }
346
347 if (window != null) {
348 window.dismiss();
349 }
350 }
351 };
Jeff Brownbd6e1502012-08-28 03:27:37 -0700352 }
353}