• 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 android.car.cluster;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.hardware.display.DisplayManager;
22 import android.hardware.display.DisplayManager.DisplayListener;
23 import android.os.SystemProperties;
24 import android.text.TextUtils;
25 import android.util.Log;
26 import android.view.Display;
27 import android.view.DisplayAddress;
28 
29 /**
30  * This class provides a display for instrument cluster renderer.
31  * <p>
32  * By default it will try to provide physical secondary display if it is connected, if secondary
33  * display is not connected during creation of this class then it will start networked virtual
34  * display and listens for incoming connections.
35  *
36  * @see {@link NetworkedVirtualDisplay}
37  */
38 public class ClusterDisplayProvider {
39     private static final String TAG = "Cluster.DisplayProvider";
40 
41     private static final String RO_CLUSTER_DISPLAY_PORT = "ro.car.cluster.displayport";
42     private static final String PERSIST_CLUSTER_DISPLAY_PORT =
43             "persist.car.cluster.displayport";
44     private static final int NETWORKED_DISPLAY_WIDTH = 1280;
45     private static final int NETWORKED_DISPLAY_HEIGHT = 720;
46     private static final int NETWORKED_DISPLAY_DPI = 320;
47 
48     private final DisplayListener mListener;
49     private final DisplayManager mDisplayManager;
50 
51     private NetworkedVirtualDisplay mNetworkedVirtualDisplay;
52     private int mClusterDisplayId = -1;
53 
ClusterDisplayProvider(Context context, DisplayListener clusterDisplayListener)54     ClusterDisplayProvider(Context context, DisplayListener clusterDisplayListener) {
55         mListener = clusterDisplayListener;
56         mDisplayManager = context.getSystemService(DisplayManager.class);
57 
58         Display clusterDisplay = getInstrumentClusterDisplay(mDisplayManager);
59         if (clusterDisplay != null) {
60             Log.i(TAG, String.format("Found display: %s (id: %d, owner: %s)",
61                     clusterDisplay.getName(), clusterDisplay.getDisplayId(),
62                     clusterDisplay.getOwnerPackageName()));
63             mClusterDisplayId = clusterDisplay.getDisplayId();
64             clusterDisplayListener.onDisplayAdded(clusterDisplay.getDisplayId());
65             trackClusterDisplay(null /* no need to track display by name */);
66         } else {
67             Log.i(TAG, "No physical cluster display found, starting network display");
68             setupNetworkDisplay(context);
69         }
70     }
71 
setupNetworkDisplay(Context context)72     private void setupNetworkDisplay(Context context) {
73         mNetworkedVirtualDisplay = new NetworkedVirtualDisplay(context,
74                 NETWORKED_DISPLAY_WIDTH, NETWORKED_DISPLAY_HEIGHT, NETWORKED_DISPLAY_DPI);
75         String displayName = mNetworkedVirtualDisplay.start();
76         trackClusterDisplay(displayName);
77     }
78 
trackClusterDisplay(@ullable String displayName)79     private void trackClusterDisplay(@Nullable String displayName) {
80         mDisplayManager.registerDisplayListener(new DisplayListener() {
81             @Override
82             public void onDisplayAdded(int displayId) {
83                 boolean clusterDisplayAdded = false;
84 
85                 if (displayName == null && mClusterDisplayId == -1) {
86                     mClusterDisplayId = displayId;
87                     clusterDisplayAdded = true;
88                 } else {
89                     Display display = mDisplayManager.getDisplay(displayId);
90                     if (display != null && TextUtils.equals(display.getName(), displayName)) {
91                         mClusterDisplayId = displayId;
92                         clusterDisplayAdded = true;
93                     }
94                 }
95 
96                 if (clusterDisplayAdded) {
97                     mListener.onDisplayAdded(displayId);
98                 }
99             }
100 
101             @Override
102             public void onDisplayRemoved(int displayId) {
103                 if (displayId == mClusterDisplayId) {
104                     mClusterDisplayId = -1;
105                     mListener.onDisplayRemoved(displayId);
106                 }
107             }
108 
109             @Override
110             public void onDisplayChanged(int displayId) {
111                 if (displayId == mClusterDisplayId) {
112                     mListener.onDisplayChanged(displayId);
113                 }
114             }
115 
116         }, null);
117     }
118 
getInstrumentClusterDisplay(DisplayManager displayManager)119     private static Display getInstrumentClusterDisplay(DisplayManager displayManager) {
120         Display[] displays = displayManager.getDisplays();
121         Log.d(TAG, "There are currently " + displays.length + " displays connected.");
122 
123         final int displayPortPrimary = 0;  // primary port should not be instrument cluster.
124         int displayPort = SystemProperties.getInt(PERSIST_CLUSTER_DISPLAY_PORT,
125                 displayPortPrimary);
126         if (displayPort == displayPortPrimary) {
127             displayPort = SystemProperties.getInt(RO_CLUSTER_DISPLAY_PORT,
128                     displayPortPrimary);
129             if (displayPort == displayPortPrimary) {
130                 return null;
131             }
132         }
133         // match port for system display ( = null getOwnerPackageName())
134         // with separate check for main display as main display should be never picked up.
135         for (Display display : displays) {
136             if (display.getDisplayId() != Display.DEFAULT_DISPLAY
137                     && display.getOwnerPackageName() == null
138                     && display.getAddress() != null
139                     && display.getAddress() instanceof DisplayAddress.Physical) {
140                 final byte port = ((DisplayAddress.Physical) display.getAddress()).getPort();
141                 if (displayPort == port) {
142                     return display;
143                 }
144             }
145         }
146         return null;
147     }
148 
149     @Override
toString()150     public String toString() {
151         return getClass().getSimpleName() + "{"
152                 + " clusterDisplayId = " + mClusterDisplayId
153                 + "}";
154     }
155 }
156