diff options
Diffstat (limited to 'src/com/android/launcher3/util/DisplayController.java')
-rw-r--r-- | src/com/android/launcher3/util/DisplayController.java | 161 |
1 files changed, 117 insertions, 44 deletions
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java index e2c0a32bb0..c050c6ca87 100644 --- a/src/com/android/launcher3/util/DisplayController.java +++ b/src/com/android/launcher3/util/DisplayController.java @@ -23,6 +23,8 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.WindowManagerCompat.MIN_TABLET_WIDTH; +import static java.util.Collections.emptyMap; + import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.ComponentCallbacks; @@ -34,10 +36,11 @@ import android.graphics.Point; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.os.Build; +import android.text.TextUtils; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.view.Display; -import android.view.WindowMetrics; import androidx.annotation.AnyThread; import androidx.annotation.UiThread; @@ -47,7 +50,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.uioverrides.ApiWrapper; import java.util.ArrayList; -import java.util.Collections; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -55,7 +58,7 @@ import java.util.Set; * Utility class to cache properties of default display to avoid a system RPC on every call. */ @SuppressLint("NewApi") -public class DisplayController implements DisplayListener, ComponentCallbacks { +public class DisplayController implements DisplayListener, ComponentCallbacks, SafeCloseable { private static final String TAG = "DisplayController"; @@ -76,9 +79,12 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { // Null for SDK < S private final Context mWindowContext; - + // The callback in this listener updates DeviceProfile, which other listeners might depend on + private DisplayInfoChangeListener mPriorityListener; private final ArrayList<DisplayInfoChangeListener> mListeners = new ArrayList<>(); + private Info mInfo; + private boolean mDestroyed = false; private DisplayController(Context context) { mContext = context; @@ -95,19 +101,35 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { mContext.registerReceiver(configChangeReceiver, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED)); } + mInfo = new Info(getDisplayInfoContext(display), display, + getInternalDisplays(mDM), emptyMap()); + mDM.registerDisplayListener(this, UI_HELPER_EXECUTOR.getHandler()); + } - // Create a single holder for all internal displays. External display holders created - // lazily. - Set<PortraitSize> extraInternalDisplays = new ArraySet<>(); - for (Display d : mDM.getDisplays()) { - if (ApiWrapper.isInternalDisplay(display) && d.getDisplayId() != DEFAULT_DISPLAY) { + private static ArrayMap<String, PortraitSize> getInternalDisplays( + DisplayManager displayManager) { + Display[] displays = displayManager.getDisplays(); + ArrayMap<String, PortraitSize> internalDisplays = new ArrayMap<>(); + for (Display display : displays) { + if (ApiWrapper.isInternalDisplay(display)) { Point size = new Point(); - d.getRealSize(size); - extraInternalDisplays.add(new PortraitSize(size.x, size.y)); + display.getRealSize(size); + internalDisplays.put(ApiWrapper.getUniqueId(display), + new PortraitSize(size.x, size.y)); } } - mInfo = new Info(getDisplayInfoContext(display), display, extraInternalDisplays); - mDM.registerDisplayListener(this, UI_HELPER_EXECUTOR.getHandler()); + return internalDisplays; + } + + @Override + public void close() { + mDestroyed = true; + if (mWindowContext != null) { + mWindowContext.unregisterComponentCallbacks(this); + } else { + // TODO: unregister broadcast receiver + } + mDM.unregisterDisplayListener(this); } @Override @@ -157,6 +179,9 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { * Only used for pre-S */ private void onConfigChanged(Intent intent) { + if (mDestroyed) { + return; + } Configuration config = mContext.getResources().getConfiguration(); if (mInfo.fontScale != config.fontScale || mInfo.densityDpi != config.densityDpi) { Log.d(TAG, "Configuration changed, notifying listeners"); @@ -184,6 +209,10 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { @Override public final void onLowMemory() { } + public void setPriorityListener(DisplayInfoChangeListener listener) { + mPriorityListener = listener; + } + public void addChangeListener(DisplayInfoChangeListener listener) { mListeners.add(listener); } @@ -203,13 +232,18 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { @AnyThread private void handleInfoChange(Display display) { Info oldInfo = mInfo; - Set<PortraitSize> extraDisplaysSizes = oldInfo.mAllSizes.size() > 1 - ? oldInfo.mAllSizes : Collections.emptySet(); Context displayContext = getDisplayInfoContext(display); - Info newInfo = new Info(displayContext, display, extraDisplaysSizes); + Info newInfo = new Info(displayContext, display, + oldInfo.mInternalDisplays, oldInfo.mPerDisplayBounds); + + if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale) { + // Cache may not be valid anymore, recreate without cache + newInfo = new Info(displayContext, display, getInternalDisplays(mDM), emptyMap()); + } + int change = 0; - if (!newInfo.mScreenSizeDp.equals(oldInfo.mScreenSizeDp)) { + if (!newInfo.displayId.equals(oldInfo.displayId)) { change |= CHANGE_ACTIVE_SCREEN; } if (newInfo.rotation != oldInfo.rotation) { @@ -223,6 +257,21 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { } if (!newInfo.supportedBounds.equals(oldInfo.supportedBounds)) { change |= CHANGE_SUPPORTED_BOUNDS; + + PortraitSize realSize = new PortraitSize(newInfo.currentSize.x, newInfo.currentSize.y); + PortraitSize expectedSize = oldInfo.mInternalDisplays.get( + ApiWrapper.getUniqueId(display)); + if (newInfo.supportedBounds.size() != oldInfo.supportedBounds.size()) { + Log.e("b/198965093", + "Inconsistent number of displays" + + "\ndisplay state: " + display.getState() + + "\noldInfo.supportedBounds: " + oldInfo.supportedBounds + + "\nnewInfo.supportedBounds: " + newInfo.supportedBounds); + } + if (!realSize.equals(expectedSize) && display.getState() == Display.STATE_OFF) { + Log.e("b/198965093", "Display size changed while display is off, ignoring change"); + return; + } } if (change != 0) { @@ -233,6 +282,9 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { } private void notifyChange(Context context, int flags) { + if (mPriorityListener != null) { + mPriorityListener.onDisplayInfoChanged(context, mInfo, flags); + } for (int i = mListeners.size() - 1; i >= 0; i--) { mListeners.get(i).onDisplayInfoChanged(context, mInfo, flags); } @@ -240,7 +292,6 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { public static class Info { - public final int id; public final int singleFrameMs; // Configuration properties @@ -249,19 +300,22 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { public final int densityDpi; private final PortraitSize mScreenSizeDp; - private final Set<PortraitSize> mAllSizes; public final Point currentSize; + public String displayId; public final Set<WindowBounds> supportedBounds = new ArraySet<>(); + private final Map<String, Set<WindowBounds>> mPerDisplayBounds = new ArrayMap<>(); + private final ArrayMap<String, PortraitSize> mInternalDisplays; public Info(Context context, Display display) { - this(context, display, Collections.emptySet()); + this(context, display, new ArrayMap<>(), emptyMap()); } - private Info(Context context, Display display, Set<PortraitSize> extraDisplaysSizes) { - id = display.getDisplayId(); - + private Info(Context context, Display display, + ArrayMap<String, PortraitSize> internalDisplays, + Map<String, Set<WindowBounds>> perDisplayBoundsCache) { + mInternalDisplays = internalDisplays; rotation = display.getRotation(); Configuration config = context.getResources().getConfiguration(); @@ -271,32 +325,51 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { singleFrameMs = getSingleFrameMs(display); currentSize = new Point(); - display.getRealSize(currentSize); - if (extraDisplaysSizes.isEmpty() || !Utilities.ATLEAST_S) { - Point smallestSize = new Point(); - Point largestSize = new Point(); - display.getCurrentSizeRange(smallestSize, largestSize); - - int portraitWidth = Math.min(currentSize.x, currentSize.y); - int portraitHeight = Math.max(currentSize.x, currentSize.y); - - supportedBounds.add(new WindowBounds(portraitWidth, portraitHeight, - smallestSize.x, largestSize.y)); - supportedBounds.add(new WindowBounds(portraitHeight, portraitWidth, - largestSize.x, smallestSize.y)); - mAllSizes = Collections.singleton(new PortraitSize(currentSize.x, currentSize.y)); - } else { - mAllSizes = new ArraySet<>(extraDisplaysSizes); - mAllSizes.add(new PortraitSize(currentSize.x, currentSize.y)); - Set<WindowMetrics> metrics = WindowManagerCompat.getDisplayProfiles( - context, mAllSizes, densityDpi, - ApiWrapper.TASKBAR_DRAWN_IN_PROCESS); - metrics.forEach(wm -> supportedBounds.add(WindowBounds.fromWindowMetrics(wm))); + displayId = ApiWrapper.getUniqueId(display); + Set<WindowBounds> currentSupportedBounds = + getSupportedBoundsForDisplay(display, currentSize); + mPerDisplayBounds.put(displayId, currentSupportedBounds); + supportedBounds.addAll(currentSupportedBounds); + + if (ApiWrapper.isInternalDisplay(display) && internalDisplays.size() > 1) { + int displayCount = internalDisplays.size(); + for (int i = 0; i < displayCount; i++) { + String displayKey = internalDisplays.keyAt(i); + if (TextUtils.equals(displayId, displayKey)) { + continue; + } + + Set<WindowBounds> displayBounds = perDisplayBoundsCache.get(displayKey); + if (displayBounds == null) { + // We assume densityDpi is the same across all internal displays + displayBounds = WindowManagerCompat.estimateDisplayProfiles( + context, internalDisplays.valueAt(i), densityDpi, + ApiWrapper.TASKBAR_DRAWN_IN_PROCESS); + } + + supportedBounds.addAll(displayBounds); + mPerDisplayBounds.put(displayKey, displayBounds); + } } } + private static Set<WindowBounds> getSupportedBoundsForDisplay(Display display, Point size) { + Point smallestSize = new Point(); + Point largestSize = new Point(); + display.getCurrentSizeRange(smallestSize, largestSize); + + int portraitWidth = Math.min(size.x, size.y); + int portraitHeight = Math.max(size.x, size.y); + Set<WindowBounds> result = new ArraySet<>(); + result.add(new WindowBounds(portraitWidth, portraitHeight, + smallestSize.x, largestSize.y)); + result.add(new WindowBounds(portraitHeight, portraitWidth, + largestSize.x, smallestSize.y)); + return result; + } + /** * Returns true if the bounds represent a tablet */ |