1#[macro_use]
2extern crate yaserde_derive;
3
4mod action;
5mod activity;
6mod activity_alias;
7mod application;
8mod attribute_list;
9mod category;
10mod compatible_screens;
11mod data;
12pub mod error;
13mod grant_uri_permission;
14mod instrumentation;
15mod intent_filter;
16mod layout;
17mod manifest;
18mod meta_data;
19mod path_permission;
20mod permission;
21mod permission_group;
22mod permission_tree;
23mod profileable;
24mod provider;
25mod queries;
26mod receiver;
27mod resources;
28mod service;
29mod supports_gl_texture;
30mod supports_screens;
31mod ui_options;
32mod uses_configuration;
33mod uses_feature;
34mod uses_library;
35mod uses_native_library;
36mod uses_permission;
37mod uses_permission_sdk_23;
38mod uses_sdk;
39mod var_or_bool;
40
41pub use action::*;
42pub use activity::*;
43pub use activity_alias::*;
44pub use application::*;
45pub use attribute_list::*;
46pub use category::*;
47pub use compatible_screens::*;
48pub use data::*;
49use error::{Error, Result};
50pub use grant_uri_permission::*;
51pub use instrumentation::*;
52pub use intent_filter::*;
53pub use layout::*;
54pub use manifest::*;
55pub use meta_data::*;
56pub use path_permission::*;
57pub use permission::*;
58pub use permission_group::*;
59pub use permission_tree::*;
60pub use profileable::*;
61pub use provider::*;
62pub use queries::*;
63pub use receiver::*;
64pub use resources::*;
65pub use service::*;
66pub use supports_gl_texture::*;
67pub use supports_screens::*;
68pub use ui_options::*;
69pub use uses_configuration::*;
70pub use uses_feature::*;
71pub use uses_library::*;
72pub use uses_native_library::UsesNativeLibrary;
73pub use uses_permission::*;
74pub use uses_permission_sdk_23::*;
75pub use uses_sdk::*;
76pub use var_or_bool::*;
77
78pub fn from_str(s: &str) -> Result<AndroidManifest> {
81 yaserde::de::from_str(s).map_err(Error::FailedToDeserialize)
82}
83
84pub fn from_reader<R: std::io::Read>(reader: R) -> Result<AndroidManifest> {
87 yaserde::de::from_reader(reader).map_err(Error::FailedToDeserialize)
88}
89
90pub fn to_string(manifest: &AndroidManifest) -> Result<String> {
93 yaserde::ser::to_string(manifest).map_err(Error::FailedToSerialize)
94}
95
96pub fn to_string_pretty(manifest: &AndroidManifest) -> Result<String> {
99 let config = yaserde::ser::Config {
100 perform_indent: true,
101 write_document_declaration: true,
102 indent_string: None,
103 };
104 yaserde::ser::to_string_with_config(manifest, &config).map_err(Error::FailedToSerialize)
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn test_complex_manifest_deserialize() {
113 let given_xml = r#"<?xml version="1.0" encoding="utf-8"?>
114 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
115 package="org.domokit.gcm"
116 android:versionCode="4"
117 android:versionName="0.0.4">
118 <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
119 <uses-permission android:name="android.permission.INTERNET" />
120
121 <uses-permission android:name="android.permission.WAKE_LOCK" />
122 <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
123
124 <permission android:name="org.domokit.gcm.permission.C2D_MESSAGE"
125 android:protectionLevel="signature" />
126 <uses-permission android:name="org.domokit.gcm.permission.C2D_MESSAGE" />
127
128 <application android:label="gcm" android:name="org.domokit.sky.shell.SkyApplication" android:usesCleartextTraffic="${usesCleartextTraffic}">
129 <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
130 android:hardwareAccelerated="true"
131 android:launchMode="singleTask"
132 android:name="org.domokit.sky.shell.SkyActivity"
133 android:theme="@android:style/Theme.Black.NoTitleBar">
134 <intent-filter>
135 <action android:name="android.intent.action.MAIN" />
136 <category android:name="android.intent.category.LAUNCHER" />
137 </intent-filter>
138 </activity>
139 <service
140 android:name="org.domokit.sky.shell.UpdateService"
141 android:exported="false"
142 android:process=":remote"/>
143 <receiver
144 android:name="com.google.android.gms.gcm.GcmReceiver"
145 android:exported="true"
146 android:permission="com.google.android.c2dm.permission.SEND" >
147 <intent-filter>
148 <action android:name="com.google.android.c2dm.intent.RECEIVE" />
149 <category android:name="org.domokit.sky.shell" />
150 </intent-filter>
151 </receiver>
152 <service
153 android:name="org.domokit.gcm.GcmListenerService"
154 android:exported="false" >
155 <intent-filter>
156 <action android:name="com.google.android.c2dm.intent.RECEIVE" />
157 </intent-filter>
158 </service>
159 <service
160 android:name="org.domokit.gcm.InstanceIDListenerService"
161 android:exported="false">
162 <intent-filter>
163 <action android:name="com.google.android.gms.iid.InstanceID"/>
164 </intent-filter>
165 </service>
166 <service
167 android:name="org.domokit.gcm.RegistrationIntentService"
168 android:exported="false">
169 </service>
170 </application>
171 </manifest>"#;
172 let expected_manifest = AndroidManifest {
173 package: "org.domokit.gcm".to_string(),
174 version_code: Some(4),
175 version_name: Some("0.0.4".to_string()),
176 application: Application {
177 label: Some(StringResourceOrString::string("gcm")),
178 name: Some("org.domokit.sky.shell.SkyApplication".to_string()),
179 uses_cleartext_traffic: Some("${usesCleartextTraffic}".into()),
180 activity: vec![Activity {
181 config_changes: AttributeList::from_vec(vec![
182 ConfigChanges::Orientation,
183 ConfigChanges::KeyboardHidden,
184 ConfigChanges::Keyboard,
185 ConfigChanges::ScreenSize,
186 ]),
187 hardware_accelerated: Some(true.into()),
188 launch_mode: Some(LaunchMode::SingleTask),
189 name: "org.domokit.sky.shell.SkyActivity".to_string(),
190 theme: Some(StyleResource::new(
191 "Theme.Black.NoTitleBar",
192 Some("android".to_string()),
193 )),
194 intent_filter: vec![IntentFilter {
195 action: vec![Action {
196 name: Some("android.intent.action.MAIN".to_string()),
197 }],
198 category: vec![Category {
199 name: Some("android.intent.category.LAUNCHER".to_string()),
200 }],
201 ..Default::default()
202 }],
203 ..Default::default()
204 }],
205 service: vec![
206 Service {
207 exported: Some(false.into()),
208 name: "org.domokit.sky.shell.UpdateService".to_string(),
209 process: Some(":remote".to_string()),
210 ..Default::default()
211 },
212 Service {
213 exported: Some(false.into()),
214 name: "org.domokit.gcm.GcmListenerService".to_string(),
215 intent_filter: vec![IntentFilter {
216 action: vec![Action {
217 name: Some("com.google.android.c2dm.intent.RECEIVE".to_string()),
218 }],
219 ..Default::default()
220 }],
221 ..Default::default()
222 },
223 Service {
224 exported: Some(false.into()),
225 name: "org.domokit.gcm.InstanceIDListenerService".to_string(),
226 intent_filter: vec![IntentFilter {
227 action: vec![Action {
228 name: Some("com.google.android.gms.iid.InstanceID".to_string()),
229 }],
230 ..Default::default()
231 }],
232 ..Default::default()
233 },
234 Service {
235 exported: Some(false.into()),
236 name: "org.domokit.gcm.RegistrationIntentService".to_string(),
237 ..Default::default()
238 },
239 ],
240 receiver: vec![Receiver {
241 exported: Some(true.into()),
242 name: "com.google.android.gms.gcm.GcmReceiver".to_string(),
243 permission: Some("com.google.android.c2dm.permission.SEND".to_string()),
244 intent_filter: vec![IntentFilter {
245 action: vec![Action {
246 name: Some("com.google.android.c2dm.intent.RECEIVE".to_string()),
247 }],
248 category: vec![Category {
249 name: Some("org.domokit.sky.shell".to_string()),
250 }],
251 ..Default::default()
252 }],
253 ..Default::default()
254 }],
255 ..Default::default()
256 },
257 uses_sdk: Some(UsesSdk {
258 min_sdk_version: Some(14),
259 target_sdk_version: Some(21),
260 ..Default::default()
261 }),
262 permission: vec![Permission {
263 name: Some("org.domokit.gcm.permission.C2D_MESSAGE".to_string()),
264 protection_level: Some(ProtectionLevel::Signature),
265 ..Default::default()
266 }],
267 uses_permission: vec![
268 UsesPermission {
269 name: Some("android.permission.INTERNET".to_string()),
270 ..Default::default()
271 },
272 UsesPermission {
273 name: Some("android.permission.WAKE_LOCK".to_string()),
274 ..Default::default()
275 },
276 UsesPermission {
277 name: Some("com.google.android.c2dm.permission.RECEIVE".to_string()),
278 ..Default::default()
279 },
280 UsesPermission {
281 name: Some("org.domokit.gcm.permission.C2D_MESSAGE".to_string()),
282 ..Default::default()
283 },
284 ],
285 ..Default::default()
286 };
287 let deserialized_xml_manifest: AndroidManifest = from_str(given_xml).unwrap();
288 assert_eq!(expected_manifest, deserialized_xml_manifest);
289 let serialized_toml_manifest = toml::to_string_pretty(&deserialized_xml_manifest).unwrap();
290 let deserialized_toml_manifest: AndroidManifest =
291 toml::from_str(&serialized_toml_manifest).unwrap();
292 assert_eq!(deserialized_xml_manifest, deserialized_toml_manifest);
293 }
294}