1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.android.launcher3.responsive
18
19 import android.content.res.TypedArray
20 import android.content.res.XmlResourceParser
21 import android.util.Xml
22 import com.android.launcher3.R
23 import com.android.launcher3.util.ResourceHelper
24 import java.io.IOException
25 import org.xmlpull.v1.XmlPullParser
26 import org.xmlpull.v1.XmlPullParserException
27
28 class ResponsiveSpecsParser(private val resourceHelper: ResourceHelper) {
29
parseSizeSpecsnull30 private fun parseSizeSpecs(parser: XmlResourceParser): Map<String, SizeSpec> {
31 val parentName = parser.name
32 parser.next()
33
34 val result = mutableMapOf<String, SizeSpec>()
35 while (parser.eventType != XmlPullParser.END_DOCUMENT && parser.name != parentName) {
36 if (parser.eventType == XmlResourceParser.START_TAG) {
37 result[parser.name] = SizeSpec.create(resourceHelper, Xml.asAttributeSet(parser))
38 }
39 parser.next()
40 }
41
42 return result
43 }
44
parseXMLnull45 fun <T> parseXML(
46 tagName: String,
47 map: (attributes: TypedArray, sizeSpecs: Map<String, SizeSpec>) -> T
48 ): List<T> {
49 val parser: XmlResourceParser = resourceHelper.getXml()
50
51 try {
52 val list = mutableListOf<T>()
53
54 var eventType = parser.eventType
55 while (eventType != XmlPullParser.END_DOCUMENT) {
56 if (eventType == XmlResourceParser.START_TAG && parser.name == tagName) {
57 val attrs =
58 resourceHelper.obtainStyledAttributes(
59 Xml.asAttributeSet(parser),
60 R.styleable.ResponsiveSpec
61 )
62
63 val sizeSpecs = parseSizeSpecs(parser)
64 list += map(attrs, sizeSpecs)
65 attrs.recycle()
66 }
67
68 eventType = parser.next()
69 }
70
71 parser.close()
72
73 return list
74 } catch (e: Exception) {
75 when (e) {
76 is NoSuchFieldException,
77 is IOException,
78 is XmlPullParserException ->
79 throw RuntimeException("Failure parsing specs file.", e)
80 else -> throw e
81 }
82 } finally {
83 parser.close()
84 }
85 }
86 }
87
getOrErrornull88 fun Map<String, SizeSpec>.getOrError(key: String): SizeSpec {
89 return this.getOrElse(key) { error("Attr '$key' must be defined.") }
90 }
91