1 /*
2 * Copyright (C) 2016 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 #include "format/proto/ProtoSerialize.h"
18
19 #include "ResourceUtils.h"
20 #include "format/proto/ProtoDeserialize.h"
21 #include "test/Test.h"
22
23 using ::android::StringPiece;
24 using ::testing::Eq;
25 using ::testing::IsEmpty;
26 using ::testing::NotNull;
27 using ::testing::SizeIs;
28 using ::testing::StrEq;
29
30 namespace aapt {
31
32 class MockFileCollection : public io::IFileCollection {
33 public:
34 MOCK_METHOD1(FindFile, io::IFile*(const StringPiece& path));
35 MOCK_METHOD0(Iterator, std::unique_ptr<io::IFileCollectionIterator>());
36 };
37
TEST(ProtoSerializeTest,SerializeSinglePackage)38 TEST(ProtoSerializeTest, SerializeSinglePackage) {
39 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
40 std::unique_ptr<ResourceTable> table =
41 test::ResourceTableBuilder()
42 .SetPackageId("com.app.a", 0x7f)
43 .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
44 .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
45 .AddString("com.app.a:string/text", {}, "hi")
46 .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
47 .SetSymbolState("com.app.a:bool/foo", {}, Visibility::Level::kUndefined,
48 true /*allow_new*/)
49 .Build();
50
51 Visibility public_symbol;
52 public_symbol.level = Visibility::Level::kPublic;
53 ASSERT_TRUE(table->SetVisibilityWithId(test::ParseNameOrDie("com.app.a:layout/main"),
54 public_symbol, ResourceId(0x7f020000),
55 context->GetDiagnostics()));
56
57 Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
58 ASSERT_THAT(id, NotNull());
59
60 // Make a plural.
61 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
62 plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one"));
63 ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"), ConfigDescription{},
64 {}, std::move(plural), context->GetDiagnostics()));
65
66 // Make a styled string.
67 StyleString style_string;
68 style_string.str = "hello";
69 style_string.spans.push_back(Span{"b", 0u, 4u});
70 ASSERT_TRUE(
71 table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
72 util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
73 context->GetDiagnostics()));
74
75 // Make a resource with different products.
76 ASSERT_TRUE(table->AddResource(
77 test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), {},
78 test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u), context->GetDiagnostics()));
79 ASSERT_TRUE(table->AddResource(
80 test::ParseNameOrDie("com.app.a:integer/one"), test::ParseConfigOrDie("land"), "tablet",
81 test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u), context->GetDiagnostics()));
82
83 // Make a reference with both resource name and resource ID.
84 // The reference should point to a resource outside of this table to test that both name and id
85 // get serialized.
86 Reference expected_ref;
87 expected_ref.name = test::ParseNameOrDie("android:layout/main");
88 expected_ref.id = ResourceId(0x01020000);
89 ASSERT_TRUE(table->AddResource(
90 test::ParseNameOrDie("com.app.a:layout/abc"), ConfigDescription::DefaultConfig(), {},
91 util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
92
93 // Make an overlayable resource.
94 ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"),
95 Overlayable{}, test::GetDiagnostics()));
96
97 pb::ResourceTable pb_table;
98 SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
99
100 test::TestFile file_a("res/layout/main.xml");
101 MockFileCollection files;
102 EXPECT_CALL(files, FindFile(Eq("res/layout/main.xml")))
103 .WillRepeatedly(::testing::Return(&file_a));
104
105 ResourceTable new_table;
106 std::string error;
107 ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
108 EXPECT_THAT(error, IsEmpty());
109
110 Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
111 ASSERT_THAT(new_id, NotNull());
112 EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
113
114 Maybe<ResourceTable::SearchResult> result =
115 new_table.FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
116 ASSERT_TRUE(result);
117
118 EXPECT_THAT(result.value().type->visibility_level, Eq(Visibility::Level::kPublic));
119 EXPECT_THAT(result.value().entry->visibility.level, Eq(Visibility::Level::kPublic));
120
121 result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
122 ASSERT_TRUE(result);
123 EXPECT_THAT(result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
124 EXPECT_TRUE(result.value().entry->allow_new);
125
126 // Find the product-dependent values
127 BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
128 &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
129 ASSERT_THAT(prim, NotNull());
130 EXPECT_THAT(prim->value.data, Eq(123u));
131
132 prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
133 &new_table, "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
134 ASSERT_THAT(prim, NotNull());
135 EXPECT_THAT(prim->value.data, Eq(321u));
136
137 Reference* actual_ref = test::GetValue<Reference>(&new_table, "com.app.a:layout/abc");
138 ASSERT_THAT(actual_ref, NotNull());
139 ASSERT_TRUE(actual_ref->name);
140 ASSERT_TRUE(actual_ref->id);
141 EXPECT_THAT(*actual_ref, Eq(expected_ref));
142
143 FileReference* actual_file_ref =
144 test::GetValue<FileReference>(&new_table, "com.app.a:layout/main");
145 ASSERT_THAT(actual_file_ref, NotNull());
146 EXPECT_THAT(actual_file_ref->file, Eq(&file_a));
147
148 StyledString* actual_styled_str =
149 test::GetValue<StyledString>(&new_table, "com.app.a:string/styled");
150 ASSERT_THAT(actual_styled_str, NotNull());
151 EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
152 ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
153 EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
154 EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
155 EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
156
157 Maybe<ResourceTable::SearchResult> search_result =
158 new_table.FindResource(test::ParseNameOrDie("com.app.a:integer/overlayable"));
159 ASSERT_TRUE(search_result);
160 ASSERT_THAT(search_result.value().entry, NotNull());
161 EXPECT_TRUE(search_result.value().entry->overlayable);
162 }
163
TEST(ProtoSerializeTest,SerializeAndDeserializeXml)164 TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
165 xml::Element element;
166 element.line_number = 22;
167 element.column_number = 23;
168 element.name = "element";
169 element.namespace_uri = "uri://";
170
171 xml::NamespaceDecl decl;
172 decl.prefix = "android";
173 decl.uri = xml::kSchemaAndroid;
174 decl.line_number = 21;
175 decl.column_number = 24;
176
177 element.namespace_decls.push_back(decl);
178
179 xml::Attribute attr;
180 attr.name = "name";
181 attr.namespace_uri = xml::kSchemaAndroid;
182 attr.value = "23dp";
183 attr.compiled_attribute = xml::AaptAttribute(Attribute{}, ResourceId(0x01010000));
184 attr.compiled_value =
185 ResourceUtils::TryParseItemForAttribute(attr.value, android::ResTable_map::TYPE_DIMENSION);
186 attr.compiled_value->SetSource(Source().WithLine(25));
187 element.attributes.push_back(std::move(attr));
188
189 std::unique_ptr<xml::Text> text = util::make_unique<xml::Text>();
190 text->line_number = 25;
191 text->column_number = 3;
192 text->text = "hey there";
193 element.AppendChild(std::move(text));
194
195 std::unique_ptr<xml::Element> child = util::make_unique<xml::Element>();
196 child->name = "child";
197
198 text = util::make_unique<xml::Text>();
199 text->text = "woah there";
200 child->AppendChild(std::move(text));
201
202 element.AppendChild(std::move(child));
203
204 pb::XmlNode pb_xml;
205 SerializeXmlToPb(element, &pb_xml);
206
207 StringPool pool;
208 xml::Element actual_el;
209 std::string error;
210 ASSERT_TRUE(DeserializeXmlFromPb(pb_xml, &actual_el, &pool, &error));
211 ASSERT_THAT(error, IsEmpty());
212
213 EXPECT_THAT(actual_el.name, StrEq("element"));
214 EXPECT_THAT(actual_el.namespace_uri, StrEq("uri://"));
215 EXPECT_THAT(actual_el.line_number, Eq(22u));
216 EXPECT_THAT(actual_el.column_number, Eq(23u));
217
218 ASSERT_THAT(actual_el.namespace_decls, SizeIs(1u));
219 const xml::NamespaceDecl& actual_decl = actual_el.namespace_decls[0];
220 EXPECT_THAT(actual_decl.prefix, StrEq("android"));
221 EXPECT_THAT(actual_decl.uri, StrEq(xml::kSchemaAndroid));
222 EXPECT_THAT(actual_decl.line_number, Eq(21u));
223 EXPECT_THAT(actual_decl.column_number, Eq(24u));
224
225 ASSERT_THAT(actual_el.attributes, SizeIs(1u));
226 const xml::Attribute& actual_attr = actual_el.attributes[0];
227 EXPECT_THAT(actual_attr.name, StrEq("name"));
228 EXPECT_THAT(actual_attr.namespace_uri, StrEq(xml::kSchemaAndroid));
229 EXPECT_THAT(actual_attr.value, StrEq("23dp"));
230
231 ASSERT_THAT(actual_attr.compiled_value, NotNull());
232 const BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(actual_attr.compiled_value.get());
233 ASSERT_THAT(prim, NotNull());
234 EXPECT_THAT(prim->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
235
236 ASSERT_TRUE(actual_attr.compiled_attribute);
237 ASSERT_TRUE(actual_attr.compiled_attribute.value().id);
238
239 ASSERT_THAT(actual_el.children, SizeIs(2u));
240 const xml::Text* child_text = xml::NodeCast<xml::Text>(actual_el.children[0].get());
241 ASSERT_THAT(child_text, NotNull());
242 const xml::Element* child_el = xml::NodeCast<xml::Element>(actual_el.children[1].get());
243 ASSERT_THAT(child_el, NotNull());
244
245 EXPECT_THAT(child_text->line_number, Eq(25u));
246 EXPECT_THAT(child_text->column_number, Eq(3u));
247 EXPECT_THAT(child_text->text, StrEq("hey there"));
248
249 EXPECT_THAT(child_el->name, StrEq("child"));
250 ASSERT_THAT(child_el->children, SizeIs(1u));
251
252 child_text = xml::NodeCast<xml::Text>(child_el->children[0].get());
253 ASSERT_THAT(child_text, NotNull());
254 EXPECT_THAT(child_text->text, StrEq("woah there"));
255 }
256
TEST(ProtoSerializeTest,SerializeAndDeserializePrimitives)257 TEST(ProtoSerializeTest, SerializeAndDeserializePrimitives) {
258 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
259 std::unique_ptr<ResourceTable> table =
260 test::ResourceTableBuilder()
261 .AddValue("android:bool/boolean_true",
262 test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, true))
263 .AddValue("android:bool/boolean_false",
264 test::BuildPrimitive(android::Res_value::TYPE_INT_BOOLEAN, false))
265 .AddValue("android:color/color_rgb8", ResourceUtils::TryParseColor("#AABBCC"))
266 .AddValue("android:color/color_argb8", ResourceUtils::TryParseColor("#11223344"))
267 .AddValue("android:color/color_rgb4", ResourceUtils::TryParseColor("#DEF"))
268 .AddValue("android:color/color_argb4", ResourceUtils::TryParseColor("#5678"))
269 .AddValue("android:integer/integer_444", ResourceUtils::TryParseInt("444"))
270 .AddValue("android:integer/integer_neg_333", ResourceUtils::TryParseInt("-333"))
271 .AddValue("android:integer/hex_int_abcd", ResourceUtils::TryParseInt("0xABCD"))
272 .AddValue("android:dimen/dimen_1.39mm", ResourceUtils::TryParseFloat("1.39mm"))
273 .AddValue("android:fraction/fraction_27", ResourceUtils::TryParseFloat("27%"))
274 .AddValue("android:dimen/neg_2.3in", ResourceUtils::TryParseFloat("-2.3in"))
275 .AddValue("android:integer/null", ResourceUtils::MakeEmpty())
276 .Build();
277
278 pb::ResourceTable pb_table;
279 SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
280
281 test::TestFile file_a("res/layout/main.xml");
282 MockFileCollection files;
283 EXPECT_CALL(files, FindFile(Eq("res/layout/main.xml")))
284 .WillRepeatedly(::testing::Return(&file_a));
285
286 ResourceTable new_table;
287 std::string error;
288 ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
289 EXPECT_THAT(error, IsEmpty());
290
291 BinaryPrimitive* bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
292 &new_table, "android:bool/boolean_true", ConfigDescription::DefaultConfig(), "");
293 ASSERT_THAT(bp, NotNull());
294 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN));
295 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseBool("true")->value.data));
296
297 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:bool/boolean_false",
298 ConfigDescription::DefaultConfig(), "");
299 ASSERT_THAT(bp, NotNull());
300 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN));
301 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseBool("false")->value.data));
302
303 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_rgb8",
304 ConfigDescription::DefaultConfig(), "");
305 ASSERT_THAT(bp, NotNull());
306 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_RGB8));
307 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#AABBCC")->value.data));
308
309 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_argb8",
310 ConfigDescription::DefaultConfig(), "");
311 ASSERT_THAT(bp, NotNull());
312 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_ARGB8));
313 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#11223344")->value.data));
314
315 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_rgb4",
316 ConfigDescription::DefaultConfig(), "");
317 ASSERT_THAT(bp, NotNull());
318 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_RGB4));
319 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#DEF")->value.data));
320
321 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:color/color_argb4",
322 ConfigDescription::DefaultConfig(), "");
323 ASSERT_THAT(bp, NotNull());
324 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_COLOR_ARGB4));
325 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseColor("#5678")->value.data));
326
327 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:integer/integer_444",
328 ConfigDescription::DefaultConfig(), "");
329 ASSERT_THAT(bp, NotNull());
330 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
331 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("444")->value.data));
332
333 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
334 &new_table, "android:integer/integer_neg_333", ConfigDescription::DefaultConfig(), "");
335 ASSERT_THAT(bp, NotNull());
336 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_DEC));
337 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("-333")->value.data));
338
339 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
340 &new_table, "android:integer/hex_int_abcd", ConfigDescription::DefaultConfig(), "");
341 ASSERT_THAT(bp, NotNull());
342 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_INT_HEX));
343 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseInt("0xABCD")->value.data));
344
345 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:dimen/dimen_1.39mm",
346 ConfigDescription::DefaultConfig(), "");
347 ASSERT_THAT(bp, NotNull());
348 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
349 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("1.39mm")->value.data));
350
351 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(
352 &new_table, "android:fraction/fraction_27", ConfigDescription::DefaultConfig(), "");
353 ASSERT_THAT(bp, NotNull());
354 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_FRACTION));
355 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("27%")->value.data));
356
357 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:dimen/neg_2.3in",
358 ConfigDescription::DefaultConfig(), "");
359 ASSERT_THAT(bp, NotNull());
360 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_DIMENSION));
361 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::TryParseFloat("-2.3in")->value.data));
362
363 bp = test::GetValueForConfigAndProduct<BinaryPrimitive>(&new_table, "android:integer/null",
364 ConfigDescription::DefaultConfig(), "");
365 ASSERT_THAT(bp, NotNull());
366 EXPECT_THAT(bp->value.dataType, Eq(android::Res_value::TYPE_NULL));
367 EXPECT_THAT(bp->value.data, Eq(ResourceUtils::MakeEmpty()->value.data));
368 }
369
ExpectConfigSerializes(const StringPiece & config_str)370 static void ExpectConfigSerializes(const StringPiece& config_str) {
371 const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
372 pb::Configuration pb_config;
373 SerializeConfig(expected_config, &pb_config);
374
375 ConfigDescription actual_config;
376 std::string error;
377 ASSERT_TRUE(DeserializeConfigFromPb(pb_config, &actual_config, &error));
378 ASSERT_THAT(error, IsEmpty());
379 EXPECT_EQ(expected_config, actual_config);
380 }
381
TEST(ProtoSerializeTest,SerializeDeserializeConfiguration)382 TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) {
383 ExpectConfigSerializes("");
384
385 ExpectConfigSerializes("mcc123");
386
387 ExpectConfigSerializes("mnc123");
388
389 ExpectConfigSerializes("en");
390 ExpectConfigSerializes("en-rGB");
391 ExpectConfigSerializes("b+en+GB");
392
393 ExpectConfigSerializes("ldltr");
394 ExpectConfigSerializes("ldrtl");
395
396 ExpectConfigSerializes("sw3600dp");
397
398 ExpectConfigSerializes("w300dp");
399
400 ExpectConfigSerializes("h400dp");
401
402 ExpectConfigSerializes("small");
403 ExpectConfigSerializes("normal");
404 ExpectConfigSerializes("large");
405 ExpectConfigSerializes("xlarge");
406
407 ExpectConfigSerializes("long");
408 ExpectConfigSerializes("notlong");
409
410 ExpectConfigSerializes("round");
411 ExpectConfigSerializes("notround");
412
413 ExpectConfigSerializes("widecg");
414 ExpectConfigSerializes("nowidecg");
415
416 ExpectConfigSerializes("highdr");
417 ExpectConfigSerializes("lowdr");
418
419 ExpectConfigSerializes("port");
420 ExpectConfigSerializes("land");
421 ExpectConfigSerializes("square");
422
423 ExpectConfigSerializes("desk");
424 ExpectConfigSerializes("car");
425 ExpectConfigSerializes("television");
426 ExpectConfigSerializes("appliance");
427 ExpectConfigSerializes("watch");
428 ExpectConfigSerializes("vrheadset");
429
430 ExpectConfigSerializes("night");
431 ExpectConfigSerializes("notnight");
432
433 ExpectConfigSerializes("300dpi");
434 ExpectConfigSerializes("hdpi");
435
436 ExpectConfigSerializes("notouch");
437 ExpectConfigSerializes("stylus");
438 ExpectConfigSerializes("finger");
439
440 ExpectConfigSerializes("keysexposed");
441 ExpectConfigSerializes("keyshidden");
442 ExpectConfigSerializes("keyssoft");
443
444 ExpectConfigSerializes("nokeys");
445 ExpectConfigSerializes("qwerty");
446 ExpectConfigSerializes("12key");
447
448 ExpectConfigSerializes("navhidden");
449 ExpectConfigSerializes("navexposed");
450
451 ExpectConfigSerializes("nonav");
452 ExpectConfigSerializes("dpad");
453 ExpectConfigSerializes("trackball");
454 ExpectConfigSerializes("wheel");
455
456 ExpectConfigSerializes("300x200");
457
458 ExpectConfigSerializes("v8");
459
460 ExpectConfigSerializes(
461 "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-"
462 "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
463 }
464
465 } // namespace aapt
466