diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index a9c2a5e51d..5769f0bf65 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -44,7 +44,6 @@ import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener; import com.android.launcher3.LauncherAppState; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.InstanceIdSequence; @@ -68,7 +67,7 @@ import java.util.stream.IntStream; /** * Model delegate which loads prediction items */ -public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChangeListener { +public class QuickstepModelDelegate extends ModelDelegate { public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state"; private static final String LAST_SNAPSHOT_TIME_MILLIS = "LAST_SNAPSHOT_TIME_MILLIS"; @@ -93,7 +92,6 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange mAppEventProducer = new AppEventProducer(context, this::onAppTargetEvent); mIDP = InvariantDeviceProfile.INSTANCE.get(context); - mIDP.addOnChangeListener(this); StatsLogCompatManager.LOGS_CONSUMER.add(mAppEventProducer); } @@ -179,7 +177,6 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange StatsLogCompatManager.LOGS_CONSUMER.remove(mAppEventProducer); destroyPredictors(); - mIDP.removeOnChangeListener(this); } private void destroyPredictors() { @@ -250,12 +247,6 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange mWidgetsRecommendationState.predictor.requestPredictionUpdate(); } - @Override - public void onIdpChanged(InvariantDeviceProfile profile) { - // Reinitialize everything - Executors.MODEL_EXECUTOR.execute(this::recreatePredictors); - } - private void onAppTargetEvent(AppTargetEvent event, int client) { PredictorState state = client == CONTAINER_PREDICTION ? mAllAppsState : mHotseatState; if (state.predictor != null) { diff --git a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java b/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java index 99dc2828ea..c776f16d2a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java +++ b/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java @@ -149,7 +149,7 @@ public class RotationButtonController { public void init() { registerListeners(); - if (mDisplayController.getInfo().id != DEFAULT_DISPLAY) { + if (mContext.getDisplay().getDisplayId() != DEFAULT_DISPLAY) { // Currently there is no accelerometer sensor on non-default display, disable fixed // rotation for non-default display onDisable2FlagChanged(StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS); @@ -168,7 +168,7 @@ public class RotationButtonController { mListenersRegistered = true; try { WindowManagerGlobal.getWindowManagerService() - .watchRotation(mRotationWatcher, mDisplayController.getInfo().id); + .watchRotation(mRotationWatcher, DEFAULT_DISPLAY); } catch (IllegalArgumentException e) { mListenersRegistered = false; Log.w(TAG, "RegisterListeners for the display failed"); @@ -335,7 +335,7 @@ public class RotationButtonController { } public void onBehaviorChanged(int displayId, @WindowInsetsController.Behavior int behavior) { - if (mDisplayController.getInfo().id != displayId) { + if (DEFAULT_DISPLAY != displayId) { return; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java index 85943b66a6..8181a846e4 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java +++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java @@ -43,6 +43,13 @@ public class ApiWrapper { return display.getType() == Display.TYPE_INTERNAL; } + /** + * Returns a unique ID representing the display + */ + public static String getUniqueId(Display display) { + return display.getUniqueId(); + } + /** * Returns the minimum space that should be left empty at the end of hotseat */ diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index 444d77a612..8a9bf7c826 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -18,6 +18,7 @@ package com.android.quickstep; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.Intent.ACTION_USER_UNLOCKED; +import static android.view.Display.DEFAULT_DISPLAY; import static com.android.launcher3.util.DisplayController.CHANGE_ALL; import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION; @@ -59,7 +60,6 @@ import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; import android.util.DisplayMetrics; -import android.util.Log; import android.view.MotionEvent; import android.view.Surface; @@ -67,7 +67,6 @@ import androidx.annotation.BinderThread; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener; import com.android.launcher3.util.DisplayController.Info; @@ -147,7 +146,7 @@ public class RecentsAnimationDeviceState implements mContext = context; mDisplayController = DisplayController.INSTANCE.get(context); mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context); - mDisplayId = mDisplayController.getInfo().id; + mDisplayId = DEFAULT_DISPLAY; mIsOneHandedModeSupported = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false); runOnDestroy(() -> mDisplayController.removeChangeListener(this)); mRotationTouchHelper = RotationTouchHelper.INSTANCE.get(context); diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java index 678b176151..2a422cce83 100644 --- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java +++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java @@ -15,6 +15,7 @@ */ package com.android.quickstep; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Surface.ROTATION_0; import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN; @@ -25,7 +26,6 @@ import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS; import android.content.Context; import android.content.res.Resources; -import android.util.Log; import android.view.MotionEvent; import android.view.OrientationEventListener; @@ -35,7 +35,6 @@ import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener; import com.android.launcher3.util.DisplayController.Info; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.quickstep.util.RecentsOrientedState; -import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; @@ -146,7 +145,7 @@ public class RotationTouchHelper implements mDisplayController = DisplayController.INSTANCE.get(mContext); Resources resources = mContext.getResources(); mSysUiNavMode = SysUINavigationMode.INSTANCE.get(mContext); - mDisplayId = mDisplayController.getInfo().id; + mDisplayId = DEFAULT_DISPLAY; mOrientationTouchTransformer = new OrientationTouchTransformer(resources, mMode, () -> QuickStepContract.getWindowCornerRadius(resources)); diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 2e1482384f..a2189c9f8b 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -57,6 +57,7 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -158,38 +159,6 @@ public class InvariantDeviceProfile { @VisibleForTesting public InvariantDeviceProfile() {} - private InvariantDeviceProfile(InvariantDeviceProfile p) { - numRows = p.numRows; - numColumns = p.numColumns; - numFolderRows = p.numFolderRows; - numFolderColumns = p.numFolderColumns; - iconSize = p.iconSize; - landscapeIconSize = p.landscapeIconSize; - twoPanelPortraitIconSize = p.twoPanelPortraitIconSize; - twoPanelLandscapeIconSize = p.twoPanelLandscapeIconSize; - iconBitmapSize = p.iconBitmapSize; - iconTextSize = p.iconTextSize; - landscapeIconTextSize = p.landscapeIconTextSize; - twoPanelPortraitIconTextSize = p.twoPanelPortraitIconTextSize; - twoPanelLandscapeIconTextSize = p.twoPanelLandscapeIconTextSize; - numShownHotseatIcons = p.numShownHotseatIcons; - numDatabaseHotseatIcons = p.numDatabaseHotseatIcons; - numAllAppsColumns = p.numAllAppsColumns; - numDatabaseAllAppsColumns = p.numDatabaseAllAppsColumns; - isScalable = p.isScalable; - devicePaddingId = p.devicePaddingId; - minCellHeight = p.minCellHeight; - minCellWidth = p.minCellWidth; - borderSpacing = p.borderSpacing; - dbFile = p.dbFile; - allAppsIconSize = p.allAppsIconSize; - allAppsIconTextSize = p.allAppsIconTextSize; - defaultLayoutId = p.defaultLayoutId; - demoModeLayoutId = p.demoModeLayoutId; - mExtraAttrs = p.mExtraAttrs; - devicePaddings = p.devicePaddings; - } - @TargetApi(23) private InvariantDeviceProfile(Context context) { String gridName = getCurrentGridName(context); @@ -236,13 +205,13 @@ public class InvariantDeviceProfile { DisplayOption result = new DisplayOption(defaultDisplayOption.grid) .add(myDisplayOption); - result.iconSize = defaultDisplayOption.iconSize; - result.landscapeIconSize = defaultDisplayOption.landscapeIconSize; - if (defaultDisplayOption.allAppsIconSize < myDisplayOption.allAppsIconSize) { - result.allAppsIconSize = defaultDisplayOption.allAppsIconSize; - } else { - result.allAppsIconSize = myDisplayOption.allAppsIconSize; + result.iconSizes[DisplayOption.INDEX_DEFAULT] = + defaultDisplayOption.iconSizes[DisplayOption.INDEX_DEFAULT]; + for (int i = 1; i < DisplayOption.COUNT_TOTAL; i++) { + result.iconSizes[i] = Math.min( + defaultDisplayOption.iconSizes[i], myDisplayOption.iconSizes[i]); } + result.minCellHeight = defaultDisplayOption.minCellHeight; result.minCellWidth = defaultDisplayOption.minCellWidth; result.borderSpacing = defaultDisplayOption.borderSpacing; @@ -288,17 +257,21 @@ public class InvariantDeviceProfile { mExtraAttrs = closestProfile.extraAttrs; - iconSize = displayOption.iconSize; - landscapeIconSize = displayOption.landscapeIconSize; - twoPanelPortraitIconSize = displayOption.twoPanelPortraitIconSize; - twoPanelLandscapeIconSize = displayOption.twoPanelLandscapeIconSize; + iconSize = displayOption.iconSizes[DisplayOption.INDEX_DEFAULT]; + landscapeIconSize = displayOption.iconSizes[DisplayOption.INDEX_LANDSCAPE]; + twoPanelPortraitIconSize = displayOption.iconSizes[DisplayOption.INDEX_TWO_PANEL_PORTRAIT]; + twoPanelLandscapeIconSize = + displayOption.iconSizes[DisplayOption.INDEX_TWO_PANEL_LANDSCAPE]; iconBitmapSize = ResourceUtils.pxFromDp(iconSize, metrics); - iconTextSize = displayOption.iconTextSize; - landscapeIconTextSize = displayOption.landscapeIconTextSize; - twoPanelPortraitIconTextSize = displayOption.twoPanelPortraitIconTextSize; - twoPanelLandscapeIconTextSize = displayOption.twoPanelLandscapeIconTextSize; fillResIconDpi = getLauncherIconDensity(iconBitmapSize); + iconTextSize = displayOption.textSizes[DisplayOption.INDEX_DEFAULT]; + landscapeIconTextSize = displayOption.textSizes[DisplayOption.INDEX_LANDSCAPE]; + twoPanelPortraitIconTextSize = + displayOption.textSizes[DisplayOption.INDEX_TWO_PANEL_PORTRAIT]; + twoPanelLandscapeIconTextSize = + displayOption.textSizes[DisplayOption.INDEX_TWO_PANEL_LANDSCAPE]; + minCellHeight = displayOption.minCellHeight; minCellWidth = displayOption.minCellWidth; borderSpacing = displayOption.borderSpacing; @@ -312,8 +285,8 @@ public class InvariantDeviceProfile { ? closestProfile.numDatabaseAllAppsColumns : closestProfile.numAllAppsColumns; if (Utilities.isGridOptionsEnabled(context)) { - allAppsIconSize = displayOption.allAppsIconSize; - allAppsIconTextSize = displayOption.allAppsIconTextSize; + allAppsIconSize = displayOption.iconSizes[DisplayOption.INDEX_ALL_APPS]; + allAppsIconTextSize = displayOption.textSizes[DisplayOption.INDEX_ALL_APPS]; } else { allAppsIconSize = iconSize; allAppsIconTextSize = iconTextSize; @@ -374,13 +347,22 @@ public class InvariantDeviceProfile { MAIN_EXECUTOR.execute(() -> onConfigChanged(appContext)); } + private Object[] toModelState() { + return new Object[] { + numColumns, numRows, numDatabaseHotseatIcons, iconBitmapSize, fillResIconDpi, + numDatabaseAllAppsColumns, dbFile}; + } + private void onConfigChanged(Context context) { + Object[] oldState = toModelState(); + // Re-init grid String gridName = getCurrentGridName(context); initGrid(context, gridName); + boolean modelPropsChanged = !Arrays.equals(oldState, toModelState()); for (OnIDPChangeListener listener : mChangeListeners) { - listener.onIdpChanged(this); + listener.onIdpChanged(modelPropsChanged); } } @@ -533,22 +515,33 @@ public class InvariantDeviceProfile { Float.compare(dist(width, height, a.minWidthDps, a.minHeightDps), dist(width, height, b.minWidthDps, b.minHeightDps))); - GridOption closestOption = points.get(0).grid; + DisplayOption closestPoint = points.get(0); + GridOption closestOption = closestPoint.grid; float weights = 0; - DisplayOption p = points.get(0); - if (dist(width, height, p.minWidthDps, p.minHeightDps) == 0) { - return p; + if (dist(width, height, closestPoint.minWidthDps, closestPoint.minHeightDps) == 0) { + return closestPoint; } DisplayOption out = new DisplayOption(closestOption); for (int i = 0; i < points.size() && i < KNEARESTNEIGHBOR; ++i) { - p = points.get(i); + DisplayOption p = points.get(i); float w = weight(width, height, p.minWidthDps, p.minHeightDps, WEIGHT_POWER); weights += w; out.add(new DisplayOption().add(p).multiply(w)); } - return out.multiply(1.0f / weights); + out.multiply(1.0f / weights); + + // Since the bitmaps are persisted, ensure that the default bitmap size is same as + // predefined size to avoid cache invalidation + out.iconSizes[DisplayOption.INDEX_DEFAULT] = + closestPoint.iconSizes[DisplayOption.INDEX_DEFAULT]; + for (int i = DisplayOption.INDEX_DEFAULT + 1; i < DisplayOption.COUNT_TOTAL; i++) { + out.iconSizes[i] = Math.min(out.iconSizes[i], + out.iconSizes[DisplayOption.INDEX_DEFAULT]); + } + + return out; } public DeviceProfile getDeviceProfile(Context context) { @@ -614,7 +607,7 @@ public class InvariantDeviceProfile { /** * Called when the device provide changes */ - void onIdpChanged(InvariantDeviceProfile profile); + void onIdpChanged(boolean modelPropertiesChanged); } @@ -695,6 +688,14 @@ public class InvariantDeviceProfile { @VisibleForTesting static final class DisplayOption { + static final int INDEX_DEFAULT = 0; + static final int INDEX_LANDSCAPE = 1; + static final int INDEX_ALL_APPS = 2; + static final int INDEX_TWO_PANEL_PORTRAIT = 3; + static final int INDEX_TWO_PANEL_LANDSCAPE = 4; + + static final int COUNT_TOTAL = 5; + public final GridOption grid; private final float minWidthDps; @@ -705,16 +706,8 @@ public class InvariantDeviceProfile { private float minCellWidth; private float borderSpacing; - private float iconSize; - private float iconTextSize; - private float landscapeIconSize; - private float twoPanelPortraitIconSize; - private float twoPanelLandscapeIconSize; - private float landscapeIconTextSize; - private float twoPanelPortraitIconTextSize; - private float twoPanelLandscapeIconTextSize; - private float allAppsIconSize; - private float allAppsIconTextSize; + private final float[] iconSizes = new float[COUNT_TOTAL]; + private final float[] textSizes = new float[COUNT_TOTAL]; DisplayOption(GridOption grid, Context context, AttributeSet attrs, int defaultFlagValue) { this.grid = grid; @@ -732,27 +725,36 @@ public class InvariantDeviceProfile { minCellWidth = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidthDps, 0); borderSpacing = a.getFloat(R.styleable.ProfileDisplayOption_borderSpacingDps, 0); - iconSize = a.getFloat(R.styleable.ProfileDisplayOption_iconImageSize, 0); - landscapeIconSize = a.getFloat(R.styleable.ProfileDisplayOption_landscapeIconSize, - iconSize); - twoPanelPortraitIconSize = a.getFloat( - R.styleable.ProfileDisplayOption_twoPanelPortraitIconSize, iconSize); - twoPanelLandscapeIconSize = a.getFloat( - R.styleable.ProfileDisplayOption_twoPanelLandscapeIconSize, - landscapeIconSize); - iconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0); - landscapeIconTextSize = a.getFloat( - R.styleable.ProfileDisplayOption_landscapeIconTextSize, iconTextSize); - twoPanelPortraitIconTextSize = a.getFloat( - R.styleable.ProfileDisplayOption_twoPanelPortraitIconTextSize, iconTextSize); - twoPanelLandscapeIconTextSize = a.getFloat( - R.styleable.ProfileDisplayOption_twoPanelLandscapeIconTextSize, - landscapeIconTextSize); + iconSizes[INDEX_DEFAULT] = + a.getFloat(R.styleable.ProfileDisplayOption_iconImageSize, 0); + iconSizes[INDEX_LANDSCAPE] = + a.getFloat(R.styleable.ProfileDisplayOption_landscapeIconSize, + iconSizes[INDEX_DEFAULT]); + iconSizes[INDEX_ALL_APPS] = + a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconSize, + iconSizes[INDEX_DEFAULT]); + iconSizes[INDEX_TWO_PANEL_PORTRAIT] = + a.getFloat(R.styleable.ProfileDisplayOption_twoPanelPortraitIconSize, + iconSizes[INDEX_DEFAULT]); + iconSizes[INDEX_TWO_PANEL_LANDSCAPE] = + a.getFloat(R.styleable.ProfileDisplayOption_twoPanelLandscapeIconSize, + iconSizes[INDEX_LANDSCAPE]); + + textSizes[INDEX_DEFAULT] = + a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0); + textSizes[INDEX_LANDSCAPE] = + a.getFloat(R.styleable.ProfileDisplayOption_landscapeIconTextSize, + textSizes[INDEX_DEFAULT]); + textSizes[INDEX_ALL_APPS] = + a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconTextSize, + textSizes[INDEX_DEFAULT]); + textSizes[INDEX_TWO_PANEL_PORTRAIT] = + a.getFloat(R.styleable.ProfileDisplayOption_twoPanelPortraitIconTextSize, + textSizes[INDEX_DEFAULT]); + textSizes[INDEX_TWO_PANEL_LANDSCAPE] = + a.getFloat(R.styleable.ProfileDisplayOption_twoPanelLandscapeIconTextSize, + textSizes[INDEX_LANDSCAPE]); - allAppsIconSize = a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconSize, - iconSize); - allAppsIconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconTextSize, - iconTextSize); a.recycle(); } @@ -771,16 +773,10 @@ public class InvariantDeviceProfile { } private DisplayOption multiply(float w) { - iconSize *= w; - landscapeIconSize *= w; - twoPanelPortraitIconSize *= w; - twoPanelLandscapeIconSize *= w; - allAppsIconSize *= w; - iconTextSize *= w; - landscapeIconTextSize *= w; - twoPanelPortraitIconTextSize *= w; - twoPanelLandscapeIconTextSize *= w; - allAppsIconTextSize *= w; + for (int i = 0; i < COUNT_TOTAL; i++) { + iconSizes[i] *= w; + textSizes[i] *= w; + } minCellHeight *= w; minCellWidth *= w; borderSpacing *= w; @@ -788,16 +784,10 @@ public class InvariantDeviceProfile { } private DisplayOption add(DisplayOption p) { - iconSize += p.iconSize; - landscapeIconSize += p.landscapeIconSize; - twoPanelPortraitIconSize += p.twoPanelPortraitIconSize; - twoPanelLandscapeIconSize += p.twoPanelLandscapeIconSize; - allAppsIconSize += p.allAppsIconSize; - iconTextSize += p.iconTextSize; - landscapeIconTextSize += p.landscapeIconTextSize; - twoPanelPortraitIconTextSize += p.twoPanelPortraitIconTextSize; - twoPanelLandscapeIconTextSize += p.twoPanelLandscapeIconTextSize; - allAppsIconTextSize += p.allAppsIconTextSize; + for (int i = 0; i < COUNT_TOTAL; i++) { + iconSizes[i] += p.iconSizes[i]; + textSizes[i] += p.textSizes[i]; + } minCellHeight += p.minCellHeight; minCellWidth += p.minCellWidth; borderSpacing += p.borderSpacing; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 6ea7b17871..3754dc147b 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -558,7 +558,7 @@ public class Launcher extends StatefulActivity implements Launche public void onConfigurationChanged(Configuration newConfig) { int diff = newConfig.diff(mOldConfig); if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) { - onIdpChanged(mDeviceProfile.inv); + onIdpChanged(false); } mOldConfig.setTo(newConfig); @@ -566,8 +566,8 @@ public class Launcher extends StatefulActivity implements Launche } @Override - public void onIdpChanged(InvariantDeviceProfile idp) { - initDeviceProfile(idp); + public void onIdpChanged(boolean modelPropertiesChanged) { + initDeviceProfile(mDeviceProfile.inv); dispatchDeviceProfileChanged(); reapplyUi(); mDragLayer.recreateControllers(); diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 702b73afba..8adbcd9caf 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -83,7 +83,11 @@ public class LauncherAppState { Log.v(Launcher.TAG, "LauncherAppState initiated"); Preconditions.assertUIThread(); - mInvariantDeviceProfile.addOnChangeListener(idp -> refreshAndReloadLauncher()); + mInvariantDeviceProfile.addOnChangeListener(modelPropertiesChanged -> { + if (modelPropertiesChanged) { + refreshAndReloadLauncher(); + } + }); mContext.getSystemService(LauncherApps.class).registerCallback(mModel); diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java index e2c0a32bb0..74461819c6 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; @@ -76,8 +79,8 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { // Null for SDK < S private final Context mWindowContext; - private final ArrayList mListeners = new ArrayList<>(); + private Info mInfo; private DisplayController(Context context) { @@ -95,19 +98,24 @@ 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 extraInternalDisplays = new ArraySet<>(); - for (Display d : mDM.getDisplays()) { - if (ApiWrapper.isInternalDisplay(display) && d.getDisplayId() != DEFAULT_DISPLAY) { + private static ArrayMap getInternalDisplays( + DisplayManager displayManager) { + Display[] displays = displayManager.getDisplays(); + ArrayMap 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 @@ -203,11 +211,16 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { @AnyThread private void handleInfoChange(Display display) { Info oldInfo = mInfo; - Set 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)) { change |= CHANGE_ACTIVE_SCREEN; @@ -240,7 +253,6 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { public static class Info { - public final int id; public final int singleFrameMs; // Configuration properties @@ -249,19 +261,21 @@ public class DisplayController implements DisplayListener, ComponentCallbacks { public final int densityDpi; private final PortraitSize mScreenSizeDp; - private final Set mAllSizes; public final Point currentSize; public final Set supportedBounds = new ArraySet<>(); + private final Map> mPerDisplayBounds = new ArrayMap<>(); + private final ArrayMap 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 extraDisplaysSizes) { - id = display.getDisplayId(); - + private Info(Context context, Display display, + ArrayMap internalDisplays, + Map> perDisplayBoundsCache) { + mInternalDisplays = internalDisplays; rotation = display.getRotation(); Configuration config = context.getResources().getConfiguration(); @@ -271,32 +285,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); + String myDisplayId = ApiWrapper.getUniqueId(display); + Set currentSupportedBounds = + getSupportedBoundsForDisplay(display, currentSize); + mPerDisplayBounds.put(myDisplayId, currentSupportedBounds); + supportedBounds.addAll(currentSupportedBounds); - int portraitWidth = Math.min(currentSize.x, currentSize.y); - int portraitHeight = Math.max(currentSize.x, currentSize.y); + 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(myDisplayId, displayKey)) { + continue; + } - 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 metrics = WindowManagerCompat.getDisplayProfiles( - context, mAllSizes, densityDpi, - ApiWrapper.TASKBAR_DRAWN_IN_PROCESS); - metrics.forEach(wm -> supportedBounds.add(WindowBounds.fromWindowMetrics(wm))); + Set 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 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 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 */ diff --git a/src/com/android/launcher3/util/WindowManagerCompat.java b/src/com/android/launcher3/util/WindowManagerCompat.java index 38a63de592..bfdf1e40ce 100644 --- a/src/com/android/launcher3/util/WindowManagerCompat.java +++ b/src/com/android/launcher3/util/WindowManagerCompat.java @@ -24,6 +24,7 @@ import android.content.res.Configuration; import android.graphics.Insets; import android.graphics.Rect; import android.os.Build; +import android.util.ArraySet; import android.view.WindowInsets; import android.view.WindowInsets.Type; import android.view.WindowManager; @@ -31,14 +32,14 @@ import android.view.WindowMetrics; import com.android.launcher3.R; import com.android.launcher3.ResourceUtils; +import com.android.launcher3.Utilities; import com.android.launcher3.util.DisplayController.PortraitSize; -import java.util.Collection; -import java.util.HashSet; +import java.util.Collections; import java.util.Set; /** - * Utility class to simulate window manager APIs until proper APIs are available + * Utility class to estimate window manager values */ @TargetApi(Build.VERSION_CODES.S) public class WindowManagerCompat { @@ -46,51 +47,51 @@ public class WindowManagerCompat { public static final int MIN_TABLET_WIDTH = 600; /** - * Returns a set of supported render sizes for a set of internal displays. - * This is a temporary workaround which assumes only nav-bar insets change across displays + * Returns a set of supported render sizes for a internal display. + * This is a temporary workaround which assumes only nav-bar insets change across displays, and + * is only used until we eventually get the real values * @param consumeTaskBar if true, it assumes that task bar is part of the app window * and ignores any insets because of task bar. */ - public static Set getDisplayProfiles( - Context windowContext, Collection allDisplaySizes, - int densityDpi, boolean consumeTaskBar) { - WindowInsets metrics = windowContext.getSystemService(WindowManager.class) + public static Set estimateDisplayProfiles( + Context windowContext, PortraitSize size, int densityDpi, boolean consumeTaskBar) { + if (!Utilities.ATLEAST_S) { + return Collections.emptySet(); + } + WindowInsets defaultInsets = windowContext.getSystemService(WindowManager.class) .getMaximumWindowMetrics().getWindowInsets(); boolean hasNavbar = ResourceUtils.getIntegerByName( "config_navBarInteractionMode", windowContext.getResources(), INVALID_RESOURCE_HANDLE) != 0; - WindowInsets.Builder insetsBuilder = new WindowInsets.Builder(metrics); + WindowInsets.Builder insetsBuilder = new WindowInsets.Builder(defaultInsets); + Set result = new ArraySet<>(); + int swDP = (int) dpiFromPx(size.width, densityDpi); + boolean isTablet = swDP >= MIN_TABLET_WIDTH; - Set result = new HashSet<>(); - for (PortraitSize size : allDisplaySizes) { - int swDP = (int) dpiFromPx(size.width, densityDpi); - boolean isTablet = swDP >= MIN_TABLET_WIDTH; - - final Insets portraitNav, landscapeNav; - if (isTablet && !consumeTaskBar) { - portraitNav = landscapeNav = Insets.of(0, 0, 0, windowContext.getResources() - .getDimensionPixelSize(R.dimen.taskbar_size)); - } else if (hasNavbar) { - portraitNav = Insets.of(0, 0, 0, - getSystemResource(windowContext, "navigation_bar_height", swDP)); - landscapeNav = isTablet - ? Insets.of(0, 0, 0, getSystemResource(windowContext, - "navigation_bar_height_landscape", swDP)) - : Insets.of(0, 0, getSystemResource(windowContext, - "navigation_bar_width", swDP), 0); - } else { - portraitNav = landscapeNav = Insets.of(0, 0, 0, 0); - } - - result.add(new WindowMetrics( - new Rect(0, 0, size.width, size.height), - insetsBuilder.setInsets(Type.navigationBars(), portraitNav).build())); - result.add(new WindowMetrics( - new Rect(0, 0, size.height, size.width), - insetsBuilder.setInsets(Type.navigationBars(), landscapeNav).build())); + final Insets portraitNav, landscapeNav; + if (isTablet && !consumeTaskBar) { + portraitNav = landscapeNav = Insets.of(0, 0, 0, windowContext.getResources() + .getDimensionPixelSize(R.dimen.taskbar_size)); + } else if (hasNavbar) { + portraitNav = Insets.of(0, 0, 0, + getSystemResource(windowContext, "navigation_bar_height", swDP)); + landscapeNav = isTablet + ? Insets.of(0, 0, 0, getSystemResource(windowContext, + "navigation_bar_height_landscape", swDP)) + : Insets.of(0, 0, getSystemResource(windowContext, + "navigation_bar_width", swDP), 0); + } else { + portraitNav = landscapeNav = Insets.of(0, 0, 0, 0); } + + result.add(WindowBounds.fromWindowMetrics(new WindowMetrics( + new Rect(0, 0, size.width, size.height), + insetsBuilder.setInsets(Type.navigationBars(), portraitNav).build()))); + result.add(WindowBounds.fromWindowMetrics(new WindowMetrics( + new Rect(0, 0, size.height, size.width), + insetsBuilder.setInsets(Type.navigationBars(), landscapeNav).build()))); return result; } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java index cc90e6c513..81e3f988ba 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java @@ -38,6 +38,13 @@ public class ApiWrapper { return display.getDisplayId() == Display.DEFAULT_DISPLAY; } + /** + * Returns a unique ID representing the display + */ + public static String getUniqueId(Display display) { + return Integer.toString(display.getDisplayId()); + } + /** * Returns the minimum space that should be left empty at the end of hotseat */