164a55af0ac700baecb0877235eb42caac59a3560Jeff Brown/*
264a55af0ac700baecb0877235eb42caac59a3560Jeff Brown * Copyright (C) 2012 The Android Open Source Project
364a55af0ac700baecb0877235eb42caac59a3560Jeff Brown *
464a55af0ac700baecb0877235eb42caac59a3560Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
564a55af0ac700baecb0877235eb42caac59a3560Jeff Brown * you may not use this file except in compliance with the License.
664a55af0ac700baecb0877235eb42caac59a3560Jeff Brown * You may obtain a copy of the License at
764a55af0ac700baecb0877235eb42caac59a3560Jeff Brown *
864a55af0ac700baecb0877235eb42caac59a3560Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
964a55af0ac700baecb0877235eb42caac59a3560Jeff Brown *
1064a55af0ac700baecb0877235eb42caac59a3560Jeff Brown * Unless required by applicable law or agreed to in writing, software
1164a55af0ac700baecb0877235eb42caac59a3560Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1264a55af0ac700baecb0877235eb42caac59a3560Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1364a55af0ac700baecb0877235eb42caac59a3560Jeff Brown * See the License for the specific language governing permissions and
1464a55af0ac700baecb0877235eb42caac59a3560Jeff Brown * limitations under the License.
1564a55af0ac700baecb0877235eb42caac59a3560Jeff Brown */
1664a55af0ac700baecb0877235eb42caac59a3560Jeff Brown
1764a55af0ac700baecb0877235eb42caac59a3560Jeff Brownpackage com.android.server.display;
1864a55af0ac700baecb0877235eb42caac59a3560Jeff Brown
1964a55af0ac700baecb0877235eb42caac59a3560Jeff Brownimport android.content.Context;
204ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brownimport android.os.Handler;
2164a55af0ac700baecb0877235eb42caac59a3560Jeff Brownimport android.os.IBinder;
22e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brownimport android.os.Looper;
2327f1d674bf9fb53af7facdcb746912e036d5bf75Jeff Brownimport android.os.SystemProperties;
244ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brownimport android.util.SparseArray;
2592130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brownimport android.view.Display;
26e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brownimport android.view.DisplayEventReceiver;
2764a55af0ac700baecb0877235eb42caac59a3560Jeff Brownimport android.view.Surface;
2864a55af0ac700baecb0877235eb42caac59a3560Jeff Brownimport android.view.Surface.PhysicalDisplayInfo;
2964a55af0ac700baecb0877235eb42caac59a3560Jeff Brown
304ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brownimport java.io.PrintWriter;
314ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
3264a55af0ac700baecb0877235eb42caac59a3560Jeff Brown/**
3364a55af0ac700baecb0877235eb42caac59a3560Jeff Brown * A display adapter for the local displays managed by Surface Flinger.
34bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * <p>
354ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
36bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown * </p>
3764a55af0ac700baecb0877235eb42caac59a3560Jeff Brown */
384ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brownfinal class LocalDisplayAdapter extends DisplayAdapter {
39bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown    private static final String TAG = "LocalDisplayAdapter";
4064a55af0ac700baecb0877235eb42caac59a3560Jeff Brown
414ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
424ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            Surface.BUILT_IN_DISPLAY_ID_MAIN,
434ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            Surface.BUILT_IN_DISPLAY_ID_HDMI,
444ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    };
454ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
464ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    private final SparseArray<LocalDisplayDevice> mDevices =
474ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            new SparseArray<LocalDisplayDevice>();
4866692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown    private HotplugDisplayEventReceiver mHotplugReceiver;
494ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
504ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo();
514ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
5266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown    // Called with SyncRoot lock held.
534ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
544ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            Context context, Handler handler, Listener listener) {
554ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        super(syncRoot, context, handler, listener, TAG);
5664a55af0ac700baecb0877235eb42caac59a3560Jeff Brown    }
5764a55af0ac700baecb0877235eb42caac59a3560Jeff Brown
5864a55af0ac700baecb0877235eb42caac59a3560Jeff Brown    @Override
594ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    public void registerLocked() {
604ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        super.registerLocked();
6166692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown
6266692500344cab2f53cdb6ee1545c567fff7cb16Jeff Brown        mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
634ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        scanDisplaysLocked();
644ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    }
654ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
664ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown    private void scanDisplaysLocked() {
674ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
684ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            IBinder displayToken = Surface.getBuiltInDisplay(builtInDisplayId);
694ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            if (displayToken != null && Surface.getDisplayInfo(displayToken, mTempPhys)) {
704ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                LocalDisplayDevice device = mDevices.get(builtInDisplayId);
714ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (device == null) {
724ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    // Display was added.
734ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    device = new LocalDisplayDevice(displayToken, builtInDisplayId, mTempPhys);
744ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDevices.put(builtInDisplayId, device);
754ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
764ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                } else if (device.updatePhysicalDisplayInfoLocked(mTempPhys)) {
774ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    // Display properties changed.
784ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
794ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
804ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            } else {
814ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                LocalDisplayDevice device = mDevices.get(builtInDisplayId);
824ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (device != null) {
834ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    // Display was removed.
844ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mDevices.remove(builtInDisplayId);
854ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
864ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
874ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            }
884ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        }
8964a55af0ac700baecb0877235eb42caac59a3560Jeff Brown    }
9064a55af0ac700baecb0877235eb42caac59a3560Jeff Brown
9164a55af0ac700baecb0877235eb42caac59a3560Jeff Brown    private final class LocalDisplayDevice extends DisplayDevice {
924ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        private final int mBuiltInDisplayId;
934ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        private final PhysicalDisplayInfo mPhys;
9464a55af0ac700baecb0877235eb42caac59a3560Jeff Brown
954ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        private DisplayDeviceInfo mInfo;
964ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        private boolean mHavePendingChanges;
979e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown        private boolean mBlanked;
984ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
994ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
1004ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                PhysicalDisplayInfo phys) {
101bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            super(LocalDisplayAdapter.this, displayToken);
1024ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            mBuiltInDisplayId = builtInDisplayId;
1034ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            mPhys = new PhysicalDisplayInfo(phys);
1044ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        }
1054ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
1064ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        public boolean updatePhysicalDisplayInfoLocked(PhysicalDisplayInfo phys) {
1074ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            if (!mPhys.equals(phys)) {
1084ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mPhys.copyFrom(phys);
1094ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mHavePendingChanges = true;
1104ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                return true;
1114ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            }
1124ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            return false;
11364a55af0ac700baecb0877235eb42caac59a3560Jeff Brown        }
11464a55af0ac700baecb0877235eb42caac59a3560Jeff Brown
11564a55af0ac700baecb0877235eb42caac59a3560Jeff Brown        @Override
1164ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        public void applyPendingDisplayDeviceInfoChangesLocked() {
1174ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            if (mHavePendingChanges) {
1184ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mInfo = null;
1194ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mHavePendingChanges = false;
120bd6e1500aedc5461e832f69e76341bff0e55fa2bJeff Brown            }
12164a55af0ac700baecb0877235eb42caac59a3560Jeff Brown        }
1224ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
1234ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        @Override
1244ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
1254ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            if (mInfo == null) {
1264ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mInfo = new DisplayDeviceInfo();
1274ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mInfo.width = mPhys.width;
1284ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mInfo.height = mPhys.height;
1294ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                mInfo.refreshRate = mPhys.refreshRate;
13077aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown
131f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown                // Assume that all built-in displays that have secure output (eg. HDCP) also
13277aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown                // support compositing from gralloc protected buffers.
133f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown                if (mPhys.secure) {
134f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown                    mInfo.flags = DisplayDeviceInfo.FLAG_SECURE
135f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown                            | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
136f0681b34dffc1510cbd9c3da5c3a7e695553fa8dJeff Brown                }
13777aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown
1384ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                if (mBuiltInDisplayId == Surface.BUILT_IN_DISPLAY_ID_MAIN) {
1394ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mInfo.name = getContext().getResources().getString(
1404ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                            com.android.internal.R.string.display_manager_built_in_display_name);
14177aebfdbae489c3712ae3f9bca29d01fb1f09dc2Jeff Brown                    mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
14227f1d674bf9fb53af7facdcb746912e036d5bf75Jeff Brown                            | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
14392130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                    mInfo.type = Display.TYPE_BUILT_IN;
144cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
145cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    mInfo.xDpi = mPhys.xDpi;
146cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    mInfo.yDpi = mPhys.yDpi;
147d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown                    mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
1484ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                } else {
14992130f6407dc51c58b3b941d28a6daf4e04b8d62Jeff Brown                    mInfo.type = Display.TYPE_HDMI;
1504ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                    mInfo.name = getContext().getResources().getString(
1514ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                            com.android.internal.R.string.display_manager_hdmi_display_name);
152d728bf514f257670fcb9aa22c6eaf97626072c93Jeff Brown                    mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
153cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                    mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height);
15427f1d674bf9fb53af7facdcb746912e036d5bf75Jeff Brown
15527f1d674bf9fb53af7facdcb746912e036d5bf75Jeff Brown                    // For demonstration purposes, allow rotation of the external display.
15627f1d674bf9fb53af7facdcb746912e036d5bf75Jeff Brown                    // In the future we might allow the user to configure this directly.
15727f1d674bf9fb53af7facdcb746912e036d5bf75Jeff Brown                    if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
15827f1d674bf9fb53af7facdcb746912e036d5bf75Jeff Brown                        mInfo.rotation = Surface.ROTATION_270;
15927f1d674bf9fb53af7facdcb746912e036d5bf75Jeff Brown                    }
1604ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown                }
1614ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            }
1624ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            return mInfo;
1634ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        }
1644ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown
1654ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        @Override
1669e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown        public void blankLocked() {
1679e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown            mBlanked = true;
1689e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown            Surface.blankDisplay(getDisplayTokenLocked());
1699e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown        }
1709e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown
1719e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown        @Override
1729e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown        public void unblankLocked() {
1739e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown            mBlanked = false;
1749e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown            Surface.unblankDisplay(getDisplayTokenLocked());
1759e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown        }
1769e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown
1779e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown        @Override
1784ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        public void dumpLocked(PrintWriter pw) {
1794ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            super.dumpLocked(pw);
1804ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
1814ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown            pw.println("mPhys=" + mPhys);
1829e316a1a2a8d734315bbd56a85308f9657a92913Jeff Brown            pw.println("mBlanked=" + mBlanked);
1834ed8fe75e1dde1a2b9576f3862aecc5a572c56b5Jeff Brown        }
18464a55af0ac700baecb0877235eb42caac59a3560Jeff Brown    }
185e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown
186e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
187e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown        public HotplugDisplayEventReceiver(Looper looper) {
188e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            super(looper);
189e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown        }
190e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown
191e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown        @Override
192e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown        public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
193e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            synchronized (getSyncRoot()) {
194e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown                scanDisplaysLocked();
195e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown            }
196e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown        }
197e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown    }
198e87bf030766198bf5e1fe846167dba766e27fb3fJeff Brown}