Loading res/values/attrs.xml +3 −1 Original line number Diff line number Diff line Loading @@ -204,6 +204,7 @@ <!-- File that contains the specs for the workspace. Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled --> <attr name="workspaceSpecsId" format="reference" /> <!-- By default all categories are enabled --> <attr name="deviceCategory" format="integer"> <!-- Enable on phone only --> Loading Loading @@ -251,10 +252,11 @@ <attr name="maxAvailableSize" format="dimension" /> </declare-styleable> <declare-styleable name="SpecSize"> <declare-styleable name="SizeSpec"> <attr name="fixedSize" format="dimension" /> <attr name="ofAvailableSpace" format="float" /> <attr name="ofRemainderSpace" format="float" /> <attr name="matchWorkspace" format="boolean" /> </declare-styleable> <declare-styleable name="ProfileDisplayOption"> Loading src/com/android/launcher3/responsive/SizeSpec.kt 0 → 100644 +73 −0 Original line number Diff line number Diff line package com.android.launcher3.responsive import android.content.res.TypedArray import android.util.AttributeSet import android.util.Log import android.util.TypedValue import com.android.launcher3.R import com.android.launcher3.util.ResourceHelper data class SizeSpec( val fixedSize: Float, val ofAvailableSpace: Float, val ofRemainderSpace: Float, val matchWorkspace: Boolean ) { fun isValid(): Boolean { // All attributes are empty if (fixedSize < 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f && !matchWorkspace) { Log.e(TAG, "SizeSpec#isValid - all attributes are empty") return false } // More than one attribute is filled val attrCount = (if (fixedSize > 0) 1 else 0) + (if (ofAvailableSpace > 0) 1 else 0) + (if (ofRemainderSpace > 0) 1 else 0) + (if (matchWorkspace) 1 else 0) if (attrCount > 1) { Log.e(TAG, "SizeSpec#isValid - more than one attribute is filled") return false } // Values should be between 0 and 1 if (ofAvailableSpace !in 0f..1f || ofRemainderSpace !in 0f..1f) { Log.e(TAG, "SizeSpec#isValid - values should be between 0 and 1") return false } // Invalid fixed size if (fixedSize < 0f) { Log.e(TAG, "SizeSpec#isValid - values should be bigger or equal to zero.") return false } return true } companion object { private const val TAG = "WorkspaceSpecs::SizeSpec" private fun getValue(a: TypedArray, index: Int): Float { return when (a.getType(index)) { TypedValue.TYPE_DIMENSION -> a.getDimensionPixelSize(index, 0).toFloat() TypedValue.TYPE_FLOAT -> a.getFloat(index, 0f) else -> 0f } } fun create(resourceHelper: ResourceHelper, attrs: AttributeSet): SizeSpec { val styledAttrs = resourceHelper.obtainStyledAttributes(attrs, R.styleable.SizeSpec) val fixedSize = getValue(styledAttrs, R.styleable.SizeSpec_fixedSize) val ofAvailableSpace = getValue(styledAttrs, R.styleable.SizeSpec_ofAvailableSpace) val ofRemainderSpace = getValue(styledAttrs, R.styleable.SizeSpec_ofRemainderSpace) val matchWorkspace = styledAttrs.getBoolean(R.styleable.SizeSpec_matchWorkspace, false) styledAttrs.recycle() return SizeSpec(fixedSize, ofAvailableSpace, ofRemainderSpace, matchWorkspace) } } } src/com/android/launcher3/workspace/WorkspaceSpecs.kt +13 −63 Original line number Diff line number Diff line Loading @@ -16,13 +16,12 @@ package com.android.launcher3.workspace import android.content.res.TypedArray import android.content.res.XmlResourceParser import android.util.AttributeSet import android.util.Log import android.util.TypedValue import android.util.Xml import com.android.launcher3.R import com.android.launcher3.responsive.SizeSpec import com.android.launcher3.util.ResourceHelper import java.io.IOException import kotlin.math.roundToInt Loading Loading @@ -95,16 +94,16 @@ class WorkspaceSpecs(resourceHelper: ResourceHelper) { if (type == XmlPullParser.START_TAG) { when (parser.name) { XmlTags.START_PADDING -> { startPadding = SizeSpec(resourceHelper, attr) startPadding = SizeSpec.create(resourceHelper, attr) } XmlTags.END_PADDING -> { endPadding = SizeSpec(resourceHelper, attr) endPadding = SizeSpec.create(resourceHelper, attr) } XmlTags.GUTTER -> { gutter = SizeSpec(resourceHelper, attr) gutter = SizeSpec.create(resourceHelper, attr) } XmlTags.CELL_SIZE -> { cellSize = SizeSpec(resourceHelper, attr) cellSize = SizeSpec.create(resourceHelper, attr) } } } Loading Loading @@ -270,61 +269,12 @@ data class WorkspaceSpec( } private fun allSpecsAreValid(): Boolean = startPadding.isValid() && endPadding.isValid() && gutter.isValid() && cellSize.isValid() } class SizeSpec(resourceHelper: ResourceHelper, attrs: AttributeSet) { val fixedSize: Float val ofAvailableSpace: Float val ofRemainderSpace: Float init { val styledAttrs = resourceHelper.obtainStyledAttributes(attrs, R.styleable.SpecSize) fixedSize = getValue(styledAttrs, R.styleable.SpecSize_fixedSize) ofAvailableSpace = getValue(styledAttrs, R.styleable.SpecSize_ofAvailableSpace) ofRemainderSpace = getValue(styledAttrs, R.styleable.SpecSize_ofRemainderSpace) styledAttrs.recycle() } private fun getValue(a: TypedArray, index: Int): Float { if (a.getType(index) == TypedValue.TYPE_DIMENSION) { return a.getDimensionPixelSize(index, 0).toFloat() } else if (a.getType(index) == TypedValue.TYPE_FLOAT) { return a.getFloat(index, 0f) } return 0f } fun isValid(): Boolean { // All attributes are empty if (fixedSize < 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f) { Log.e(TAG, "SizeSpec#isValid - all attributes are empty") return false } // More than one attribute is filled val attrCount = (if (fixedSize > 0) 1 else 0) + (if (ofAvailableSpace > 0) 1 else 0) + (if (ofRemainderSpace > 0) 1 else 0) if (attrCount > 1) { Log.e(TAG, "SizeSpec#isValid - more than one attribute is filled") return false } // Values should be between 0 and 1 if (ofAvailableSpace !in 0f..1f || ofRemainderSpace !in 0f..1f) { Log.e(TAG, "SizeSpec#isValid - values should be between 0 and 1") return false } return true } override fun toString(): String { return "SizeSpec(fixedSize=$fixedSize, ofAvailableSpace=$ofAvailableSpace, " + "ofRemainderSpace=$ofRemainderSpace)" } startPadding.isValid() && endPadding.isValid() && gutter.isValid() && cellSize.isValid() && !startPadding.matchWorkspace && !endPadding.matchWorkspace && !gutter.matchWorkspace && !cellSize.matchWorkspace } tests/res/values/attrs.xml +2 −2 Original line number Diff line number Diff line Loading @@ -26,10 +26,10 @@ <attr name="maxAvailableSize" format="dimension" /> </declare-styleable> <declare-styleable name="SpecSize"> <declare-styleable name="SizeSpec"> <attr name="fixedSize" format="dimension" /> <attr name="ofAvailableSpace" format="float" /> <attr name="ofRemainderSpace" format="float" /> <attr name="matchWorkspace" format="boolean" /> </declare-styleable> </resources> tests/res/xml/invalid_workspace_file_case_4.xml 0 → 100644 +58 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?><!-- ~ 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. --> <workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto"> <workspaceSpec launcher:specType="height" launcher:maxAvailableSize="648dp"> <startPadding launcher:ofAvailableSpace="0.0125" /> <endPadding launcher:ofAvailableSpace="0.05" /> <!-- value in workspace spec using matchWorkspace --> <gutter launcher:matchWorkspace="true" /> <cellSize launcher:ofRemainderSpace="0.2" /> </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" /> </workspaceSpec> <!-- 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" /> </workspaceSpec> </workspaceSpecs> Loading
res/values/attrs.xml +3 −1 Original line number Diff line number Diff line Loading @@ -204,6 +204,7 @@ <!-- File that contains the specs for the workspace. Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled --> <attr name="workspaceSpecsId" format="reference" /> <!-- By default all categories are enabled --> <attr name="deviceCategory" format="integer"> <!-- Enable on phone only --> Loading Loading @@ -251,10 +252,11 @@ <attr name="maxAvailableSize" format="dimension" /> </declare-styleable> <declare-styleable name="SpecSize"> <declare-styleable name="SizeSpec"> <attr name="fixedSize" format="dimension" /> <attr name="ofAvailableSpace" format="float" /> <attr name="ofRemainderSpace" format="float" /> <attr name="matchWorkspace" format="boolean" /> </declare-styleable> <declare-styleable name="ProfileDisplayOption"> Loading
src/com/android/launcher3/responsive/SizeSpec.kt 0 → 100644 +73 −0 Original line number Diff line number Diff line package com.android.launcher3.responsive import android.content.res.TypedArray import android.util.AttributeSet import android.util.Log import android.util.TypedValue import com.android.launcher3.R import com.android.launcher3.util.ResourceHelper data class SizeSpec( val fixedSize: Float, val ofAvailableSpace: Float, val ofRemainderSpace: Float, val matchWorkspace: Boolean ) { fun isValid(): Boolean { // All attributes are empty if (fixedSize < 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f && !matchWorkspace) { Log.e(TAG, "SizeSpec#isValid - all attributes are empty") return false } // More than one attribute is filled val attrCount = (if (fixedSize > 0) 1 else 0) + (if (ofAvailableSpace > 0) 1 else 0) + (if (ofRemainderSpace > 0) 1 else 0) + (if (matchWorkspace) 1 else 0) if (attrCount > 1) { Log.e(TAG, "SizeSpec#isValid - more than one attribute is filled") return false } // Values should be between 0 and 1 if (ofAvailableSpace !in 0f..1f || ofRemainderSpace !in 0f..1f) { Log.e(TAG, "SizeSpec#isValid - values should be between 0 and 1") return false } // Invalid fixed size if (fixedSize < 0f) { Log.e(TAG, "SizeSpec#isValid - values should be bigger or equal to zero.") return false } return true } companion object { private const val TAG = "WorkspaceSpecs::SizeSpec" private fun getValue(a: TypedArray, index: Int): Float { return when (a.getType(index)) { TypedValue.TYPE_DIMENSION -> a.getDimensionPixelSize(index, 0).toFloat() TypedValue.TYPE_FLOAT -> a.getFloat(index, 0f) else -> 0f } } fun create(resourceHelper: ResourceHelper, attrs: AttributeSet): SizeSpec { val styledAttrs = resourceHelper.obtainStyledAttributes(attrs, R.styleable.SizeSpec) val fixedSize = getValue(styledAttrs, R.styleable.SizeSpec_fixedSize) val ofAvailableSpace = getValue(styledAttrs, R.styleable.SizeSpec_ofAvailableSpace) val ofRemainderSpace = getValue(styledAttrs, R.styleable.SizeSpec_ofRemainderSpace) val matchWorkspace = styledAttrs.getBoolean(R.styleable.SizeSpec_matchWorkspace, false) styledAttrs.recycle() return SizeSpec(fixedSize, ofAvailableSpace, ofRemainderSpace, matchWorkspace) } } }
src/com/android/launcher3/workspace/WorkspaceSpecs.kt +13 −63 Original line number Diff line number Diff line Loading @@ -16,13 +16,12 @@ package com.android.launcher3.workspace import android.content.res.TypedArray import android.content.res.XmlResourceParser import android.util.AttributeSet import android.util.Log import android.util.TypedValue import android.util.Xml import com.android.launcher3.R import com.android.launcher3.responsive.SizeSpec import com.android.launcher3.util.ResourceHelper import java.io.IOException import kotlin.math.roundToInt Loading Loading @@ -95,16 +94,16 @@ class WorkspaceSpecs(resourceHelper: ResourceHelper) { if (type == XmlPullParser.START_TAG) { when (parser.name) { XmlTags.START_PADDING -> { startPadding = SizeSpec(resourceHelper, attr) startPadding = SizeSpec.create(resourceHelper, attr) } XmlTags.END_PADDING -> { endPadding = SizeSpec(resourceHelper, attr) endPadding = SizeSpec.create(resourceHelper, attr) } XmlTags.GUTTER -> { gutter = SizeSpec(resourceHelper, attr) gutter = SizeSpec.create(resourceHelper, attr) } XmlTags.CELL_SIZE -> { cellSize = SizeSpec(resourceHelper, attr) cellSize = SizeSpec.create(resourceHelper, attr) } } } Loading Loading @@ -270,61 +269,12 @@ data class WorkspaceSpec( } private fun allSpecsAreValid(): Boolean = startPadding.isValid() && endPadding.isValid() && gutter.isValid() && cellSize.isValid() } class SizeSpec(resourceHelper: ResourceHelper, attrs: AttributeSet) { val fixedSize: Float val ofAvailableSpace: Float val ofRemainderSpace: Float init { val styledAttrs = resourceHelper.obtainStyledAttributes(attrs, R.styleable.SpecSize) fixedSize = getValue(styledAttrs, R.styleable.SpecSize_fixedSize) ofAvailableSpace = getValue(styledAttrs, R.styleable.SpecSize_ofAvailableSpace) ofRemainderSpace = getValue(styledAttrs, R.styleable.SpecSize_ofRemainderSpace) styledAttrs.recycle() } private fun getValue(a: TypedArray, index: Int): Float { if (a.getType(index) == TypedValue.TYPE_DIMENSION) { return a.getDimensionPixelSize(index, 0).toFloat() } else if (a.getType(index) == TypedValue.TYPE_FLOAT) { return a.getFloat(index, 0f) } return 0f } fun isValid(): Boolean { // All attributes are empty if (fixedSize < 0f && ofAvailableSpace <= 0f && ofRemainderSpace <= 0f) { Log.e(TAG, "SizeSpec#isValid - all attributes are empty") return false } // More than one attribute is filled val attrCount = (if (fixedSize > 0) 1 else 0) + (if (ofAvailableSpace > 0) 1 else 0) + (if (ofRemainderSpace > 0) 1 else 0) if (attrCount > 1) { Log.e(TAG, "SizeSpec#isValid - more than one attribute is filled") return false } // Values should be between 0 and 1 if (ofAvailableSpace !in 0f..1f || ofRemainderSpace !in 0f..1f) { Log.e(TAG, "SizeSpec#isValid - values should be between 0 and 1") return false } return true } override fun toString(): String { return "SizeSpec(fixedSize=$fixedSize, ofAvailableSpace=$ofAvailableSpace, " + "ofRemainderSpace=$ofRemainderSpace)" } startPadding.isValid() && endPadding.isValid() && gutter.isValid() && cellSize.isValid() && !startPadding.matchWorkspace && !endPadding.matchWorkspace && !gutter.matchWorkspace && !cellSize.matchWorkspace }
tests/res/values/attrs.xml +2 −2 Original line number Diff line number Diff line Loading @@ -26,10 +26,10 @@ <attr name="maxAvailableSize" format="dimension" /> </declare-styleable> <declare-styleable name="SpecSize"> <declare-styleable name="SizeSpec"> <attr name="fixedSize" format="dimension" /> <attr name="ofAvailableSpace" format="float" /> <attr name="ofRemainderSpace" format="float" /> <attr name="matchWorkspace" format="boolean" /> </declare-styleable> </resources>
tests/res/xml/invalid_workspace_file_case_4.xml 0 → 100644 +58 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?><!-- ~ 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. --> <workspaceSpecs xmlns:launcher="http://schemas.android.com/apk/res-auto"> <workspaceSpec launcher:specType="height" launcher:maxAvailableSize="648dp"> <startPadding launcher:ofAvailableSpace="0.0125" /> <endPadding launcher:ofAvailableSpace="0.05" /> <!-- value in workspace spec using matchWorkspace --> <gutter launcher:matchWorkspace="true" /> <cellSize launcher:ofRemainderSpace="0.2" /> </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" /> </workspaceSpec> <!-- 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" /> </workspaceSpec> </workspaceSpecs>