1 /* 2 * Copyright (C) 2020 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.annotation.NonNull; 20 import android.os.Trace; 21 import android.util.Slog; 22 import android.view.Display; 23 import android.view.DisplayAddress; 24 25 import com.android.internal.annotations.GuardedBy; 26 import com.android.server.display.DisplayManagerService.SyncRoot; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.function.Consumer; 31 32 /** 33 * Container for all the display devices present in the system. If an object wants to get events 34 * about all the DisplayDevices without needing to listen to all of the DisplayAdapters, they can 35 * listen and interact with the instance of this class. 36 * <p> 37 * The collection of {@link DisplayDevice}s and their usage is protected by the provided 38 * {@link DisplayManagerService.SyncRoot} lock object. 39 */ 40 class DisplayDeviceRepository implements DisplayAdapter.Listener { 41 private static final String TAG = "DisplayDeviceRepository"; 42 private static final Boolean DEBUG = false; 43 44 public static final int DISPLAY_DEVICE_EVENT_ADDED = 1; 45 public static final int DISPLAY_DEVICE_EVENT_CHANGED = 2; 46 public static final int DISPLAY_DEVICE_EVENT_REMOVED = 3; 47 48 /** 49 * List of all currently connected display devices. Indexed by the displayId. 50 * TODO: multi-display - break the notion that this is indexed by displayId. 51 */ 52 @GuardedBy("mSyncRoot") 53 private final List<DisplayDevice> mDisplayDevices = new ArrayList<>(); 54 55 /** Listeners for {link DisplayDevice} events. */ 56 @GuardedBy("mSyncRoot") 57 private final List<Listener> mListeners = new ArrayList<>(); 58 59 /** Global lock object from {@link DisplayManagerService}. */ 60 private final SyncRoot mSyncRoot; 61 62 private final PersistentDataStore mPersistentDataStore; 63 64 /** 65 * @param syncRoot The global lock for DisplayManager related objects. 66 * @param persistentDataStore Settings data store from {@link DisplayManagerService}. 67 */ DisplayDeviceRepository(@onNull SyncRoot syncRoot, @NonNull PersistentDataStore persistentDataStore)68 DisplayDeviceRepository(@NonNull SyncRoot syncRoot, 69 @NonNull PersistentDataStore persistentDataStore) { 70 mSyncRoot = syncRoot; 71 mPersistentDataStore = persistentDataStore; 72 } 73 addListener(@onNull Listener listener)74 public void addListener(@NonNull Listener listener) { 75 mListeners.add(listener); 76 } 77 78 @Override onDisplayDeviceEvent(DisplayDevice device, int event)79 public void onDisplayDeviceEvent(DisplayDevice device, int event) { 80 String tag = null; 81 if (DEBUG) { 82 tag = "DisplayDeviceRepository#onDisplayDeviceEvent (event=" + event + ")"; 83 Trace.beginAsyncSection(tag, 0); 84 } 85 switch (event) { 86 case DISPLAY_DEVICE_EVENT_ADDED: 87 handleDisplayDeviceAdded(device); 88 break; 89 90 case DISPLAY_DEVICE_EVENT_CHANGED: 91 handleDisplayDeviceChanged(device); 92 break; 93 94 case DISPLAY_DEVICE_EVENT_REMOVED: 95 handleDisplayDeviceRemoved(device); 96 break; 97 } 98 if (DEBUG) { 99 Trace.endAsyncSection(tag, 0); 100 } 101 } 102 103 @Override onTraversalRequested()104 public void onTraversalRequested() { 105 final int size = mListeners.size(); 106 for (int i = 0; i < size; i++) { 107 mListeners.get(i).onTraversalRequested(); 108 } 109 } 110 containsLocked(DisplayDevice d)111 public boolean containsLocked(DisplayDevice d) { 112 return mDisplayDevices.contains(d); 113 } 114 sizeLocked()115 public int sizeLocked() { 116 return mDisplayDevices.size(); 117 } 118 forEachLocked(Consumer<DisplayDevice> consumer)119 public void forEachLocked(Consumer<DisplayDevice> consumer) { 120 final int count = mDisplayDevices.size(); 121 for (int i = 0; i < count; i++) { 122 consumer.accept(mDisplayDevices.get(i)); 123 } 124 } 125 getByAddressLocked(@onNull DisplayAddress address)126 public DisplayDevice getByAddressLocked(@NonNull DisplayAddress address) { 127 for (int i = mDisplayDevices.size() - 1; i >= 0; i--) { 128 final DisplayDevice device = mDisplayDevices.get(i); 129 if (address.equals(device.getDisplayDeviceInfoLocked().address)) { 130 return device; 131 } 132 } 133 return null; 134 } 135 136 // String uniqueId -> DisplayDevice object with that given uniqueId getByUniqueIdLocked(@onNull String uniqueId)137 public DisplayDevice getByUniqueIdLocked(@NonNull String uniqueId) { 138 for (int i = mDisplayDevices.size() - 1; i >= 0; i--) { 139 final DisplayDevice displayDevice = mDisplayDevices.get(i); 140 if (displayDevice.getUniqueId().equals(uniqueId)) { 141 return displayDevice; 142 } 143 } 144 return null; 145 } 146 handleDisplayDeviceAdded(DisplayDevice device)147 private void handleDisplayDeviceAdded(DisplayDevice device) { 148 synchronized (mSyncRoot) { 149 DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 150 if (mDisplayDevices.contains(device)) { 151 Slog.w(TAG, "Attempted to add already added display device: " + info); 152 return; 153 } 154 Slog.i(TAG, "Display device added: " + info); 155 device.mDebugLastLoggedDeviceInfo = info; 156 157 mDisplayDevices.add(device); 158 sendEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); 159 } 160 } 161 handleDisplayDeviceChanged(DisplayDevice device)162 private void handleDisplayDeviceChanged(DisplayDevice device) { 163 synchronized (mSyncRoot) { 164 final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 165 if (!mDisplayDevices.contains(device)) { 166 Slog.w(TAG, "Attempted to change non-existent display device: " + info); 167 return; 168 } 169 if (DEBUG) { 170 Trace.beginSection("handleDisplayDeviceChanged"); 171 } 172 int diff = device.mDebugLastLoggedDeviceInfo.diff(info); 173 if (diff == DisplayDeviceInfo.DIFF_STATE) { 174 Slog.i(TAG, "Display device changed state: \"" + info.name 175 + "\", " + Display.stateToString(info.state)); 176 } else if (diff != 0) { 177 Slog.i(TAG, "Display device changed: " + info); 178 } 179 180 if ((diff & DisplayDeviceInfo.DIFF_COLOR_MODE) != 0) { 181 try { 182 mPersistentDataStore.setColorMode(device, info.colorMode); 183 } finally { 184 mPersistentDataStore.saveIfNeeded(); 185 } 186 } 187 device.mDebugLastLoggedDeviceInfo = info; 188 189 device.applyPendingDisplayDeviceInfoChangesLocked(); 190 sendEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED); 191 if (DEBUG) { 192 Trace.endSection(); 193 } 194 } 195 } 196 handleDisplayDeviceRemoved(DisplayDevice device)197 private void handleDisplayDeviceRemoved(DisplayDevice device) { 198 synchronized (mSyncRoot) { 199 DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); 200 if (!mDisplayDevices.remove(device)) { 201 Slog.w(TAG, "Attempted to remove non-existent display device: " + info); 202 return; 203 } 204 205 Slog.i(TAG, "Display device removed: " + info); 206 device.mDebugLastLoggedDeviceInfo = info; 207 sendEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED); 208 } 209 } 210 sendEventLocked(DisplayDevice device, int event)211 private void sendEventLocked(DisplayDevice device, int event) { 212 final int size = mListeners.size(); 213 for (int i = 0; i < size; i++) { 214 mListeners.get(i).onDisplayDeviceEventLocked(device, event); 215 } 216 } 217 218 /** 219 * Listens to {@link DisplayDevice} events from {@link DisplayDeviceRepository}. 220 */ 221 public interface Listener { onDisplayDeviceEventLocked(DisplayDevice device, int event)222 void onDisplayDeviceEventLocked(DisplayDevice device, int event); 223 224 // TODO: multi-display - Try to remove the need for requestTraversal...it feels like 225 // a shoe-horned method for a shoe-horned feature. onTraversalRequested()226 void onTraversalRequested(); 227 }; 228 } 229