Do not reload launcher when changing active display
> Updating IDP to use fixed bitmap sizes, so that the cache stays valid > Caching last known windowMetrices for non-active displays and using estimation only when the cache is not available > Only reloading model if IDP change could have affected the model > Remove unnecessary listeners from IDP which are already controlled by model lifecycle Bug: 191657065 Test: Manual Change-Id: Ia8e6dfafd0977e62aa3fcf367ad79f7a49b2df51
This commit is contained in:
parent
ee3814de1a
commit
6e6f79933e
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -558,7 +558,7 @@ public class Launcher extends StatefulActivity<LauncherState> 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<LauncherState> implements Launche
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onIdpChanged(InvariantDeviceProfile idp) {
|
||||
initDeviceProfile(idp);
|
||||
public void onIdpChanged(boolean modelPropertiesChanged) {
|
||||
initDeviceProfile(mDeviceProfile.inv);
|
||||
dispatchDeviceProfileChanged();
|
||||
reapplyUi();
|
||||
mDragLayer.recreateControllers();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<DisplayInfoChangeListener> 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<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
|
||||
|
@ -203,11 +211,16 @@ 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)) {
|
||||
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<PortraitSize> mAllSizes;
|
||||
|
||||
public final Point currentSize;
|
||||
|
||||
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 +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<WindowBounds> 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<WindowMetrics> metrics = WindowManagerCompat.getDisplayProfiles(
|
||||
context, mAllSizes, densityDpi,
|
||||
ApiWrapper.TASKBAR_DRAWN_IN_PROCESS);
|
||||
metrics.forEach(wm -> supportedBounds.add(WindowBounds.fromWindowMetrics(wm)));
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -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<WindowMetrics> getDisplayProfiles(
|
||||
Context windowContext, Collection<PortraitSize> allDisplaySizes,
|
||||
int densityDpi, boolean consumeTaskBar) {
|
||||
WindowInsets metrics = windowContext.getSystemService(WindowManager.class)
|
||||
public static Set<WindowBounds> 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<WindowBounds> result = new ArraySet<>();
|
||||
int swDP = (int) dpiFromPx(size.width, densityDpi);
|
||||
boolean isTablet = swDP >= MIN_TABLET_WIDTH;
|
||||
|
||||
Set<WindowMetrics> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue