Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d282d595 authored by Thales Lima's avatar Thales Lima Committed by Android (Google) Code Review
Browse files

Merge "Calculate sizes for responsive grid" into udc-dev

parents ee311b3e c98b7815
Loading
Loading
Loading
Loading
+20 −5
Original line number Diff line number Diff line
@@ -55,7 +55,10 @@ import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.ResourceHelper;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.workspace.CalculatedWorkspaceSpec;
import com.android.launcher3.workspace.WorkspaceSpecs;

import java.io.PrintWriter;
import java.util.Locale;
@@ -101,9 +104,14 @@ public class DeviceProfile {
    public final float aspectRatio;

    public final boolean isScalableGrid;
    public final boolean isResponsiveGrid;
    private final int mTypeIndex;

    // Responsive grid
    private final boolean mIsResponsiveGrid;
    private WorkspaceSpecs mWorkspaceSpecs;
    private CalculatedWorkspaceSpec mResponsiveWidthSpec;
    private CalculatedWorkspaceSpec mResponsiveHeightSpec;

    /**
     * The maximum amount of left/right workspace padding as a percentage of the screen width.
     * To be clear, this means that up to 7% of the screen width can be used as left padding, and
@@ -294,9 +302,8 @@ public class DeviceProfile {
        this.rotationHint = windowBounds.rotationHint;
        mInsets.set(windowBounds.insets);

        // TODO(b/241386436):
        //  for testing that the flag works only, shouldn't change any launcher behaviour
        isResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE;
        // TODO(b/241386436): shouldn't change any launcher behaviour
        mIsResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE;

        isScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
        // Determine device posture.
@@ -335,6 +342,14 @@ public class DeviceProfile {
            }
        }

        if (mIsResponsiveGrid) {
            mWorkspaceSpecs = new WorkspaceSpecs(new ResourceHelper(context, inv.workspaceSpecsId));
            mResponsiveWidthSpec = mWorkspaceSpecs.getCalculatedWidthSpec(inv.numColumns,
                    availableWidthPx);
            mResponsiveHeightSpec = mWorkspaceSpecs.getCalculatedHeightSpec(inv.numRows,
                    availableHeightPx);
        }

        if (DisplayController.isTransientTaskbar(context)) {
            float invTransientIconSizeDp = inv.transientTaskbarIconSize[mTypeIndex];
            taskbarIconSize = pxFromDp(invTransientIconSizeDp, mMetrics);
@@ -1582,7 +1597,7 @@ public class DeviceProfile {

        writer.println(prefix + "\taspectRatio:" + aspectRatio);

        writer.println(prefix + "\tisResponsiveGrid:" + isResponsiveGrid);
        writer.println(prefix + "\tisResponsiveGrid:" + mIsResponsiveGrid);
        writer.println(prefix + "\tisScalableGrid:" + isScalableGrid);

        writer.println(prefix + "\tinv.numRows: " + inv.numRows);
+73 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.util.Xml
import com.android.launcher3.R
import com.android.launcher3.util.ResourceHelper
import java.io.IOException
import kotlin.math.roundToInt
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException

@@ -159,6 +160,77 @@ class WorkspaceSpecs(resourceHelper: ResourceHelper) {
            }
        }
    }

    /**
     * Returns the CalculatedWorkspaceSpec for width, based on the available width and the
     * WorkspaceSpecs.
     */
    fun getCalculatedWidthSpec(columns: Int, availableWidth: Int): CalculatedWorkspaceSpec {
        val widthSpec = workspaceWidthSpecList.first { availableWidth <= it.maxAvailableSize }

        return CalculatedWorkspaceSpec(availableWidth, columns, widthSpec)
    }

    /**
     * Returns the CalculatedWorkspaceSpec for height, based on the available height and the
     * WorkspaceSpecs.
     */
    fun getCalculatedHeightSpec(rows: Int, availableHeight: Int): CalculatedWorkspaceSpec {
        val heightSpec = workspaceHeightSpecList.first { availableHeight <= it.maxAvailableSize }

        return CalculatedWorkspaceSpec(availableHeight, rows, heightSpec)
    }
}

class CalculatedWorkspaceSpec(
    val availableSpace: Int,
    val cells: Int,
    val workspaceSpec: WorkspaceSpec
) {
    var startPaddingPx: Int = 0
        private set
    var endPaddingPx: Int = 0
        private set
    var gutterPx: Int = 0
        private set
    var cellSizePx: Int = 0
        private set
    init {
        // Calculate all fixed size first
        if (workspaceSpec.startPadding.fixedSize > 0)
            startPaddingPx = workspaceSpec.startPadding.fixedSize.roundToInt()
        if (workspaceSpec.endPadding.fixedSize > 0)
            endPaddingPx = workspaceSpec.endPadding.fixedSize.roundToInt()
        if (workspaceSpec.gutter.fixedSize > 0)
            gutterPx = workspaceSpec.gutter.fixedSize.roundToInt()
        if (workspaceSpec.cellSize.fixedSize > 0)
            cellSizePx = workspaceSpec.cellSize.fixedSize.roundToInt()

        // Calculate all available space next
        if (workspaceSpec.startPadding.ofAvailableSpace > 0)
            startPaddingPx =
                (workspaceSpec.startPadding.ofAvailableSpace * availableSpace).roundToInt()
        if (workspaceSpec.endPadding.ofAvailableSpace > 0)
            endPaddingPx = (workspaceSpec.endPadding.ofAvailableSpace * availableSpace).roundToInt()
        if (workspaceSpec.gutter.ofAvailableSpace > 0)
            gutterPx = (workspaceSpec.gutter.ofAvailableSpace * availableSpace).roundToInt()
        if (workspaceSpec.cellSize.ofAvailableSpace > 0)
            cellSizePx = (workspaceSpec.cellSize.ofAvailableSpace * availableSpace).roundToInt()

        // Calculate remainder space last
        val gutters = cells - 1
        val usedSpace = startPaddingPx + endPaddingPx + (gutterPx * gutters) + (cellSizePx * cells)
        val remainderSpace = availableSpace - usedSpace
        if (workspaceSpec.startPadding.ofRemainderSpace > 0)
            startPaddingPx =
                (workspaceSpec.startPadding.ofRemainderSpace * remainderSpace).roundToInt()
        if (workspaceSpec.endPadding.ofRemainderSpace > 0)
            endPaddingPx = (workspaceSpec.endPadding.ofRemainderSpace * remainderSpace).roundToInt()
        if (workspaceSpec.gutter.ofRemainderSpace > 0)
            gutterPx = (workspaceSpec.gutter.ofRemainderSpace * remainderSpace).roundToInt()
        if (workspaceSpec.cellSize.ofRemainderSpace > 0)
            cellSizePx = (workspaceSpec.cellSize.ofRemainderSpace * remainderSpace).roundToInt()
    }
}

data class WorkspaceSpec(
@@ -220,7 +292,7 @@ class SizeSpec(resourceHelper: ResourceHelper, attrs: AttributeSet) {

    fun isValid(): Boolean {
        // All attributes are empty
        if (fixedSize <= 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f) {
        if (fixedSize < 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f) {
            Log.e(TAG, "SizeSpec#isValid - all attributes are empty")
            return false
        }
+27 −25
Original line number Diff line number Diff line
@@ -15,43 +15,45 @@
  -->

<workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto">
    <!-- 584 grid height -->
    <workspaceSpec
        launcher:specType="height"
        launcher:maxAvailableSize="648dp">
        <startPadding
            launcher:ofAvailableSpace="0.0125" />
        <endPadding
            launcher:ofAvailableSpace="0.05" />
        <gutter
            launcher:fixedSize="16dp" />
        <cellSize
            launcher:ofRemainderSpace="0.2" />
        launcher:maxAvailableSize="584dp">
        <startPadding launcher:fixedSize="0dp" />
        <endPadding launcher:fixedSize="32dp" />
        <gutter launcher:fixedSize="16dp" />
        <cellSize launcher:ofAvailableSpace="0.15808" />
    </workspaceSpec>

    <!-- 584 grid height + 28 remainder space -->
    <workspaceSpec
        launcher:specType="height"
        launcher:maxAvailableSize="612dp">
        <startPadding launcher:fixedSize="0dp" />
        <endPadding launcher:ofRemainderSpace="1" />
        <gutter launcher:fixedSize="16dp" />
        <cellSize launcher:fixedSize="104dp" />
    </workspaceSpec>

    <workspaceSpec
        launcher:specType="height"
        launcher:maxAvailableSize="9999dp">
        <startPadding
            launcher:ofAvailableSpace="0.0306" />
        <endPadding
            launcher:ofAvailableSpace="0.068" />
        <gutter
            launcher:fixedSize="16dp" />
        <cellSize
            launcher:ofRemainderSpace="0.2" />
        <startPadding launcher:fixedSize="8dp" />
        <endPadding launcher:ofRemainderSpace="1" />
        <gutter launcher:fixedSize="16dp" />
        <cellSize launcher:fixedSize="104dp" />
    </workspaceSpec>

    <!--  TODO(b/241386436): other specs here for height ...  -->

    <!-- Width spec is always the same -->
    <workspaceSpec
        launcher:specType="width"
        launcher:maxAvailableSize="9999dp">
        <startPadding
            launcher:ofRemainderSpace="0.21436227" />
        <endPadding
            launcher:ofRemainderSpace="0.21436227" />
        <gutter
            launcher:ofRemainderSpace="0.11425509" />
        <cellSize
            launcher:fixedSize="120dp" />
        <startPadding launcher:fixedSize="22dp" />
        <endPadding launcher:fixedSize="22dp" />
        <gutter launcher:fixedSize="16dp" />
        <cellSize launcher:ofRemainderSpace="0.25" />
    </workspaceSpec>

</workspaceSpecs>
+1 −1
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ abstract class AbstractDeviceProfileTest {

    class DeviceSpec(
        val naturalSize: Pair<Int, Int>,
        val densityDpi: Int,
        var densityDpi: Int,
        val statusBarNaturalPx: Int,
        val statusBarRotatedPx: Int,
        val gesturePx: Int,
+107 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.workspace

import android.content.Context
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.AbstractDeviceProfileTest
import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class CalculatedWorkspaceSpecTest : AbstractDeviceProfileTest() {
    override val runningContext: Context = InstrumentationRegistry.getInstrumentation().context

    /**
     * This test tests:
     * - (height spec) gets the correct breakpoint from the XML - skips the first 2 breakpoints
     * - (height spec) do the correct calculations for available space and fixed size
     * - (width spec) do the correct calculations for remainder space and fixed size
     */
    @Test
    fun normalPhone_returnsThirdBreakpointSpec() {
        val deviceSpec = deviceSpecs["phone"]!!
        initializeVarsForPhone(deviceSpec)

        val availableWidth = deviceSpec.naturalSize.first
        // Hotseat size is roughly 495px on a real device,
        // it doesn't need to be precise on unit tests
        val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 495

        val workspaceSpecs =
            WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
        val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
        val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)

        assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
        assertThat(widthSpec.cells).isEqualTo(4)
        assertThat(widthSpec.startPaddingPx).isEqualTo(58)
        assertThat(widthSpec.endPaddingPx).isEqualTo(58)
        assertThat(widthSpec.gutterPx).isEqualTo(42)
        assertThat(widthSpec.cellSizePx).isEqualTo(210)

        assertThat(heightSpec.availableSpace).isEqualTo(availableHeight)
        assertThat(heightSpec.cells).isEqualTo(5)
        assertThat(heightSpec.startPaddingPx).isEqualTo(21)
        assertThat(heightSpec.endPaddingPx).isEqualTo(233)
        assertThat(heightSpec.gutterPx).isEqualTo(42)
        assertThat(heightSpec.cellSizePx).isEqualTo(273)
    }

    /**
     * This test tests:
     * - (height spec) gets the correct breakpoint from the XML - use the first breakpoint
     * - (height spec) do the correct calculations for remainder space and fixed size
     * - (width spec) do the correct calculations for remainder space and fixed size
     */
    @Test
    fun smallPhone_returnsFirstBreakpointSpec() {
        val deviceSpec = deviceSpecs["phone"]!!
        deviceSpec.densityDpi = 540 // larger display size
        initializeVarsForPhone(deviceSpec)

        val availableWidth = deviceSpec.naturalSize.first
        // Hotseat size is roughly 640px on a real device,
        // it doesn't need to be precise on unit tests
        val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 640

        val workspaceSpecs =
            WorkspaceSpecs(TestResourceHelper(context!!, TestR.xml.valid_workspace_file))
        val widthSpec = workspaceSpecs.getCalculatedWidthSpec(4, availableWidth)
        val heightSpec = workspaceSpecs.getCalculatedHeightSpec(5, availableHeight)

        assertThat(widthSpec.availableSpace).isEqualTo(availableWidth)
        assertThat(widthSpec.cells).isEqualTo(4)
        assertThat(widthSpec.startPaddingPx).isEqualTo(74)
        assertThat(widthSpec.endPaddingPx).isEqualTo(74)
        assertThat(widthSpec.gutterPx).isEqualTo(54)
        assertThat(widthSpec.cellSizePx).isEqualTo(193)

        assertThat(heightSpec.availableSpace).isEqualTo(availableHeight)
        assertThat(heightSpec.cells).isEqualTo(5)
        assertThat(heightSpec.startPaddingPx).isEqualTo(0)
        assertThat(heightSpec.endPaddingPx).isEqualTo(108)
        assertThat(heightSpec.gutterPx).isEqualTo(54)
        assertThat(heightSpec.cellSizePx).isEqualTo(260)
    }
}
Loading