Loading quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ import android.graphics.Rect import android.graphics.RectF import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.launcher3.DeviceProfileBaseTest import com.android.launcher3.FakeInvariantDeviceProfileTest import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT import com.android.quickstep.views.TaskView.FullscreenDrawParams Loading @@ -36,7 +36,7 @@ import org.mockito.Mockito.mock /** Test for FullscreenDrawParams class. */ @SmallTest @RunWith(AndroidJUnit4::class) class FullscreenDrawParamsTest : DeviceProfileBaseTest() { class FullscreenDrawParamsTest : FakeInvariantDeviceProfileTest() { private val TASK_SCALE = 0.7f private var mThumbnailData: ThumbnailData = mock(ThumbnailData::class.java) Loading quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ package com.android.quickstep import android.graphics.Rect import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.launcher3.DeviceProfileBaseTest import com.android.launcher3.FakeInvariantDeviceProfileTest import com.android.launcher3.util.WindowBounds import com.google.common.truth.Truth.assertThat import org.junit.Test Loading @@ -26,7 +26,7 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class HotseatWidthCalculationTest : DeviceProfileBaseTest() { class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { /** * This is a case when after setting the hotseat, the space needs to be recalculated but it Loading res/values/attrs.xml +15 −0 Original line number Diff line number Diff line Loading @@ -224,6 +224,21 @@ <attr name="alignOnIcon" format="boolean" /> </declare-styleable> <!-- Responsive grids attributes --> <declare-styleable name="WorkspaceSpec"> <attr name="specType" format="integer"> <enum name="height" value="0" /> <enum name="width" value="1" /> </attr> <attr name="maxAvailableSize" format="dimension" /> </declare-styleable> <declare-styleable name="SpecSize"> <attr name="fixedSize" format="dimension" /> <attr name="ofAvailableSpace" format="float" /> <attr name="ofRemainderSpace" format="float" /> </declare-styleable> <declare-styleable name="ProfileDisplayOption"> <attr name="name" /> <attr name="minWidthDps" format="float" /> Loading src/com/android/launcher3/util/ResourceHelper.kt 0 → 100644 +37 −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.util import android.content.Context import android.content.res.TypedArray import android.content.res.XmlResourceParser import android.util.AttributeSet import kotlin.IntArray /** * This class is a helper that can be subclassed in tests to provide a way to parse attributes * correctly. */ open class ResourceHelper(private val context: Context, private val specsFileId: Int) { open fun getXml(): XmlResourceParser { return context.resources.getXml(specsFileId) } open fun obtainStyledAttributes(attrs: AttributeSet, styleId: IntArray): TypedArray { return context.obtainStyledAttributes(attrs, styleId) } } src/com/android/launcher3/workspace/WorkspaceSpecs.kt 0 → 100644 +252 −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.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.util.ResourceHelper import java.io.IOException import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParserException private const val TAG = "WorkspaceSpecs" class WorkspaceSpecs(resourceHelper: ResourceHelper) { object XmlTags { const val WORKSPACE_SPECS = "workspaceSpecs" const val WORKSPACE_SPEC = "workspaceSpec" const val START_PADDING = "startPadding" const val END_PADDING = "endPadding" const val GUTTER = "gutter" const val CELL_SIZE = "cellSize" } val workspaceHeightSpecList = mutableListOf<WorkspaceSpec>() val workspaceWidthSpecList = mutableListOf<WorkspaceSpec>() init { try { val parser: XmlResourceParser = resourceHelper.getXml() val depth = parser.depth var type: Int while ( (parser.next().also { type = it } != XmlPullParser.END_TAG || parser.depth > depth) && type != XmlPullParser.END_DOCUMENT ) { if (type == XmlPullParser.START_TAG && XmlTags.WORKSPACE_SPECS == parser.name) { val displayDepth = parser.depth while ( (parser.next().also { type = it } != XmlPullParser.END_TAG || parser.depth > displayDepth) && type != XmlPullParser.END_DOCUMENT ) { if ( type == XmlPullParser.START_TAG && XmlTags.WORKSPACE_SPEC == parser.name ) { val attrs = resourceHelper.obtainStyledAttributes( Xml.asAttributeSet(parser), R.styleable.WorkspaceSpec ) val maxAvailableSize = attrs.getDimensionPixelSize( R.styleable.WorkspaceSpec_maxAvailableSize, 0 ) val specType = WorkspaceSpec.SpecType.values()[ attrs.getInt( R.styleable.WorkspaceSpec_specType, WorkspaceSpec.SpecType.HEIGHT.ordinal ) ] attrs.recycle() var startPadding: SizeSpec? = null var endPadding: SizeSpec? = null var gutter: SizeSpec? = null var cellSize: SizeSpec? = null val limitDepth = parser.depth while ( (parser.next().also { type = it } != XmlPullParser.END_TAG || parser.depth > limitDepth) && type != XmlPullParser.END_DOCUMENT ) { val attr: AttributeSet = Xml.asAttributeSet(parser) if (type == XmlPullParser.START_TAG) { when (parser.name) { XmlTags.START_PADDING -> { startPadding = SizeSpec(resourceHelper, attr) } XmlTags.END_PADDING -> { endPadding = SizeSpec(resourceHelper, attr) } XmlTags.GUTTER -> { gutter = SizeSpec(resourceHelper, attr) } XmlTags.CELL_SIZE -> { cellSize = SizeSpec(resourceHelper, attr) } } } } if ( startPadding == null || endPadding == null || gutter == null || cellSize == null ) { throw IllegalStateException( "All attributes in workspaceSpec must be defined" ) } val workspaceSpec = WorkspaceSpec( maxAvailableSize, specType, startPadding, endPadding, gutter, cellSize ) if (workspaceSpec.isValid()) { if (workspaceSpec.specType == WorkspaceSpec.SpecType.HEIGHT) workspaceHeightSpecList.add(workspaceSpec) else workspaceWidthSpecList.add(workspaceSpec) } else { throw IllegalStateException("Invalid workspaceSpec found.") } } } if (workspaceWidthSpecList.isEmpty() || workspaceHeightSpecList.isEmpty()) { throw IllegalStateException( "WorkspaceSpecs is incomplete - " + "height list size = ${workspaceHeightSpecList.size}; " + "width list size = ${workspaceWidthSpecList.size}." ) } } } parser.close() } catch (e: Exception) { when (e) { is IOException, is XmlPullParserException -> { throw RuntimeException("Failure parsing workspaces specs file.", e) } else -> throw e } } } } data class WorkspaceSpec( val maxAvailableSize: Int, val specType: SpecType, val startPadding: SizeSpec, val endPadding: SizeSpec, val gutter: SizeSpec, val cellSize: SizeSpec ) { enum class SpecType { HEIGHT, WIDTH } fun isValid(): Boolean { if (maxAvailableSize <= 0) { Log.e(TAG, "WorkspaceSpec#isValid - maxAvailableSize <= 0") return false } // All specs need to be individually valid if (!allSpecsAreValid()) { Log.e(TAG, "WorkspaceSpec#isValid - !allSpecsAreValid()") return false } return true } 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)" } } Loading
quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ import android.graphics.Rect import android.graphics.RectF import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.launcher3.DeviceProfileBaseTest import com.android.launcher3.FakeInvariantDeviceProfileTest import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT import com.android.quickstep.views.TaskView.FullscreenDrawParams Loading @@ -36,7 +36,7 @@ import org.mockito.Mockito.mock /** Test for FullscreenDrawParams class. */ @SmallTest @RunWith(AndroidJUnit4::class) class FullscreenDrawParamsTest : DeviceProfileBaseTest() { class FullscreenDrawParamsTest : FakeInvariantDeviceProfileTest() { private val TASK_SCALE = 0.7f private var mThumbnailData: ThumbnailData = mock(ThumbnailData::class.java) Loading
quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt +2 −2 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ package com.android.quickstep import android.graphics.Rect import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.launcher3.DeviceProfileBaseTest import com.android.launcher3.FakeInvariantDeviceProfileTest import com.android.launcher3.util.WindowBounds import com.google.common.truth.Truth.assertThat import org.junit.Test Loading @@ -26,7 +26,7 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class HotseatWidthCalculationTest : DeviceProfileBaseTest() { class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { /** * This is a case when after setting the hotseat, the space needs to be recalculated but it Loading
res/values/attrs.xml +15 −0 Original line number Diff line number Diff line Loading @@ -224,6 +224,21 @@ <attr name="alignOnIcon" format="boolean" /> </declare-styleable> <!-- Responsive grids attributes --> <declare-styleable name="WorkspaceSpec"> <attr name="specType" format="integer"> <enum name="height" value="0" /> <enum name="width" value="1" /> </attr> <attr name="maxAvailableSize" format="dimension" /> </declare-styleable> <declare-styleable name="SpecSize"> <attr name="fixedSize" format="dimension" /> <attr name="ofAvailableSpace" format="float" /> <attr name="ofRemainderSpace" format="float" /> </declare-styleable> <declare-styleable name="ProfileDisplayOption"> <attr name="name" /> <attr name="minWidthDps" format="float" /> Loading
src/com/android/launcher3/util/ResourceHelper.kt 0 → 100644 +37 −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.util import android.content.Context import android.content.res.TypedArray import android.content.res.XmlResourceParser import android.util.AttributeSet import kotlin.IntArray /** * This class is a helper that can be subclassed in tests to provide a way to parse attributes * correctly. */ open class ResourceHelper(private val context: Context, private val specsFileId: Int) { open fun getXml(): XmlResourceParser { return context.resources.getXml(specsFileId) } open fun obtainStyledAttributes(attrs: AttributeSet, styleId: IntArray): TypedArray { return context.obtainStyledAttributes(attrs, styleId) } }
src/com/android/launcher3/workspace/WorkspaceSpecs.kt 0 → 100644 +252 −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.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.util.ResourceHelper import java.io.IOException import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParserException private const val TAG = "WorkspaceSpecs" class WorkspaceSpecs(resourceHelper: ResourceHelper) { object XmlTags { const val WORKSPACE_SPECS = "workspaceSpecs" const val WORKSPACE_SPEC = "workspaceSpec" const val START_PADDING = "startPadding" const val END_PADDING = "endPadding" const val GUTTER = "gutter" const val CELL_SIZE = "cellSize" } val workspaceHeightSpecList = mutableListOf<WorkspaceSpec>() val workspaceWidthSpecList = mutableListOf<WorkspaceSpec>() init { try { val parser: XmlResourceParser = resourceHelper.getXml() val depth = parser.depth var type: Int while ( (parser.next().also { type = it } != XmlPullParser.END_TAG || parser.depth > depth) && type != XmlPullParser.END_DOCUMENT ) { if (type == XmlPullParser.START_TAG && XmlTags.WORKSPACE_SPECS == parser.name) { val displayDepth = parser.depth while ( (parser.next().also { type = it } != XmlPullParser.END_TAG || parser.depth > displayDepth) && type != XmlPullParser.END_DOCUMENT ) { if ( type == XmlPullParser.START_TAG && XmlTags.WORKSPACE_SPEC == parser.name ) { val attrs = resourceHelper.obtainStyledAttributes( Xml.asAttributeSet(parser), R.styleable.WorkspaceSpec ) val maxAvailableSize = attrs.getDimensionPixelSize( R.styleable.WorkspaceSpec_maxAvailableSize, 0 ) val specType = WorkspaceSpec.SpecType.values()[ attrs.getInt( R.styleable.WorkspaceSpec_specType, WorkspaceSpec.SpecType.HEIGHT.ordinal ) ] attrs.recycle() var startPadding: SizeSpec? = null var endPadding: SizeSpec? = null var gutter: SizeSpec? = null var cellSize: SizeSpec? = null val limitDepth = parser.depth while ( (parser.next().also { type = it } != XmlPullParser.END_TAG || parser.depth > limitDepth) && type != XmlPullParser.END_DOCUMENT ) { val attr: AttributeSet = Xml.asAttributeSet(parser) if (type == XmlPullParser.START_TAG) { when (parser.name) { XmlTags.START_PADDING -> { startPadding = SizeSpec(resourceHelper, attr) } XmlTags.END_PADDING -> { endPadding = SizeSpec(resourceHelper, attr) } XmlTags.GUTTER -> { gutter = SizeSpec(resourceHelper, attr) } XmlTags.CELL_SIZE -> { cellSize = SizeSpec(resourceHelper, attr) } } } } if ( startPadding == null || endPadding == null || gutter == null || cellSize == null ) { throw IllegalStateException( "All attributes in workspaceSpec must be defined" ) } val workspaceSpec = WorkspaceSpec( maxAvailableSize, specType, startPadding, endPadding, gutter, cellSize ) if (workspaceSpec.isValid()) { if (workspaceSpec.specType == WorkspaceSpec.SpecType.HEIGHT) workspaceHeightSpecList.add(workspaceSpec) else workspaceWidthSpecList.add(workspaceSpec) } else { throw IllegalStateException("Invalid workspaceSpec found.") } } } if (workspaceWidthSpecList.isEmpty() || workspaceHeightSpecList.isEmpty()) { throw IllegalStateException( "WorkspaceSpecs is incomplete - " + "height list size = ${workspaceHeightSpecList.size}; " + "width list size = ${workspaceWidthSpecList.size}." ) } } } parser.close() } catch (e: Exception) { when (e) { is IOException, is XmlPullParserException -> { throw RuntimeException("Failure parsing workspaces specs file.", e) } else -> throw e } } } } data class WorkspaceSpec( val maxAvailableSize: Int, val specType: SpecType, val startPadding: SizeSpec, val endPadding: SizeSpec, val gutter: SizeSpec, val cellSize: SizeSpec ) { enum class SpecType { HEIGHT, WIDTH } fun isValid(): Boolean { if (maxAvailableSize <= 0) { Log.e(TAG, "WorkspaceSpec#isValid - maxAvailableSize <= 0") return false } // All specs need to be individually valid if (!allSpecsAreValid()) { Log.e(TAG, "WorkspaceSpec#isValid - !allSpecsAreValid()") return false } return true } 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)" } }