Merge "Removing unnecessary device sumaltion code" into tm-qpr-dev

This commit is contained in:
Sunny Goyal
2023-04-04 17:00:34 +00:00
committed by Android (Google) Code Review
6 changed files with 39 additions and 395 deletions
@@ -41,7 +41,6 @@ import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.util.Xml;
import android.view.Display;
@@ -58,11 +57,9 @@ import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Partner;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.WindowManagerProxy;
@@ -76,6 +73,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class InvariantDeviceProfile {
@@ -151,8 +149,6 @@ public class InvariantDeviceProfile {
public float[] transientTaskbarIconSize;
private SparseArray<TypedValue> mExtraAttrs;
/**
* Number of icons inside the hotseat area.
*/
@@ -360,8 +356,6 @@ public class InvariantDeviceProfile {
inlineNavButtonsEndSpacing = closestProfile.inlineNavButtonsEndSpacing;
mExtraAttrs = closestProfile.extraAttrs;
iconSize = displayOption.iconSizes;
float maxIconSize = iconSize[0];
for (int i = 1; i < iconSize.length; i++) {
@@ -495,9 +489,8 @@ public class InvariantDeviceProfile {
if ((type == XmlPullParser.START_TAG)
&& GridOption.TAG_NAME.equals(parser.getName())) {
GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser),
deviceType);
if (gridOption.isEnabled || allowDisabledGrid) {
GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser));
if (gridOption.isEnabled(deviceType) || allowDisabledGrid) {
final int displayDepth = parser.getDepth();
while (((type = parser.next()) != XmlPullParser.END_TAG
|| parser.getDepth() > displayDepth)
@@ -519,7 +512,7 @@ public class InvariantDeviceProfile {
if (!TextUtils.isEmpty(gridName)) {
for (DisplayOption option : profiles) {
if (gridName.equals(option.grid.name)
&& (option.grid.isEnabled || allowDisabledGrid)) {
&& (option.grid.isEnabled(deviceType) || allowDisabledGrid)) {
filteredProfiles.add(option);
}
}
@@ -542,6 +535,16 @@ public class InvariantDeviceProfile {
* @return all the grid options that can be shown on the device
*/
public List<GridOption> parseAllGridOptions(Context context) {
return parseAllDefinedGridOptions(context)
.stream()
.filter(go -> go.isEnabled(deviceType))
.collect(Collectors.toList());
}
/**
* @return all the grid options that can be shown on the device
*/
public static List<GridOption> parseAllDefinedGridOptions(Context context) {
List<GridOption> result = new ArrayList<>();
try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
@@ -551,11 +554,7 @@ public class InvariantDeviceProfile {
|| parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if ((type == XmlPullParser.START_TAG)
&& GridOption.TAG_NAME.equals(parser.getName())) {
GridOption option =
new GridOption(context, Xml.asAttributeSet(parser), deviceType);
if (option.isEnabled) {
result.add(option);
}
result.add(new GridOption(context, Xml.asAttributeSet(parser)));
}
}
} catch (IOException | XmlPullParserException e) {
@@ -774,7 +773,7 @@ public class InvariantDeviceProfile {
public final int numRows;
public final int numColumns;
public final int numSearchContainerColumns;
public final boolean isEnabled;
public final int deviceCategory;
private final int numFolderRows;
private final int numFolderColumns;
@@ -800,9 +799,7 @@ public class InvariantDeviceProfile {
private final boolean isScalable;
private final int devicePaddingId;
private final SparseArray<TypedValue> extraAttrs;
public GridOption(Context context, AttributeSet attrs, @DeviceType int deviceType) {
public GridOption(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.GridDisplayOption);
name = a.getString(R.styleable.GridDisplayOption_name);
@@ -859,16 +856,8 @@ public class InvariantDeviceProfile {
R.styleable.GridDisplayOption_isScalable, false);
devicePaddingId = a.getResourceId(
R.styleable.GridDisplayOption_devicePaddingId, INVALID_RESOURCE_HANDLE);
int deviceCategory = a.getInt(R.styleable.GridDisplayOption_deviceCategory,
deviceCategory = a.getInt(R.styleable.GridDisplayOption_deviceCategory,
DEVICE_CATEGORY_ALL);
isEnabled = (deviceType == TYPE_PHONE
&& ((deviceCategory & DEVICE_CATEGORY_PHONE) == DEVICE_CATEGORY_PHONE))
|| (deviceType == TYPE_TABLET
&& ((deviceCategory & DEVICE_CATEGORY_TABLET) == DEVICE_CATEGORY_TABLET))
|| (deviceType == TYPE_MULTI_DISPLAY
&& ((deviceCategory & DEVICE_CATEGORY_MULTI_DISPLAY)
== DEVICE_CATEGORY_MULTI_DISPLAY));
int inlineForRotation = a.getInt(R.styleable.GridDisplayOption_inlineQsb,
DONT_INLINE_QSB);
@@ -884,8 +873,20 @@ public class InvariantDeviceProfile {
== INLINE_QSB_FOR_TWO_PANEL_LANDSCAPE;
a.recycle();
extraAttrs = Themes.createValueMap(context, attrs,
IntArray.wrap(R.styleable.GridDisplayOption));
}
public boolean isEnabled(@DeviceType int deviceType) {
switch (deviceType) {
case TYPE_PHONE:
return (deviceCategory & DEVICE_CATEGORY_PHONE) == DEVICE_CATEGORY_PHONE;
case TYPE_TABLET:
return (deviceCategory & DEVICE_CATEGORY_TABLET) == DEVICE_CATEGORY_TABLET;
case TYPE_MULTI_DISPLAY:
return (deviceCategory & DEVICE_CATEGORY_MULTI_DISPLAY)
== DEVICE_CATEGORY_MULTI_DISPLAY;
default:
return false;
}
}
}
@@ -392,6 +392,13 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable {
return dpiFromPx(Math.min(bounds.bounds.width(), bounds.bounds.height()), densityDpi);
}
/**
* Returns all displays for the device
*/
public Set<CachedDisplayInfo> getAllDisplays() {
return Collections.unmodifiableSet(mPerDisplayBounds.keySet());
}
public int getDensityDpi() {
return densityDpi;
}
-45
View File
@@ -1,45 +0,0 @@
{
"pixel6pro": {
"width": 1440,
"height": 3120,
"density": 560,
"name": "pixel6pro",
"cutout": "0, 130, 0, 0",
"grids": [
"normal",
"reasonable",
"practical",
"big",
"crazy_big"
],
"resourceOverrides": {
"status_bar_height": 98,
"navigation_bar_height_landscape": 56,
"navigation_bar_height": 56,
"navigation_bar_width": 56
}
},
"test": {
"data needs updating": 0
},
"pixel5": {
"width": 1080,
"height": 2340,
"density": 440,
"name": "pixel5",
"cutout": "0, 136, 0, 0",
"grids": [
"normal",
"reasonable",
"practical",
"big",
"crazy_big"
],
"resourceOverrides": {
"status_bar_height": 66,
"navigation_bar_height_landscape": 44,
"navigation_bar_height": 44,
"navigation_bar_width": 44
}
}
}
@@ -1,93 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.deviceemulator;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.os.UserHandle;
import android.view.Display;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
import androidx.test.uiautomator.UiDevice;
import com.android.launcher3.deviceemulator.models.DeviceEmulationData;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.util.window.WindowManagerProxy;
import java.util.concurrent.Callable;
public class DisplayEmulator {
Context mContext;
LauncherInstrumentation mLauncher;
DisplayEmulator(Context context, LauncherInstrumentation launcher) {
mContext = context;
mLauncher = launcher;
}
/**
* By changing the WindowManagerProxy we can override the window insets information
**/
private IWindowManager changeWindowManagerInstance(DeviceEmulationData deviceData) {
WindowManagerProxy.INSTANCE.initializeForTesting(new TestWindowManagerProxy(deviceData));
return WindowManagerGlobal.getWindowManagerService();
}
public <T> T emulate(DeviceEmulationData device, String grid, Callable<T> runInEmulation)
throws Exception {
WindowManagerProxy original = WindowManagerProxy.INSTANCE.get(mContext);
// Set up emulation
final int userId = UserHandle.myUserId();
WindowManagerProxy.INSTANCE.initializeForTesting(new TestWindowManagerProxy(device));
IWindowManager wm = changeWindowManagerInstance(device);
// Change density twice to force display controller to reset its state
wm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, device.density / 2, userId);
wm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, device.density, userId);
wm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, device.width, device.height);
wm.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 1);
// Set up grid
setGrid(grid);
try {
return runInEmulation.call();
} finally {
// Clear emulation
WindowManagerProxy.INSTANCE.initializeForTesting(original);
UiDevice.getInstance(getInstrumentation()).executeShellCommand("cmd window reset");
}
}
private void setGrid(String gridType) {
// When the grid changes, the desktop arrangement get stored in SQL and we need to wait to
// make sure there is no SQL operations running and get SQL_BUSY error, that's why we need
// to call mLauncher.waitForLauncherInitialized();
mLauncher.waitForLauncherInitialized();
String testProviderAuthority = mContext.getPackageName() + ".grid_control";
Uri gridUri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(testProviderAuthority)
.appendPath("default_grid")
.build();
ContentValues values = new ContentValues();
values.put("name", gridType);
mContext.getContentResolver().update(gridUri, values, null, null);
}
}
@@ -1,72 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.deviceemulator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.WindowInsets;
import com.android.launcher3.deviceemulator.models.DeviceEmulationData;
import com.android.launcher3.util.RotationUtils;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.CachedDisplayInfo;
import com.android.launcher3.util.window.WindowManagerProxy;
public class TestWindowManagerProxy extends WindowManagerProxy {
private final DeviceEmulationData mDevice;
public TestWindowManagerProxy(DeviceEmulationData device) {
super(true);
mDevice = device;
}
@Override
protected int getDimenByName(Resources res, String resName) {
Integer mock = mDevice.resourceOverrides.get(resName);
return mock != null ? mock : super.getDimenByName(res, resName);
}
@Override
protected int getDimenByName(Resources res, String resName, String fallback) {
return getDimenByName(res, resName);
}
@Override
public CachedDisplayInfo getDisplayInfo(Context displayInfoContext) {
int rotation = getRotation(displayInfoContext);
Point size = new Point(mDevice.width, mDevice.height);
RotationUtils.rotateSize(size, rotation);
Rect cutout = new Rect(mDevice.cutout);
RotationUtils.rotateRect(cutout, rotation);
return new CachedDisplayInfo(size, rotation, cutout);
}
@Override
public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) {
return estimateInternalDisplayBounds(displayInfoContext).get(
getDisplayInfo(displayInfoContext))[getDisplay(displayInfoContext).getRotation()];
}
@Override
public WindowInsets normalizeWindowInsets(Context context, WindowInsets oldInsets,
Rect outInsets) {
outInsets.set(getRealBounds(context, getDisplayInfo(context)).insets);
return oldInsets;
}
}
@@ -1,154 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.deviceemulator.models;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.launcher3.testing.shared.ResourceUtils.NAVBAR_HEIGHT;
import static com.android.launcher3.testing.shared.ResourceUtils.NAVBAR_HEIGHT_LANDSCAPE;
import static com.android.launcher3.testing.shared.ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE;
import static com.android.launcher3.testing.shared.ResourceUtils.getDimenByName;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Build;
import android.util.ArrayMap;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.IOUtils;
import com.android.launcher3.util.IntArray;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Map;
public class DeviceEmulationData {
public final int width;
public final int height;
public final int density;
public final String name;
public final String[] grids;
public final Rect cutout;
public final Map<String, Integer> resourceOverrides;
private static final String[] EMULATED_SYSTEM_RESOURCES = new String[]{
NAVBAR_HEIGHT,
NAVBAR_HEIGHT_LANDSCAPE,
NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE,
"status_bar_height",
};
public DeviceEmulationData(int width, int height, int density, Rect cutout, String name,
String[] grid,
Map<String, Integer> resourceOverrides) {
this.width = width;
this.height = height;
this.density = density;
this.name = name;
this.grids = grid;
this.cutout = cutout;
this.resourceOverrides = resourceOverrides;
}
public static DeviceEmulationData deviceFromJSON(JSONObject json) throws JSONException {
int width = json.getInt("width");
int height = json.getInt("height");
int density = json.getInt("density");
String name = json.getString("name");
JSONArray gridArray = json.getJSONArray("grids");
String[] grids = new String[gridArray.length()];
for (int i = 0, count = grids.length; i < count; i++) {
grids[i] = gridArray.getString(i);
}
IntArray deviceCutout = IntArray.fromConcatString(json.getString("cutout"));
Rect cutout = new Rect(deviceCutout.get(0), deviceCutout.get(1), deviceCutout.get(2),
deviceCutout.get(3));
JSONObject resourceOverridesJson = json.getJSONObject("resourceOverrides");
Map<String, Integer> resourceOverrides = new ArrayMap<>();
for (String key : resourceOverridesJson.keySet()) {
resourceOverrides.put(key, resourceOverridesJson.getInt(key));
}
return new DeviceEmulationData(width, height, density, cutout, name, grids,
resourceOverrides);
}
@Override
public String toString() {
JSONObject json = new JSONObject();
try {
json.put("width", width);
json.put("height", height);
json.put("density", density);
json.put("name", name);
json.put("cutout", IntArray.wrap(
cutout.left, cutout.top, cutout.right, cutout.bottom).toConcatString());
JSONArray gridArray = new JSONArray();
Arrays.stream(grids).forEach(gridArray::put);
json.put("grids", gridArray);
JSONObject resourceOverrides = new JSONObject();
for (Map.Entry<String, Integer> e : this.resourceOverrides.entrySet()) {
resourceOverrides.put(e.getKey(), e.getValue());
}
json.put("resourceOverrides", resourceOverrides);
} catch (Exception e) {
e.printStackTrace();
}
return json.toString();
}
public static DeviceEmulationData getCurrentDeviceData(Context context) {
DisplayController.Info info = DisplayController.INSTANCE.get(context).getInfo();
String[] grids = InvariantDeviceProfile.INSTANCE.get(context)
.parseAllGridOptions(context).stream()
.map(go -> go.name).toArray(String[]::new);
String code = Build.MODEL.replaceAll("\\s", "").toLowerCase();
Map<String, Integer> resourceOverrides = new ArrayMap<>();
for (String s : EMULATED_SYSTEM_RESOURCES) {
resourceOverrides.put(s, getDimenByName(s, context.getResources(), 0));
}
return new DeviceEmulationData(info.currentSize.x, info.currentSize.y,
info.getDensityDpi(), info.cutout, code, grids, resourceOverrides);
}
public static DeviceEmulationData getDevice(String deviceCode) throws Exception {
return DeviceEmulationData.deviceFromJSON(readJSON().getJSONObject(deviceCode));
}
private static JSONObject readJSON() throws Exception {
Context context = getInstrumentation().getContext();
Resources myRes = context.getResources();
int resId = myRes.getIdentifier("devices", "raw", context.getPackageName());
try (InputStream is = myRes.openRawResource(resId)) {
return new JSONObject(new String(IOUtils.toByteArray(is)));
}
}
}