Home | History | Annotate | Download | only in display
      1 /*
      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 
     17 package com.android.server.display;
     18 
     19 import android.content.Context;
     20 import android.os.Handler;
     21 import android.os.IBinder;
     22 import android.os.Looper;
     23 import android.os.SystemProperties;
     24 import android.util.SparseArray;
     25 import android.view.Display;
     26 import android.view.DisplayEventReceiver;
     27 import android.view.Surface;
     28 import android.view.Surface.PhysicalDisplayInfo;
     29 
     30 import java.io.PrintWriter;
     31 
     32 /**
     33  * A display adapter for the local displays managed by Surface Flinger.
     34  * <p>
     35  * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
     36  * </p>
     37  */
     38 final class LocalDisplayAdapter extends DisplayAdapter {
     39     private static final String TAG = "LocalDisplayAdapter";
     40 
     41     private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
     42             Surface.BUILT_IN_DISPLAY_ID_MAIN,
     43             Surface.BUILT_IN_DISPLAY_ID_HDMI,
     44     };
     45 
     46     private final SparseArray<LocalDisplayDevice> mDevices =
     47             new SparseArray<LocalDisplayDevice>();
     48     private HotplugDisplayEventReceiver mHotplugReceiver;
     49 
     50     private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo();
     51 
     52     // Called with SyncRoot lock held.
     53     public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
     54             Context context, Handler handler, Listener listener) {
     55         super(syncRoot, context, handler, listener, TAG);
     56     }
     57 
     58     @Override
     59     public void registerLocked() {
     60         super.registerLocked();
     61 
     62         mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
     63         scanDisplaysLocked();
     64     }
     65 
     66     private void scanDisplaysLocked() {
     67         for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
     68             IBinder displayToken = Surface.getBuiltInDisplay(builtInDisplayId);
     69             if (displayToken != null && Surface.getDisplayInfo(displayToken, mTempPhys)) {
     70                 LocalDisplayDevice device = mDevices.get(builtInDisplayId);
     71                 if (device == null) {
     72                     // Display was added.
     73                     device = new LocalDisplayDevice(displayToken, builtInDisplayId, mTempPhys);
     74                     mDevices.put(builtInDisplayId, device);
     75                     sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
     76                 } else if (device.updatePhysicalDisplayInfoLocked(mTempPhys)) {
     77                     // Display properties changed.
     78                     sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
     79                 }
     80             } else {
     81                 LocalDisplayDevice device = mDevices.get(builtInDisplayId);
     82                 if (device != null) {
     83                     // Display was removed.
     84                     mDevices.remove(builtInDisplayId);
     85                     sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
     86                 }
     87             }
     88         }
     89     }
     90 
     91     private final class LocalDisplayDevice extends DisplayDevice {
     92         private final int mBuiltInDisplayId;
     93         private final PhysicalDisplayInfo mPhys;
     94 
     95         private DisplayDeviceInfo mInfo;
     96         private boolean mHavePendingChanges;
     97         private boolean mBlanked;
     98 
     99         public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
    100                 PhysicalDisplayInfo phys) {
    101             super(LocalDisplayAdapter.this, displayToken);
    102             mBuiltInDisplayId = builtInDisplayId;
    103             mPhys = new PhysicalDisplayInfo(phys);
    104         }
    105 
    106         public boolean updatePhysicalDisplayInfoLocked(PhysicalDisplayInfo phys) {
    107             if (!mPhys.equals(phys)) {
    108                 mPhys.copyFrom(phys);
    109                 mHavePendingChanges = true;
    110                 return true;
    111             }
    112             return false;
    113         }
    114 
    115         @Override
    116         public void applyPendingDisplayDeviceInfoChangesLocked() {
    117             if (mHavePendingChanges) {
    118                 mInfo = null;
    119                 mHavePendingChanges = false;
    120             }
    121         }
    122 
    123         @Override
    124         public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
    125             if (mInfo == null) {
    126                 mInfo = new DisplayDeviceInfo();
    127                 mInfo.width = mPhys.width;
    128                 mInfo.height = mPhys.height;
    129                 mInfo.refreshRate = mPhys.refreshRate;
    130 
    131                 // Assume that all built-in displays that have secure output (eg. HDCP) also
    132                 // support compositing from gralloc protected buffers.
    133                 if (mPhys.secure) {
    134                     mInfo.flags = DisplayDeviceInfo.FLAG_SECURE
    135                             | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
    136                 }
    137 
    138                 if (mBuiltInDisplayId == Surface.BUILT_IN_DISPLAY_ID_MAIN) {
    139                     mInfo.name = getContext().getResources().getString(
    140                             com.android.internal.R.string.display_manager_built_in_display_name);
    141                     mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
    142                             | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
    143                     mInfo.type = Display.TYPE_BUILT_IN;
    144                     mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
    145                     mInfo.xDpi = mPhys.xDpi;
    146                     mInfo.yDpi = mPhys.yDpi;
    147                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
    148                 } else {
    149                     mInfo.type = Display.TYPE_HDMI;
    150                     mInfo.name = getContext().getResources().getString(
    151                             com.android.internal.R.string.display_manager_hdmi_display_name);
    152                     mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
    153                     mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height);
    154 
    155                     // For demonstration purposes, allow rotation of the external display.
    156                     // In the future we might allow the user to configure this directly.
    157                     if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
    158                         mInfo.rotation = Surface.ROTATION_270;
    159                     }
    160                 }
    161             }
    162             return mInfo;
    163         }
    164 
    165         @Override
    166         public void blankLocked() {
    167             mBlanked = true;
    168             Surface.blankDisplay(getDisplayTokenLocked());
    169         }
    170 
    171         @Override
    172         public void unblankLocked() {
    173             mBlanked = false;
    174             Surface.unblankDisplay(getDisplayTokenLocked());
    175         }
    176 
    177         @Override
    178         public void dumpLocked(PrintWriter pw) {
    179             super.dumpLocked(pw);
    180             pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
    181             pw.println("mPhys=" + mPhys);
    182             pw.println("mBlanked=" + mBlanked);
    183         }
    184     }
    185 
    186     private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
    187         public HotplugDisplayEventReceiver(Looper looper) {
    188             super(looper);
    189         }
    190 
    191         @Override
    192         public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
    193             synchronized (getSyncRoot()) {
    194                 scanDisplaysLocked();
    195             }
    196         }
    197     }
    198 }