diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2018-11-29 10:33:47 -0800 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2018-12-07 00:06:25 -0800 |
commit | 415f17333123eb40e7677cf0766f59e7af3f7418 (patch) | |
tree | cb2573a312e63bb0602963cf3fa20d1a69f1ee5a /src/com | |
parent | dab230f63ccf3fa184e14ffa3d10a647097d8478 (diff) | |
download | android_packages_apps_Trebuchet-415f17333123eb40e7677cf0766f59e7af3f7418.tar.gz android_packages_apps_Trebuchet-415f17333123eb40e7677cf0766f59e7af3f7418.tar.bz2 android_packages_apps_Trebuchet-415f17333123eb40e7677cf0766f59e7af3f7418.zip |
Changing the format for device profile definition
Device profiles are defined such that the grid size is fixed
and only the icon and text sizes change. For every grid size option
there are multiple display configurations.
Bug: 118758696
Change-Id: I54aac9106c576324b02530913c447e849b4ae1da
Diffstat (limited to 'src/com')
-rw-r--r-- | src/com/android/launcher3/DeviceProfile.java | 9 | ||||
-rw-r--r-- | src/com/android/launcher3/InvariantDeviceProfile.java | 285 | ||||
-rw-r--r-- | src/com/android/launcher3/Utilities.java | 16 | ||||
-rw-r--r-- | src/com/android/launcher3/model/GridSizeMigrationTask.java | 12 | ||||
-rw-r--r-- | src/com/android/launcher3/provider/ImportDataTask.java | 16 |
5 files changed, 210 insertions, 128 deletions
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index c1c12046e..812cf9f8e 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -207,11 +207,10 @@ public class DeviceProfile { // Add a bit of space between nav bar and hotseat in multi-window vertical bar layout. hotseatBarSidePaddingStartPx = isMultiWindowMode && isVerticalBarLayout() ? edgeMarginPx : 0; - hotseatBarSizePx = isVerticalBarLayout() - ? Utilities.pxFromDp(inv.iconSize, dm) + hotseatBarSidePaddingStartPx - + hotseatBarSidePaddingEndPx - : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_size) - + hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx; + hotseatBarSizePx = Utilities.pxFromDp(inv.iconSize, dm) + (isVerticalBarLayout() + ? (hotseatBarSidePaddingStartPx + hotseatBarSidePaddingEndPx) + : (res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size) + + hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx)); // Calculate all of the remaining variables. updateAvailableDimensions(dm, res); diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 0b2f4d921..257e46c2f 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -24,6 +24,8 @@ import android.content.res.Configuration; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.Point; +import android.text.TextUtils; +import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.util.Xml; @@ -32,15 +34,12 @@ import android.view.WindowManager; import com.android.launcher3.util.ConfigMonitor; import com.android.launcher3.util.MainThreadInitializedObject; -import com.android.launcher3.util.Thunk; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import androidx.annotation.VisibleForTesting; @@ -50,6 +49,8 @@ public class InvariantDeviceProfile { public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE = new MainThreadInitializedObject<>(InvariantDeviceProfile::new); + private static final String KEY_IDP_GRIP_NAME = "idp_grid_name"; + private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48; public static final int CHANGE_FLAG_GRID = 1 << 0; @@ -63,11 +64,6 @@ public class InvariantDeviceProfile { // used to offset float not being able to express extremely small weights in extreme cases. private static float WEIGHT_EFFICIENT = 100000f; - // Profile-defining invariant properties - private String name; - private float minWidthDps; - private float minHeightDps; - /** * Number of icons per row and column in the workspace. */ @@ -90,7 +86,7 @@ public class InvariantDeviceProfile { */ public int numHotseatIcons; - int defaultLayoutId; + public int defaultLayoutId; int demoModeLayoutId; public DeviceProfile landscapeProfile; @@ -105,37 +101,26 @@ public class InvariantDeviceProfile { public InvariantDeviceProfile() {} private InvariantDeviceProfile(InvariantDeviceProfile p) { - this(p.name, p.minWidthDps, p.minHeightDps, p.numRows, p.numColumns, - p.numFolderRows, p.numFolderColumns, - p.iconSize, p.landscapeIconSize, p.iconTextSize, p.numHotseatIcons, - p.defaultLayoutId, p.demoModeLayoutId); - } - - private InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc, - float is, float lis, float its, int hs, int dlId, int dmlId) { - name = n; - minWidthDps = w; - minHeightDps = h; - numRows = r; - numColumns = c; - numFolderRows = fr; - numFolderColumns = fc; - iconSize = is; - landscapeIconSize = lis; - iconTextSize = its; - numHotseatIcons = hs; - defaultLayoutId = dlId; - demoModeLayoutId = dmlId; + numRows = p.numRows; + numColumns = p.numColumns; + numFolderRows = p.numFolderRows; + numFolderColumns = p.numFolderColumns; + iconSize = p.iconSize; + landscapeIconSize = p.landscapeIconSize; + iconTextSize = p.iconTextSize; + numHotseatIcons = p.numHotseatIcons; + defaultLayoutId = p.defaultLayoutId; + demoModeLayoutId = p.demoModeLayoutId; } @TargetApi(23) private InvariantDeviceProfile(Context context) { - initGrid(context); + initGrid(context, Utilities.getPrefs(context).getString(KEY_IDP_GRIP_NAME, null)); mConfigMonitor = new ConfigMonitor(context, APPLY_CONFIG_AT_RUNTIME.get() ? this::onConfigChanged : this::killProcess); } - private void initGrid(Context context) { + private void initGrid(Context context, String gridName) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); DisplayMetrics dm = new DisplayMetrics(); @@ -145,16 +130,18 @@ public class InvariantDeviceProfile { Point largestSize = new Point(); display.getCurrentSizeRange(smallestSize, largestSize); + ArrayList<DisplayOption> allOptions = getPredefinedDeviceProfiles(context, gridName); // This guarantees that width < height - minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y), dm); - minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y), dm); - - ArrayList<InvariantDeviceProfile> closestProfiles = findClosestDeviceProfiles( - minWidthDps, minHeightDps, getPredefinedDeviceProfiles(context)); - InvariantDeviceProfile interpolatedDeviceProfileOut = - invDistWeightedInterpolate(minWidthDps, minHeightDps, closestProfiles); - - InvariantDeviceProfile closestProfile = closestProfiles.get(0); + float minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y), dm); + float minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y), dm); + // Sort the profiles based on the closeness to the device size + allOptions.sort((a, b) -> + Float.compare(dist(minWidthDps, minHeightDps, a.minWidthDps, a.minHeightDps), + dist(minWidthDps, minHeightDps, b.minWidthDps, b.minHeightDps))); + DisplayOption interpolatedDisplayOption = + invDistWeightedInterpolate(minWidthDps, minHeightDps, allOptions); + + GridOption closestProfile = allOptions.get(0).grid; numRows = closestProfile.numRows; numColumns = closestProfile.numColumns; numHotseatIcons = closestProfile.numHotseatIcons; @@ -162,11 +149,15 @@ public class InvariantDeviceProfile { demoModeLayoutId = closestProfile.demoModeLayoutId; numFolderRows = closestProfile.numFolderRows; numFolderColumns = closestProfile.numFolderColumns; + if (!closestProfile.name.equals(gridName)) { + Utilities.getPrefs(context).edit() + .putString(KEY_IDP_GRIP_NAME, closestProfile.name).apply(); + } - iconSize = interpolatedDeviceProfileOut.iconSize; - landscapeIconSize = interpolatedDeviceProfileOut.landscapeIconSize; + iconSize = interpolatedDisplayOption.iconSize; + landscapeIconSize = interpolatedDisplayOption.landscapeIconSize; iconBitmapSize = Utilities.pxFromDp(iconSize, dm); - iconTextSize = interpolatedDeviceProfileOut.iconTextSize; + iconTextSize = interpolatedDisplayOption.iconTextSize; fillResIconDpi = getLauncherIconDensity(iconBitmapSize); // If the partner customization apk contains any grid overrides, apply them @@ -210,7 +201,7 @@ public class InvariantDeviceProfile { InvariantDeviceProfile oldProfile = new InvariantDeviceProfile(this); // Re-init grid - initGrid(context); + initGrid(context, Utilities.getPrefs(context).getString(KEY_IDP_GRIP_NAME, null)); int changeFlags = 0; if (numRows != oldProfile.numRows || @@ -234,41 +225,53 @@ public class InvariantDeviceProfile { } } - ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles(Context context) { - ArrayList<InvariantDeviceProfile> profiles = new ArrayList<>(); + static ArrayList<DisplayOption> getPredefinedDeviceProfiles(Context context, String gridName) { + ArrayList<DisplayOption> profiles = new ArrayList<>(); try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) { final int depth = parser.getDepth(); int type; while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { - if ((type == XmlPullParser.START_TAG) && "profile".equals(parser.getName())) { - TypedArray a = context.obtainStyledAttributes( - Xml.asAttributeSet(parser), R.styleable.InvariantDeviceProfile); - int numRows = a.getInt(R.styleable.InvariantDeviceProfile_numRows, 0); - int numColumns = a.getInt(R.styleable.InvariantDeviceProfile_numColumns, 0); - float iconSize = a.getFloat(R.styleable.InvariantDeviceProfile_iconSize, 0); - profiles.add(new InvariantDeviceProfile( - a.getString(R.styleable.InvariantDeviceProfile_name), - a.getFloat(R.styleable.InvariantDeviceProfile_minWidthDps, 0), - a.getFloat(R.styleable.InvariantDeviceProfile_minHeightDps, 0), - numRows, - numColumns, - a.getInt(R.styleable.InvariantDeviceProfile_numFolderRows, numRows), - a.getInt(R.styleable.InvariantDeviceProfile_numFolderColumns, numColumns), - iconSize, - a.getFloat(R.styleable.InvariantDeviceProfile_landscapeIconSize, iconSize), - a.getFloat(R.styleable.InvariantDeviceProfile_iconTextSize, 0), - a.getInt(R.styleable.InvariantDeviceProfile_numHotseatIcons, numColumns), - a.getResourceId(R.styleable.InvariantDeviceProfile_defaultLayoutId, 0), - a.getResourceId(R.styleable.InvariantDeviceProfile_demoModeLayoutId, 0))); - a.recycle(); + if ((type == XmlPullParser.START_TAG) && "grid-option".equals(parser.getName())) { + + GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser)); + final int displayDepth = parser.getDepth(); + while (((type = parser.next()) != XmlPullParser.END_TAG || + parser.getDepth() > displayDepth) + && type != XmlPullParser.END_DOCUMENT) { + if ((type == XmlPullParser.START_TAG) && "display-option".equals( + parser.getName())) { + profiles.add(new DisplayOption( + gridOption, context, Xml.asAttributeSet(parser))); + } + } } } } catch (IOException|XmlPullParserException e) { throw new RuntimeException(e); } - return profiles; + + ArrayList<DisplayOption> filteredProfiles = new ArrayList<>(); + if (!TextUtils.isEmpty(gridName)) { + for (DisplayOption option : profiles) { + if (gridName.equals(option.grid.name)) { + filteredProfiles.add(option); + } + } + } + if (filteredProfiles.isEmpty()) { + // No grid found, use the default options + for (DisplayOption option : profiles) { + if (option.canBeDefault) { + filteredProfiles.add(option); + } + } + } + if (filteredProfiles.isEmpty()) { + throw new RuntimeException("No display option with canBeDefault=true"); + } + return filteredProfiles; } private int getLauncherIconDensity(int requiredSize) { @@ -307,60 +310,40 @@ public class InvariantDeviceProfile { } } - @Thunk float dist(float x0, float y0, float x1, float y1) { + private static float dist(float x0, float y0, float x1, float y1) { return (float) Math.hypot(x1 - x0, y1 - y0); } /** * Returns the closest device profiles ordered by closeness to the specified width and height */ - // Package private visibility for testing. - ArrayList<InvariantDeviceProfile> findClosestDeviceProfiles( - final float width, final float height, ArrayList<InvariantDeviceProfile> points) { - - // Sort the profiles by their closeness to the dimensions - ArrayList<InvariantDeviceProfile> pointsByNearness = points; - Collections.sort(pointsByNearness, new Comparator<InvariantDeviceProfile>() { - public int compare(InvariantDeviceProfile a, InvariantDeviceProfile b) { - return Float.compare(dist(width, height, a.minWidthDps, a.minHeightDps), - dist(width, height, b.minWidthDps, b.minHeightDps)); - } - }); - - return pointsByNearness; + @VisibleForTesting + static ArrayList<DisplayOption> sortByClosenessToSize( + float width, float height, ArrayList<DisplayOption> points) { + points.sort((a, b) -> + Float.compare(dist(width, height, a.minWidthDps, a.minHeightDps), + dist(width, height, b.minWidthDps, b.minHeightDps))); + return points; } - // Package private visibility for testing. - InvariantDeviceProfile invDistWeightedInterpolate(float width, float height, - ArrayList<InvariantDeviceProfile> points) { + @VisibleForTesting + static DisplayOption invDistWeightedInterpolate(float width, float height, + ArrayList<DisplayOption> points) { float weights = 0; - InvariantDeviceProfile p = points.get(0); + DisplayOption p = points.get(0); if (dist(width, height, p.minWidthDps, p.minHeightDps) == 0) { return p; } - InvariantDeviceProfile out = new InvariantDeviceProfile(); + DisplayOption out = new DisplayOption(); for (int i = 0; i < points.size() && i < KNEARESTNEIGHBOR; ++i) { - p = new InvariantDeviceProfile(points.get(i)); + p = points.get(i); float w = weight(width, height, p.minWidthDps, p.minHeightDps, WEIGHT_POWER); weights += w; - out.add(p.multiply(w)); + out.add(new DisplayOption().add(p).multiply(w)); } - return out.multiply(1.0f/weights); - } - - private void add(InvariantDeviceProfile p) { - iconSize += p.iconSize; - landscapeIconSize += p.landscapeIconSize; - iconTextSize += p.iconTextSize; - } - - private InvariantDeviceProfile multiply(float w) { - iconSize *= w; - landscapeIconSize *= w; - iconTextSize *= w; - return this; + return out.multiply(1.0f / weights); } public DeviceProfile getDeviceProfile(Context context) { @@ -368,7 +351,7 @@ public class InvariantDeviceProfile { == Configuration.ORIENTATION_LANDSCAPE ? landscapeProfile : portraitProfile; } - private float weight(float x0, float y0, float x1, float y1, float pow) { + private static float weight(float x0, float y0, float x1, float y1, float pow) { float d = dist(x0, y0, x1, y1); if (Float.compare(d, 0f) == 0) { return Float.POSITIVE_INFINITY; @@ -409,4 +392,94 @@ public class InvariantDeviceProfile { void onIdpChanged(int changeFlags, InvariantDeviceProfile profile); } + + + private static final class GridOption { + + private final String name; + private final int numRows; + private final int numColumns; + + private final int numFolderRows; + private final int numFolderColumns; + + private final int numHotseatIcons; + + private final int defaultLayoutId; + private final int demoModeLayoutId; + + GridOption(Context context, AttributeSet attrs) { + TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.GridDisplayOption); + name = a.getString(R.styleable.GridDisplayOption_name); + numRows = a.getInt(R.styleable.GridDisplayOption_numRows, 0); + numColumns = a.getInt(R.styleable.GridDisplayOption_numColumns, 0); + + defaultLayoutId = a.getResourceId( + R.styleable.GridDisplayOption_defaultLayoutId, 0); + demoModeLayoutId = a.getResourceId( + R.styleable.GridDisplayOption_demoModeLayoutId, defaultLayoutId); + numHotseatIcons = a.getInt( + R.styleable.GridDisplayOption_numHotseatIcons, numColumns); + numFolderRows = a.getInt( + R.styleable.GridDisplayOption_numFolderRows, numRows); + numFolderColumns = a.getInt( + R.styleable.GridDisplayOption_numFolderColumns, numColumns); + a.recycle(); + } + } + + private static final class DisplayOption { + private final GridOption grid; + + private final String name; + private final float minWidthDps; + private final float minHeightDps; + private final boolean canBeDefault; + + private float iconSize; + private float landscapeIconSize; + private float iconTextSize; + + DisplayOption(GridOption grid, Context context, AttributeSet attrs) { + this.grid = grid; + + TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.ProfileDisplayOption); + + name = a.getString(R.styleable.ProfileDisplayOption_name); + minWidthDps = a.getFloat(R.styleable.ProfileDisplayOption_minWidthDps, 0); + minHeightDps = a.getFloat(R.styleable.ProfileDisplayOption_minHeightDps, 0); + canBeDefault = a.getBoolean( + R.styleable.ProfileDisplayOption_canBeDefault, false); + + iconSize = a.getFloat(R.styleable.ProfileDisplayOption_iconSize, 0); + landscapeIconSize = a.getFloat(R.styleable.ProfileDisplayOption_landscapeIconSize, + iconSize); + iconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0); + a.recycle(); + } + + DisplayOption() { + grid = null; + name = null; + minWidthDps = 0; + minHeightDps = 0; + canBeDefault = false; + } + + private DisplayOption multiply(float w) { + iconSize *= w; + landscapeIconSize *= w; + iconTextSize *= w; + return this; + } + + private DisplayOption add(DisplayOption p) { + iconSize += p.iconSize; + landscapeIconSize += p.landscapeIconSize; + iconTextSize += p.iconTextSize; + return this; + } + } }
\ No newline at end of file diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 65f070327..a0f005c43 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -31,6 +31,7 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.Paint; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; @@ -587,6 +588,21 @@ public final class Utilities { handler.sendMessage(msg); } + /** + * Parses a string encoded using {@link #getPointString(int, int)} + */ + public static Point parsePoint(String point) { + String[] split = point.split(","); + return new Point(Integer.parseInt(split[0]), Integer.parseInt(split[1])); + } + + /** + * Encodes a point to string to that it can be persisted atomically. + */ + public static String getPointString(int x, int y) { + return String.format(Locale.ENGLISH, "%d,%d", x, y); + } + public interface Consumer<T> { void accept(T var1); } diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java index 2c1aa745f..289de1a4b 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTask.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java @@ -1,5 +1,8 @@ package com.android.launcher3.model; +import static com.android.launcher3.Utilities.getPointString; +import static com.android.launcher3.Utilities.parsePoint; + import android.content.ComponentName; import android.content.ContentProviderOperation; import android.content.ContentValues; @@ -877,15 +880,6 @@ public class GridSizeMigrationTask { return dup; } - private static Point parsePoint(String point) { - String[] split = point.split(","); - return new Point(Integer.parseInt(split[0]), Integer.parseInt(split[1])); - } - - private static String getPointString(int x, int y) { - return String.format(Locale.ENGLISH, "%d,%d", x, y); - } - public static void markForMigration( Context context, int gridX, int gridY, int hotseatSize) { Utilities.getPrefs(context).edit() diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java index e1b26980c..b389b145d 100644 --- a/src/com/android/launcher3/provider/ImportDataTask.java +++ b/src/com/android/launcher3/provider/ImportDataTask.java @@ -44,7 +44,6 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.Settings; import com.android.launcher3.LauncherSettings.WorkspaceScreens; -import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.compat.UserManagerCompat; @@ -378,18 +377,13 @@ public class ImportDataTask { return false; } - private static int getMyHotseatLayoutId(Context context) { - return LauncherAppState.getIDP(context).numHotseatIcons <= 5 - ? R.xml.dw_phone_hotseat - : R.xml.dw_tablet_hotseat; - } - /** * Extension of {@link DefaultLayoutParser} which only allows icons and shortcuts. */ private static class HotseatLayoutParser extends DefaultLayoutParser { public HotseatLayoutParser(Context context, LayoutParserCallback callback) { - super(context, null, callback, context.getResources(), getMyHotseatLayoutId(context)); + super(context, null, callback, context.getResources(), + LauncherAppState.getIDP(context).defaultLayoutId); } @Override @@ -434,6 +428,12 @@ public class ImportDataTask { // No need to add more items. return 0; } + if (!Integer.valueOf(Favorites.CONTAINER_HOTSEAT) + .equals(values.getAsInteger(Favorites.CONTAINER))) { + // Ignore items which are not for hotseat. + return 0; + } + Intent intent; try { intent = Intent.parseUri(values.getAsString(Favorites.INTENT), 0); |