├── .github └── workflows │ ├── publish.yml │ └── ci.yml ├── src ├── error.rs ├── ui_options.rs ├── action.rs ├── profileable.rs ├── category.rs ├── permission_group.rs ├── permission_tree.rs ├── resources │ ├── types.rs │ ├── any.rs │ ├── res_or_string.rs │ ├── mipmap_or_drawable.rs │ └── mod.rs ├── uses_native_library.rs ├── uses_permission_sdk_23.rs ├── meta_data.rs ├── uses_library.rs ├── grant_uri_permission.rs ├── path_permission.rs ├── instrumentation.rs ├── uses_permission.rs ├── var_or_bool.rs ├── attribute_list.rs ├── supports_gl_texture.rs ├── activity_alias.rs ├── uses_configuration.rs ├── layout.rs ├── permission.rs ├── data.rs ├── uses_sdk.rs ├── uses_feature.rs ├── intent_filter.rs ├── compatible_screens.rs ├── queries.rs └── lib.rs ├── Cargo.toml ├── tests ├── test_optional_package.rs ├── tools_attributes_test.rs └── test_manifest_with_tools.xml ├── README.md ├── .gitignore └── LICENSE /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Build and deploy to crates.io 2 | on: 3 | push: 4 | branches: [main] 5 | paths: 6 | - '.github/workflows/publish.yml' 7 | - 'Cargo.toml' 8 | jobs: 9 | build-deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@master 13 | - run: cargo login ${{ secrets.CRATES_IO_TOKEN }} 14 | - run: cargo publish 15 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use displaydoc::Display; 2 | use thiserror::Error; 3 | 4 | pub type Result = std::result::Result; 5 | 6 | #[derive(Display, Debug, Error)] 7 | pub enum Error { 8 | /// Failed to serialize AndroidManifest.xml. Error: {0} 9 | FailedToSerialize(String), 10 | /// Failed to deserialize AndroidManifest.xml. Error: {0} 11 | FailedToDeserialize(String), 12 | } 13 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "android-manifest" 3 | version = "0.3.0" 4 | authors = ["DodoRare Team "] 5 | description = "Android Manifest serializer and deserializer for Rust" 6 | repository = "https://github.com/dodorare/android-manifest-rs" 7 | license = "Apache-2.0" 8 | edition = "2024" 9 | 10 | [dependencies] 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_plain = "1.0" 13 | yaserde = "0.12" 14 | yaserde_derive = "0.12" 15 | xml-rs = "0.8" 16 | thiserror = "2.0" 17 | displaydoc = "0.2" 18 | log = "0.4" 19 | 20 | [dev-dependencies] 21 | toml = "0.9" 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [main] 5 | paths: 6 | - '.github/workflows/ci.yml' 7 | - '**.rs' 8 | - '**.toml' 9 | pull_request: 10 | paths: 11 | - '.github/workflows/ci.yml' 12 | - '**.rs' 13 | - '**.toml' 14 | jobs: 15 | test-and-check: 16 | name: Check code format 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@master 20 | - uses: actions-rs/toolchain@v1 21 | with: 22 | toolchain: nightly 23 | components: rustfmt, clippy 24 | override: true 25 | - name: Check the format 26 | run: cargo +nightly fmt --all -- --check 27 | - name: Run clippy 28 | run: cargo clippy --all-targets --all-features -- -D warnings -A clippy::upper_case_acronyms 29 | - name: Check for deadlinks 30 | run: | 31 | cargo install cargo-deadlinks 32 | cargo deadlinks --check-http || true 33 | - name: Run tests 34 | run: cargo test --no-fail-fast 35 | -------------------------------------------------------------------------------- /src/ui_options.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Extra options for an activity's UI. 4 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 5 | #[serde(rename_all = "camelCase")] 6 | #[derive(Default)] 7 | pub enum UiOptions { 8 | /// No extra UI options. This is the default 9 | #[yaserde(rename = "none")] 10 | #[default] 11 | None, 12 | /// Add a bar at the bottom of the screen to display action items in the app 13 | /// bar (also known as the action bar), when constrained for horizontal 14 | /// space (such as when in portrait mode on a handset). Instead of a 15 | /// small number of action items appearing in the app bar at the top of the 16 | /// screen, the app bar is split into the top navigation section and the 17 | /// bottom bar for action items. This ensures a reasonable amount of 18 | /// space is made available not only for the action items, but also for 19 | /// navigation and title elements at the top. Menu items are not split 20 | /// across the two bars; they always appear together. 21 | #[yaserde(rename = "splitActionBarWhenNarrow")] 22 | SplitActionBarWhenNarrow, 23 | } 24 | -------------------------------------------------------------------------------- /src/action.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Adds an action to an intent filter. 4 | /// 5 | /// An [``] element must contain one or more `` elements. If there 6 | /// are no `` elements in an intent filter, the filter doesn't accept any 7 | /// [`Intent`] objects. See [`Intents and Intent Filters`] for details on intent filters 8 | /// and the role of action specifications within a filter. 9 | /// 10 | /// ## XML Syntax 11 | /// ```xml 12 | /// 13 | /// ``` 14 | /// 15 | /// ## Contained in 16 | /// * [``] 17 | /// 18 | /// ## Introduced in 19 | /// API Level 1 20 | /// 21 | /// [``]: crate::IntentFilter 22 | /// [`Intent`]: https://developer.android.com/reference/android/content/Intent 23 | /// [`Intents and Intent Filters`]: https://developer.android.com/guide/components/intents-filters 24 | #[derive( 25 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 26 | )] 27 | pub struct Action { 28 | /// The name of the action. Some standard actions are defined in the [`Intent`] class 29 | /// as `ACTION_string` constants. To assign one of these actions to this 30 | /// attribute, prepend `"android.intent.action."` o the `string` that follows 31 | /// `ACTION_`. For example, for `ACTION_MAIN`, use "`android.intent.action.MAIN`" 32 | /// and for `ACTION_WEB_SEARCH`, use "`android.intent.action.WEB_SEARCH`". 33 | /// 34 | /// For actions you define, it's best to use your app's package name as a prefix to 35 | /// ensure uniqueness. 36 | /// 37 | /// ## XML Examples 38 | /// A `TRANSMOGRIFY` action might be specified as follows: 39 | /// ```xml 40 | /// 41 | /// ``` 42 | /// 43 | /// [`Intent`]: https://developer.android.com/reference/android/content/Intent 44 | #[yaserde(attribute = true, prefix = "android")] 45 | pub name: Option, 46 | } 47 | -------------------------------------------------------------------------------- /src/profileable.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | use crate::VarOrBool; 4 | 5 | /// Specifies how profilers can access this application. 6 | /// 7 | /// ## XML Syntax 8 | /// ```xml 9 | /// 12 | /// ``` 13 | /// 14 | /// ## Contained in 15 | /// * [``] 16 | /// 17 | /// ## Introduced in 18 | /// API Level 29 19 | /// 20 | /// [``]: crate::Application 21 | #[derive( 22 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 23 | )] 24 | pub struct Profileable { 25 | /// Specifies whether the user of the device can profile this application 26 | /// through local debugging tools. These include 27 | /// 28 | /// * [`android.os.Trace`] tracing APIs (Android 11 and lower) 29 | /// * [`simpleperf`] 30 | /// * [`am profile commands`] 31 | /// * [`perfetto profilers`] (native memory, Java memory, CPU). 32 | /// 33 | /// If this isn't set or is set to false, these tools and APIs will work 34 | /// only when an app is debuggable. Debuggable apps incur significant and 35 | /// varied performance degradation, and are not useful for measuring timing 36 | /// accurately. This element is strongly recommended for local performance 37 | /// measurements, in order to capture accurate results. 38 | /// 39 | /// [`android.os.Trace`]: https://developer.android.com/reference/kotlin/android/os/Trace 40 | /// [`simpleperf`]: https://developer.android.com/ndk/guides/simpleperf 41 | /// [`am profile commands`]: https://developer.android.com/studio/command-line/perfetto 42 | #[yaserde(attribute = true, prefix = "android")] 43 | pub shell: VarOrBool, 44 | /// Specifies whether the application can be profiled by system services or 45 | /// shell tools (for the latter, you must also set [`android:shell`]). If 46 | /// false, the application cannot be profiled at all. Defaults to true. This 47 | /// attribute was added in API level 30. 48 | /// 49 | /// [`android:shell`]: https://developer.android.com/guide/topics/manifest/profileable-element#shell 50 | #[yaserde(attribute = true, prefix = "android")] 51 | pub enable: VarOrBool, 52 | } 53 | -------------------------------------------------------------------------------- /src/category.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Adds a category name to an intent filter. 4 | /// 5 | /// See [`Intents and Intent Filters`] for details on intent filters and 6 | /// the role of category specifications within a filter. 7 | /// 8 | /// ## XML Syntax 9 | /// ```xml 10 | /// 11 | /// ``` 12 | /// 13 | /// ## Contained in: 14 | /// * [``] 15 | /// 16 | /// ## Introduced in 17 | /// API Level 1 18 | /// 19 | /// [`Intents and Intent Filters`]: https://developer.android.com/guide/components/intents-filters 20 | /// [``]: crate::IntentFilter 21 | #[derive( 22 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 23 | )] 24 | pub struct Category { 25 | /// The name of the category. Standard categories are defined in the [`Intent`] 26 | /// class as CATEGORY_name constants. The name assigned here can be derived 27 | /// from those constants by prefixing `"android.intent.category."` to 28 | /// the name that follows CATEGORY_. For example, the string value for 29 | /// CATEGORY_LAUNCHER is`"android.intent.category.LAUNCHER"`. 30 | /// 31 | /// ## Note 32 | /// In order to receive implicit intents, you must include the 33 | /// [`CATEGORY_DEFAULT`] category in the intent filter. The methods 34 | /// [`startActivity()`] and [`startActivityForResult()`] treat all intents 35 | /// as if they declared the [`CATEGORY_DEFAULT`] category. If you do not 36 | /// declare it in your intent filter, no implicit intents will resolve to 37 | /// your activity. 38 | /// 39 | /// Custom categories should use the package name as a prefix, to ensure that 40 | /// they are unique. 41 | /// 42 | /// [`Intent`]: https://developer.android.com/reference/android/content/Intent 43 | /// [`CATEGORY_DEFAULT`]: https://developer.android.com/reference/android/content/Intent#CATEGORY_DEFAULT 44 | /// [`startActivity()`]: https://developer.android.com/reference/android/app/Activity#startActivity(android.content.Intent) 45 | /// [`startActivityForResult()`]: https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int) 46 | #[yaserde(attribute = true, prefix = "android")] 47 | pub name: Option, 48 | } 49 | -------------------------------------------------------------------------------- /tests/test_optional_package.rs: -------------------------------------------------------------------------------- 1 | use android_manifest::{AndroidManifest, Application}; 2 | 3 | #[test] 4 | fn test_package_optional_serialization() { 5 | // Test with package = None - should not appear in XML 6 | let manifest = AndroidManifest { 7 | package: None, 8 | application: Application::default(), 9 | ..Default::default() 10 | }; 11 | 12 | let xml = yaserde::ser::to_string(&manifest).expect("Failed to serialize"); 13 | println!("XML without package:\n{}", xml); 14 | 15 | assert!( 16 | !xml.contains("package="), 17 | "package attribute should not appear when None" 18 | ); 19 | 20 | // Test with package = Some(...) - should appear in XML 21 | let manifest2 = AndroidManifest { 22 | package: Some("com.example.app".to_string()), 23 | application: Application::default(), 24 | ..Default::default() 25 | }; 26 | 27 | let xml2 = yaserde::ser::to_string(&manifest2).expect("Failed to serialize"); 28 | println!("\nXML with package:\n{}", xml2); 29 | 30 | assert!( 31 | xml2.contains("package=\"com.example.app\""), 32 | "package attribute should appear when Some" 33 | ); 34 | } 35 | 36 | #[test] 37 | fn test_package_optional_deserialization() { 38 | // Test parsing XML without package attribute 39 | let xml_without = r#" 40 | 41 | 42 | "#; 43 | 44 | let manifest: AndroidManifest = 45 | yaserde::de::from_str(xml_without).expect("Failed to parse manifest without package"); 46 | 47 | assert_eq!( 48 | manifest.package, None, 49 | "package should be None when not present in XML" 50 | ); 51 | 52 | // Test parsing XML with package attribute 53 | let xml_with = r#" 54 | 56 | 57 | "#; 58 | 59 | let manifest2: AndroidManifest = 60 | yaserde::de::from_str(xml_with).expect("Failed to parse manifest with package"); 61 | 62 | assert_eq!( 63 | manifest2.package, 64 | Some("com.example.test".to_string()), 65 | "package should be Some when present in XML" 66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /src/permission_group.rs: -------------------------------------------------------------------------------- 1 | use super::resources::{ 2 | MipmapOrDrawableResource, Resource, StringResource, StringResourceOrString, 3 | }; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | /// Declares a name for a logical grouping of related permissions. 7 | /// 8 | /// Individual permission join the group through the permissionGroup attribute of the 9 | /// [``] element. Members of a group are presented together in 10 | /// the user interface. 11 | /// 12 | /// Note that this element does not declare a permission itself, only a category in which 13 | /// permissions can be placed. See the [``] element for element for 14 | /// information on declaring permissions and assigning them to groups. 15 | /// 16 | /// ## XML Syntax 17 | /// ```xml 18 | /// 22 | /// ``` 23 | /// 24 | /// ## Contained in 25 | /// * [``] 26 | /// 27 | /// ## Introduced in 28 | /// API Level 1 29 | /// 30 | /// [``]: crate::AndroidManifest 31 | /// [``]: crate::Permission 32 | #[derive( 33 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 34 | )] 35 | pub struct PermissionGroup { 36 | /// User-readable text that describes the group. The text should be longer and more 37 | /// explanatory than the label. This attribute must be set as a reference to a 38 | /// string resource. Unlike the label attribute, it cannot be a raw string. 39 | #[yaserde(attribute = true, prefix = "android")] 40 | pub description: Option>, 41 | /// An icon representing the permission. This attribute must be set as a reference to 42 | /// a drawable resource containing the image definition. 43 | #[yaserde(attribute = true, prefix = "android")] 44 | pub icon: Option, 45 | /// A user-readable name for the group. As a convenience, the label can be directly 46 | /// set as a raw string while you're developing the application. However, when the 47 | /// application is ready to be published, it should be set as a reference to a 48 | /// string resource, so that it can be localized like other strings in the user 49 | /// interface. 50 | #[yaserde(attribute = true, prefix = "android")] 51 | pub label: Option, 52 | /// The name of the group. This is the name that can be assigned to a 53 | /// [``] element's [``] attribute. 54 | /// 55 | /// [``]: crate::Permission 56 | /// [``]: crate::Permission#structfield.permission_group 57 | #[yaserde(attribute = true, prefix = "android")] 58 | pub name: Option, 59 | } 60 | -------------------------------------------------------------------------------- /src/permission_tree.rs: -------------------------------------------------------------------------------- 1 | use super::resources::{MipmapOrDrawableResource, StringResourceOrString}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | /// Declares the base name for a tree of permissions. 5 | /// 6 | /// The application takes ownership of all names within the tree. It can dynamically add 7 | /// new permissions to the tree by calling [`PackageManager.addPermission()`] Names within 8 | /// the tree are separated by periods `('.')`. For example, if the base name is 9 | /// com.example.project.taxes. 10 | /// 11 | /// Permissions like the following might be added: 12 | /// 13 | /// * `com.example.project.taxes.CALCULATE` 14 | /// * `com.example.project.taxes.deductions.MAKE_SOME_UP` 15 | /// * `com.example.project.taxes.deductions.EXAGGERATE` 16 | /// 17 | /// Note that this element does not declare a permission itself, only a 18 | /// namespace in which further permissions can be placed. See the [``] 19 | /// element for information on declaring permissions. 20 | /// 21 | /// ## XML Syntax 22 | /// ```xml 23 | /// 26 | /// ``` 27 | /// 28 | /// ## Contained in 29 | /// * [``] 30 | /// 31 | /// ## Introduced in 32 | /// API Level 1 33 | /// 34 | /// [`PackageManager.addPermission()`]: https://developer.android.com/reference/android/content/pm/PackageManager#addPermission(android.content.pm.PermissionInfo) 35 | /// [``]: crate::Permission 36 | /// [``]: crate::AndroidManifest 37 | #[derive( 38 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 39 | )] 40 | pub struct PermissionTree { 41 | /// An icon representing all the permissions in the tree. This attribute must be set 42 | /// as a reference to a drawable resource containing the image definition. 43 | #[yaserde(attribute = true, prefix = "android")] 44 | pub icon: Option, 45 | /// A user-readable name for the group. As a convenience, the label can be directly 46 | /// set as a raw string for quick and dirty programming. However, when the 47 | /// application is ready to be published, it should be set as a reference to a 48 | /// string resource, so that it can be localized like other strings in the user 49 | /// interface. 50 | #[yaserde(attribute = true, prefix = "android")] 51 | pub label: Option, 52 | /// The name that's at the base of the permission tree. It serves as a prefix to all 53 | /// permission names in the tree. Java-style scoping should be used to ensure that 54 | /// the name is unique. The name must have more than two period-separated segments 55 | /// in its path — for example, `com.example.base` is OK, but `com.example` is not. 56 | #[yaserde(attribute = true, prefix = "android")] 57 | pub name: Option, 58 | } 59 | -------------------------------------------------------------------------------- /tests/tools_attributes_test.rs: -------------------------------------------------------------------------------- 1 | use android_manifest::AndroidManifest; 2 | use std::fs; 3 | 4 | #[test] 5 | fn test_parse_manifest_with_tools_attributes() { 6 | let xml_content = fs::read_to_string("tests/test_manifest_with_tools.xml") 7 | .expect("Failed to read test manifest file"); 8 | 9 | let manifest: AndroidManifest = 10 | yaserde::de::from_str(&xml_content).expect("Failed to parse manifest"); 11 | 12 | // Test manifest level tools attributes 13 | assert_eq!(manifest.package, Some("com.example.testapp".to_string())); 14 | assert_eq!(manifest.ignore, Some("MissingVersion".to_string())); 15 | assert_eq!(manifest.locale, Some("en".to_string())); 16 | 17 | // Test application tools attributes 18 | let app = &manifest.application; 19 | assert_eq!(app.name, Some(".MyApplication".to_string())); 20 | assert_eq!(app.replace, Some("android:icon,android:theme".to_string())); 21 | assert_eq!(app.ignore, Some("GoogleAppIndexingWarning".to_string())); 22 | 23 | // Test activity tools attributes 24 | let main_activity = app 25 | .activity 26 | .iter() 27 | .find(|a| a.name == ".MainActivity") 28 | .expect("MainActivity not found"); 29 | 30 | assert_eq!( 31 | main_activity.replace, 32 | Some("android:theme,android:exported".to_string()) 33 | ); 34 | assert_eq!(main_activity.node, Some("replace".to_string())); 35 | assert_eq!(main_activity.exported, Some(true.into())); 36 | 37 | let second_activity = app 38 | .activity 39 | .iter() 40 | .find(|a| a.name == ".SecondActivity") 41 | .expect("SecondActivity not found"); 42 | 43 | assert_eq!( 44 | second_activity.remove, 45 | Some("android:windowSoftInputMode".to_string()) 46 | ); 47 | assert_eq!(second_activity.target_api, Some("21".to_string())); 48 | 49 | // Test service tools attributes 50 | let service = app 51 | .service 52 | .iter() 53 | .find(|s| s.name == ".MyService") 54 | .expect("MyService not found"); 55 | 56 | assert_eq!(service.node, Some("merge".to_string())); 57 | assert_eq!(service.ignore, Some("ExportedService".to_string())); 58 | 59 | // Test receiver tools attributes 60 | let receiver = app 61 | .receiver 62 | .iter() 63 | .find(|r| r.name == ".MyReceiver") 64 | .expect("MyReceiver not found"); 65 | 66 | assert_eq!(receiver.replace, Some("android:exported".to_string())); 67 | assert_eq!(receiver.selector, Some("com.example.lib1".to_string())); 68 | 69 | // Test provider tools attributes 70 | let provider = app 71 | .provider 72 | .iter() 73 | .find(|p| p.name == ".MyProvider") 74 | .expect("MyProvider not found"); 75 | 76 | assert_eq!(provider.node, Some("strict".to_string())); 77 | assert_eq!(provider.strict, Some("android:authorities".to_string())); 78 | 79 | println!("✅ All tools attributes parsed successfully!"); 80 | } 81 | -------------------------------------------------------------------------------- /src/resources/types.rs: -------------------------------------------------------------------------------- 1 | use super::ResourceType; 2 | use std::str::FromStr; 3 | 4 | /// String resource type. 5 | #[derive(Debug, PartialEq, Eq, Clone)] 6 | pub struct StringResource; 7 | 8 | impl FromStr for StringResource { 9 | type Err = String; 10 | 11 | fn from_str(s: &str) -> Result { 12 | if s == "string" { 13 | Ok(StringResource) 14 | } else { 15 | Err(format!("failed to convert {} to string recource type", s)) 16 | } 17 | } 18 | } 19 | 20 | impl ResourceType for StringResource { 21 | fn resource_type() -> &'static str { 22 | "string" 23 | } 24 | } 25 | 26 | /// Drawable resource type. 27 | #[derive(Debug, PartialEq, Eq, Clone)] 28 | pub struct DrawableResource; 29 | 30 | impl FromStr for DrawableResource { 31 | type Err = String; 32 | 33 | fn from_str(s: &str) -> Result { 34 | if s == "drawable" { 35 | Ok(DrawableResource) 36 | } else { 37 | Err(format!("failed to convert {} to drawable resource type", s)) 38 | } 39 | } 40 | } 41 | 42 | impl ResourceType for DrawableResource { 43 | fn resource_type() -> &'static str { 44 | "drawable" 45 | } 46 | } 47 | 48 | /// Mipmap resource type. 49 | #[derive(Debug, PartialEq, Eq, Clone)] 50 | pub struct MipmapResource; 51 | 52 | impl FromStr for MipmapResource { 53 | type Err = String; 54 | 55 | fn from_str(s: &str) -> Result { 56 | if s == "mipmap" { 57 | Ok(MipmapResource) 58 | } else { 59 | Err(format!("failed to convert {} to mipmap resource type", s)) 60 | } 61 | } 62 | } 63 | 64 | impl ResourceType for MipmapResource { 65 | fn resource_type() -> &'static str { 66 | "mipmap" 67 | } 68 | } 69 | 70 | /// Xml resource type. 71 | #[derive(Debug, PartialEq, Eq, Clone)] 72 | pub struct XmlResource; 73 | 74 | impl FromStr for XmlResource { 75 | type Err = String; 76 | 77 | fn from_str(s: &str) -> Result { 78 | if s == "xml" { 79 | Ok(XmlResource) 80 | } else { 81 | Err(format!("failed to convert {} to xml resource type", s)) 82 | } 83 | } 84 | } 85 | 86 | impl ResourceType for XmlResource { 87 | fn resource_type() -> &'static str { 88 | "xml" 89 | } 90 | } 91 | 92 | /// Style resource type. 93 | #[derive(Debug, PartialEq, Eq, Clone)] 94 | pub struct StyleResource; 95 | 96 | impl FromStr for StyleResource { 97 | type Err = String; 98 | 99 | fn from_str(s: &str) -> Result { 100 | if s == "style" { 101 | Ok(StyleResource) 102 | } else { 103 | Err(format!("failed to convert {} to style resource type", s)) 104 | } 105 | } 106 | } 107 | 108 | impl ResourceType for StyleResource { 109 | fn resource_type() -> &'static str { 110 | "style" 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/uses_native_library.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | use crate::VarOrBool; 4 | 5 | /// Specifies a [`vendor-provided shared native library`] that the application must be 6 | /// linked against. 7 | /// 8 | /// This element tells the system to make the native library accessible for the package. 9 | /// 10 | /// NDK libraries are by default accessible and therefore don't require the 11 | /// `` tag. 12 | /// 13 | /// Non-NDK native shared libraries that are provided by silicon vendors or device 14 | /// manufacturers are not accessible by default if the app is targeting Android 12 15 | /// or higher. The libraries are accessible only when they are explicitly requested 16 | /// using the `` tag. 17 | /// 18 | /// If the app is targeting Android 11 or lower, the `` tag is 19 | /// not required. n that case, any native shared library is accessible regardless 20 | /// of whether it is an NDK library. 21 | /// 22 | /// This element also affects the installation of the application on a particular device: 23 | /// 24 | /// ## Installation 25 | /// If this element is present and its android:required attribute is set to true, 26 | /// the [`PackageManager`] framework won't let the user install the application unless 27 | /// the library is present on the user's device. 28 | /// 29 | /// The android:required attribute is described in detail in the following section. 30 | /// 31 | /// ## XML Syntax 32 | /// ```xml 33 | /// 36 | /// ``` 37 | /// 38 | /// ## Contained in 39 | /// * [``] 40 | /// 41 | /// ## Introduced in 42 | /// API Level S 43 | /// 44 | /// [`vendor-provided shared native library`]: https://source.android.com/devices/tech/config/namespaces_libraries#adding-additional-native-libraries 45 | /// [`PackageManager`]: https://developer.android.com/reference/android/content/pm/PackageManager 46 | /// [``]: crate::Application 47 | #[derive( 48 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 49 | )] 50 | pub struct UsesNativeLibrary { 51 | /// The name of the library file. 52 | #[yaserde(attribute = true, prefix = "android")] 53 | pub name: String, 54 | /// Boolean value that indicates whether the application requires the library 55 | /// specified by android:name: 56 | /// 57 | /// * `"true"`: The application does not function without this library. The system will 58 | /// not allow the application on a device that does not have the library. 59 | /// 60 | /// * `"false"`: The application can use the library if present, but is designed to 61 | /// function 62 | /// without it if necessary. The system will allow the application to be installed, 63 | /// even if the library is not present. If you use `"false"`, you are responsible 64 | /// for gracefully handling the absence of the library. 65 | /// 66 | /// The default is `"true"`. 67 | #[yaserde(attribute = true, prefix = "android")] 68 | pub required: Option, 69 | } 70 | -------------------------------------------------------------------------------- /tests/test_manifest_with_tools.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 25 | 26 | 27 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 46 | 47 | 48 | 54 | 55 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 74 | 75 | 76 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/uses_permission_sdk_23.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Specifies that an app wants a particular permission. 4 | /// 5 | /// But only if the app is installed on a device running Android 6.0 ([`API level`] 6 | /// 23) or higher. If the device is running API level 22 or lower, the app does 7 | /// not have the specified permission. 8 | /// 9 | /// This element is useful when you update an app to include a new feature that 10 | /// requires an additional permission. If a user updates an app on a device that 11 | /// is running API level 22 or lower, the system prompts the user at install 12 | /// time to grant all new permissions that are declared in that update. If a new 13 | /// feature is minor enough, you may prefer to disable the feature altogether on 14 | /// those devices, so the user does not have to grant additional permissions to 15 | /// update the app. By using the `` element instead of 16 | /// [``], you can request the permission only if the app is running 17 | /// on platforms that support the [`runtime permissions model`] in which the user 18 | /// grants permissions to the app while it is running. 19 | /// 20 | /// For more information on permissions, see the [`Permissions`] section in the 21 | /// introduction and the separate [`System Permissions`] API guide. A list of 22 | /// permissions defined by the base platform is available at 23 | /// [`android.Manifest.permission`]. 24 | /// 25 | /// ## XML Syntax 26 | /// ```xml 27 | /// 29 | /// ``` 30 | /// 31 | /// ## Contained in 32 | /// [``] 33 | /// 34 | /// ## introduced in: 35 | /// API Level 23 36 | /// 37 | /// [`API level`]: https://developer.android.com/guide/topics/manifest/uses-sdk-element#ApiLevels 38 | /// [`runtime permissions model`]: https://developer.android.com/training/permissions/requesting 39 | /// [`Permissions`]: https://developer.android.com/guide/topics/manifest/manifest-intro#perms 40 | /// [`System Permissions`]: https://developer.android.com/guide/topics/permissions/overview 41 | /// [`android.Manifest.permission`]: https://developer.android.com/reference/android/Manifest.permission 42 | /// [``]: crate::AndroidManifest 43 | /// [``]: crate::UsesPermission 44 | #[derive( 45 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 46 | )] 47 | pub struct UsesPermissionSdk23 { 48 | /// The name of the permission. This permission can be defined by the app 49 | /// with the [``] element, it can be a permission defined by another 50 | /// app, or it can be one of the standard system permissions, such as 51 | /// [`android.permission.CAMERA`] or [`android.permission.READ_CONTACTS`]. 52 | /// 53 | /// [``]: crate::Permission 54 | /// [`android.permission.CAMERA`]: https://developer.android.com/reference/android/Manifest.permission#CAMERA 55 | /// [`android.permission.READ_CONTACTS`]: https://developer.android.com/reference/android/Manifest.permission#READ_CONTACTS 56 | #[yaserde(attribute = true, prefix = "android")] 57 | pub name: Option, 58 | /// The highest API level at which this permission should be granted to your 59 | /// app. If the app is installed on a device with a later API level, the 60 | /// app is not granted the permission and cannot use any related 61 | /// functionality. 62 | #[yaserde(attribute = true, prefix = "android", rename = "maxSdkVersion")] 63 | pub max_sdk_version: Option, 64 | } 65 | -------------------------------------------------------------------------------- /src/meta_data.rs: -------------------------------------------------------------------------------- 1 | use super::resources::*; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | /// A name-value pair for an item of additional, arbitrary data that can be 5 | /// supplied to the parent component. 6 | /// 7 | /// A component element can contain any number 8 | /// of `` subelements. The values from all of them are collected in a 9 | /// single [`Bundle`] object and made available to the component as the 10 | /// [`PackageItemInfo.metaData`] field. 11 | /// 12 | /// Ordinary values are specified through the [`value`] attribute. However, to assign a 13 | /// resource ID as the value, use the [`resource`] attribute instead. For example, the 14 | /// following code assigns whatever value is stored in the @string/kangaroo resource to 15 | /// the `"zoo"` name: 16 | /// 17 | /// ## XML Examples 18 | /// 19 | /// ```xml 20 | /// 21 | /// ``` 22 | /// On the other hand, using the resource attribute would assign `"zoo"` the 23 | /// numeric ID of the resource, not the value stored in the resource: 24 | /// 25 | /// ```xml 26 | /// 27 | /// ``` 28 | /// 29 | /// It is highly recommended that you avoid supplying related data as multiple 30 | /// separate `` entries. Instead, if you have complex data to 31 | /// associate with a component, store it as a `resource` and use the resource 32 | /// attribute to inform the component of its ID. 33 | /// 34 | /// ## XML Syntax 35 | /// ```xml 36 | /// 39 | /// ``` 40 | /// 41 | /// ## Contained in 42 | /// * [``] 43 | /// * [``] 44 | /// * [``] 45 | /// * [``] 46 | /// * [``] 47 | /// * [``] 48 | /// 49 | /// ## Introduced in 50 | /// API Level 1 51 | /// 52 | /// [`Bundle`]: https://developer.android.com/reference/android/os/Bundle 53 | /// [`PackageItemInfo.metaData`]: https://developer.android.com/reference/android/content/pm/PackageItemInfo#metaData 54 | /// [`value`]: crate::MetaData#structfield.value 55 | /// [`resource`]: crate::MetaData#structfield.resource 56 | /// [``]: crate::Activity 57 | /// [``]: crate::ActivityAlias 58 | /// [``]: crate::Application 59 | /// [``]: crate::Service 60 | /// [``]: crate::Receiver 61 | /// [``]: crate::Provider 62 | #[derive( 63 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 64 | )] 65 | pub struct MetaData { 66 | /// A unique name for the item. To ensure that the name is unique, use a Java-style 67 | /// naming convention — for example, `"com.example.project.activity.fred"`. 68 | #[yaserde(attribute = true, prefix = "android")] 69 | pub name: Option, 70 | /// A reference to a resource. The ID of the resource is the value assigned to the 71 | /// item. The ID can be retrieved from the meta-data Bundle by the 72 | /// [`Bundle.getInt()`] method. 73 | /// 74 | /// [`Bundle.getInt()`]: https://developer.android.com/reference/android/os/BaseBundle#getInt(java.lang.String) 75 | #[yaserde(attribute = true, prefix = "android")] 76 | pub resource: Option, 77 | /// The value assigned to the item. The data types that can be assigned as values and 78 | /// the Bundle methods that components use to retrieve those values are listed in the 79 | /// following table: https://developer.android.com/guide/topics/manifest/meta-data-element#val 80 | #[yaserde(attribute = true, prefix = "android")] 81 | pub value: Option, 82 | } 83 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Android Manifest

3 | 4 | CI Info 5 | Crate Info 6 | API Docs 7 | Crate 8 |
9 | 10 | [AndroidManifest] serializer and deserializer for Rust. This library will also likely continue to stay up to date with the official AndroidManifest specification as changes happen. 11 | 12 | [AndroidManifest]: https://developer.android.com/guide/topics/manifest/manifest-intro 13 | 14 | ```toml 15 | # Cargo.toml 16 | [dependencies] 17 | android-manifest = "*" 18 | ``` 19 | 20 | Create `AndroidManifest.xml` by yourself: 21 | ```rust 22 | let manifest = AndroidManifest { 23 | package: "com.example.toggletest".to_string(), 24 | version_code: Some(1), 25 | version_name: Some("1.0".to_string()), 26 | application: Application { 27 | allow_backup: Some(true.into())), 28 | icon: Some(MipmapOrDrawableResource::mipmap("ic_launcher", None)), 29 | label: Some(StringResourceOrString::resource("app_name", None)), 30 | theme: Some(StyleResource::new("AppTheme", None)), 31 | activity: vec![Activity { 32 | label: Some(StringResourceOrString::resource("app_name", None)), 33 | name: "com.example.toggletest.MainActivity".to_string(), 34 | intent_filter: vec![IntentFilter { 35 | action: vec![Action { 36 | name: Some("android.intent.action.MAIN".to_string()), 37 | }], 38 | category: vec![Category { 39 | name: Some("android.intent.category.LAUNCHER".to_string()), 40 | }], 41 | ..Default::default() 42 | }], 43 | ..Default::default() 44 | }], 45 | ..Default::default() 46 | }, 47 | ..Default::default() 48 | }; 49 | let serialized_manifest = android_manifest::to_string_pretty(&manifest).unwrap(); 50 | ``` 51 | 52 | Or parse any `AndroidManifest.xml` file: 53 | ```rust 54 | let xml = r#" 55 | 56 | 60 | 64 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | "#; 73 | let manifest: AndroidManifest = android_manifest::from_str(xml).unwrap(); 74 | ``` 75 | 76 | # License 77 | 78 | This project is licensed under Apache License, Version 2.0, ([LICENSE](LICENSE) or http://www.apache.org/licenses/LICENSE-2.0). 79 | 80 | ### Contribution 81 | 82 | Unless you explicitly state otherwise, any contribution intentionally submitted 83 | for inclusion in toml-rs by you, as defined in the Apache-2.0 license, shall be 84 | dual licensed as above, without any additional terms or conditions. 85 | -------------------------------------------------------------------------------- /src/uses_library.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | use crate::VarOrBool; 4 | /// Specifies a shared library that the application must be linked against. 5 | /// 6 | /// This element tells the system to include the library's code in the class loader for 7 | /// the package. All of the android packages (such as [`android.app`], 8 | /// [`android.content`], [`android.view`], and [`android.widget`]) are in the default 9 | /// library that all applications are automatically linked against. However, 10 | /// some packages (such as maps) are in separate libraries that are not 11 | /// automatically linked. Consult the documentation for the packages you're 12 | /// using to determine which library contains the package code. 13 | /// 14 | /// ## Node 15 | /// Google Play uses the elements declared in your app manifest to filter 16 | /// your app from devices that don't meet its library requirements. For more information 17 | /// about filtering, see the topic [`Google Play filters`]. 18 | /// 19 | /// This element also affects the installation of the application on a particular device 20 | /// and the availability of the application on Google Play: 21 | /// 22 | /// ## Installation 23 | /// If this element is present and its android:required attribute is set to true, the 24 | /// [`PackageManager`] framework won't let the user install the application unless the 25 | /// library is present on the user's device. 26 | /// 27 | /// The `android:required` attribute is described in detail in the following 28 | /// section. 29 | /// 30 | /// ## XML Syntax 31 | /// ```xml 32 | /// 35 | /// ``` 36 | /// 37 | /// ## Contained in 38 | /// [``] 39 | /// 40 | /// ## introduced in 41 | /// API Level 1 42 | /// 43 | /// [`android.app`]: https://developer.android.com/reference/android/app/package-summary 44 | /// [`android.content`]: https://developer.android.com/reference/android/content/package-summary 45 | /// [`android.view`]: https://developer.android.com/reference/android/view/package-summary 46 | /// [`android.widget`]: https://developer.android.com/reference/android/widget/package-summary 47 | /// [`PackageManager`]: https://developer.android.com/reference/android/content/pm/PackageManager 48 | /// [`Google Play filters`]: https://developer.android.com/google/play/filters 49 | /// [``]: crate::Application 50 | #[derive( 51 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 52 | )] 53 | pub struct UsesLibrary { 54 | /// The name of the library. The name is provided by the documentation for the package 55 | /// you are using. An example of this is `"android.test.runner"`, a package that 56 | /// contains Android test classes. 57 | #[yaserde(attribute = true, prefix = "android")] 58 | pub name: Option, 59 | /// Boolean value that indicates whether the application requires the library 60 | /// specified by android:name: 61 | /// * `"true":` The application does not 62 | /// function without this library. The system will not allow the application 63 | /// on a device that does not have the library. 64 | /// * `"false":` The application can use the library if present, but is 65 | /// designed to function without it if necessary. The system will allow 66 | /// the application to be installed, even if the library is not present. 67 | /// If you use `"false"`, you are responsible for checking at runtime that 68 | /// the library is available. 69 | /// 70 | /// To check for a library, you can use reflection to determine if a particular class 71 | /// is available. 72 | /// 73 | /// The default is `"true"`. 74 | /// 75 | /// Introduced in: API Level 7. 76 | #[yaserde(attribute = true, prefix = "android")] 77 | pub required: Option, 78 | } 79 | -------------------------------------------------------------------------------- /src/grant_uri_permission.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Specifies the subsets of app data that parent content provider can access. 4 | /// 5 | /// Data subsets are indicated by the path part of a `content:` URI. (The authority part 6 | /// of the URI identifies the content provider.) Granting permission is a way of enabling 7 | /// clients of the provider that don't normally have permission to access its data to 8 | /// overcome that restriction on a one-time basis. 9 | /// 10 | /// If a content provider's [`grantUriPermissions`] attribute is `"true"`, permission can 11 | /// be granted for any the data under the provider's purview. However, if that attribute 12 | /// is `"false"` permission can be granted only to data subsets that are specified 13 | /// by this element. A provider can contain any number of 14 | /// `` elements. Each one can specify only one path (only 15 | /// one of the three possible attributes). 16 | /// 17 | /// For information on how permission is granted, see the [``] element's 18 | /// [`grantUriPermissions`] attribute. 19 | /// 20 | /// ## XML Syntax 21 | /// ```xml 22 | /// 25 | /// ``` 26 | /// 27 | /// ## Contained in 28 | /// * [``] 29 | /// 30 | /// ## Introduced in 31 | /// API Level 1 32 | /// 33 | /// [`grantUriPermissions`]: crate::Provider#structfield.grant_uri_permissions 34 | /// [``]: crate::IntentFilter 35 | /// [``]: crate::Provider 36 | #[derive( 37 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 38 | )] 39 | pub struct GrantUriPermission { 40 | /// A path identifying the data subset or subsets that permission can be granted for. 41 | /// The path attribute specifies a complete path; permission can be granted only 42 | /// to the particular data subset identified by that path. The `pathPrefix` 43 | /// attribute specifies the initial part of a path; permission can be granted to 44 | /// all data subsets with paths that share that initial part. The `pathPattern` 45 | /// attribute specifies a complete path, but one that can contain the following 46 | /// wildcards: 47 | /// 48 | /// * An asterisk `('*')` matches a sequence of 0 to many occurrences of the 49 | /// immediately preceding character. 50 | /// * A period followed by an asterisk `(".*")` matches any sequence of 0 to many 51 | /// characters. 52 | /// 53 | /// Because `'\'` is used as an escape character when the string is read from XML 54 | /// (before it is parsed as a pattern), you will need to double-escape: For 55 | /// example, a literal `'*'` would be written as `"\\*"` and a literal `'\'` would 56 | /// be written as `"\\\\"`. This is basically the same as what you would need to 57 | /// write if constructing the string in Java code. 58 | /// For more information on these types of patterns, see the descriptions of 59 | /// [`PATTERN_LITERAL`], [`PATTERN_PREFIX`], and [`PATTERN_SIMPLE_GLOB`] in the 60 | /// [`PatternMatcher`] class. 61 | /// 62 | /// [`PATTERN_LITERAL`]: https://developer.android.com/reference/android/os/PatternMatcher#PATTERN_LITERAL 63 | /// [`PATTERN_PREFIX`]: https://developer.android.com/reference/android/os/PatternMatcher#PATTERN_PREFIX 64 | /// [`PATTERN_SIMPLE_GLOB`]: https://developer.android.com/reference/android/os/PatternMatcher#PATTERN_SIMPLE_GLOB 65 | /// [`PatternMatcher`]: https://developer.android.com/reference/android/os/PatternMatcher 66 | #[yaserde(attribute = true, prefix = "android")] 67 | pub path: Option, 68 | #[yaserde(attribute = true, prefix = "android", rename = "pathPattern")] 69 | pub path_pattern: Option, 70 | #[yaserde(attribute = true, prefix = "android", rename = "pathPrefix")] 71 | pub path_prefix: Option, 72 | } 73 | -------------------------------------------------------------------------------- /src/path_permission.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Defines the path and required permissions for a specific subset of data 4 | /// within a content provider. 5 | /// 6 | /// This element can be specified multiple times to 7 | /// supply multiple paths. 8 | /// 9 | /// ## XML Syntax 10 | /// ```xml 11 | /// 17 | /// ``` 18 | /// 19 | /// ## Contained in 20 | /// * [``] 21 | /// 22 | /// ## Introduced in 23 | /// API Level 4 24 | /// 25 | /// [``]: crate::Provider 26 | #[derive( 27 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 28 | )] 29 | pub struct PathPermission { 30 | /// A complete URI path for a subset of content provider data. Permission can be 31 | /// granted only to the particular data identified by this path. When used to 32 | /// provide search suggestion content, it must be appended with 33 | /// "/search_suggest_query". 34 | #[yaserde(attribute = true, prefix = "android")] 35 | pub path: Option, 36 | /// The initial part of a URI path for a subset of content provider data. Permission 37 | /// can be granted to all data subsets with paths that share this initial part. 38 | #[yaserde(attribute = true, prefix = "android", rename = "pathPrefix")] 39 | pub path_prefix: Option, 40 | /// A complete URI path for a subset of content provider data, but one that 41 | /// can use the following wildcards: 42 | /// 43 | /// * An asterisk `('*')`. This matches a sequence of 0 to many occurrences of the 44 | /// immediately precedingcharacter. 45 | /// * A period followed by an asterisk `(".*")`. This matches any 46 | /// sequence of 0 or more characters. 47 | /// 48 | /// Because `'\'` is used as an escape character when the string is read from XML 49 | /// (before it is parsed as a pattern), you will need to double-escape. For 50 | /// example, a literal `'*'` would be written as `"\\*"` and a literal `'\'` would be 51 | /// written as `"\\"`. This is basically the same as what you would need to write if 52 | /// constructing the string in Java code. 53 | /// 54 | /// For more information on these types of patterns, see the descriptions of 55 | /// [`PATTERN_LITERAL`], [`PATTERN_PREFIX`], and [`PATTERN_SIMPLE_GLOB`] in the 56 | /// [`PatternMatcher`] class. 57 | /// 58 | /// [`PATTERN_LITERAL`]: https://developer.android.com/reference/android/os/PatternMatcher#PATTERN_LITERAL 59 | /// [`PATTERN_PREFIX`]: https://developer.android.com/reference/android/os/PatternMatcher#PATTERN_PREFIX 60 | /// [`PATTERN_SIMPLE_GLOB`]: https://developer.android.com/reference/android/os/PatternMatcher#PATTERN_SIMPLE_GLOB 61 | /// [`PatternMatcher`]: https://developer.android.com/reference/android/os/PatternMatcher 62 | #[yaserde(attribute = true, prefix = "android", rename = "pathPattern")] 63 | pub path_pattern: Option, 64 | /// The name of a permission that clients must have in order to read or write the 65 | /// content provider's data. This attribute is a convenient way of setting a 66 | /// single permission for both reading and writing. However, the `readPermission` 67 | /// and `writePermission` attributes take precedence over this one. 68 | #[yaserde(attribute = true, prefix = "android")] 69 | pub permission: Option, 70 | /// A permission that clients must have in order to query the content provider. 71 | #[yaserde(attribute = true, prefix = "android", rename = "readPermission")] 72 | pub read_permission: Option, 73 | /// A permission that clients must have in order to make changes to the data 74 | /// controlled by the content provider. 75 | #[yaserde(attribute = true, prefix = "android", rename = "writePermission")] 76 | pub write_permission: Option, 77 | } 78 | -------------------------------------------------------------------------------- /src/instrumentation.rs: -------------------------------------------------------------------------------- 1 | use crate::VarOrBool; 2 | 3 | use super::resources::{MipmapOrDrawableResource, StringResourceOrString}; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | /// Declares an [`Instrumentation`] class that enables you to monitor an application's 7 | /// interaction with the system. 8 | /// 9 | /// The Instrumentation object is instantiated before any of the application's 10 | /// components. 11 | /// 12 | /// ## XML Syntax 13 | /// ```xml 14 | /// 21 | /// ``` 22 | /// 23 | /// ## Contained in: 24 | /// * [``] 25 | /// 26 | /// ## Introduced in 27 | /// API Level 1 28 | /// 29 | /// [`Instrumentation`]: https://developer.android.com/reference/android/app/Instrumentation 30 | /// [``]: crate::AndroidManifest 31 | #[derive( 32 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 33 | )] 34 | pub struct Instrumentation { 35 | /// Whether or not the Instrumentation class should run as a functional test — 36 | /// `"true"` if it should, and `"false"` if not. The default value is `"false"`. 37 | #[yaserde(attribute = true, prefix = "android", rename = "functionalTest")] 38 | pub functional_test: Option, 39 | /// Whether or not the Instrumentation object will turn profiling on and off — 40 | /// `"true"` if it determines when profiling starts and stops, and `"false"` if 41 | /// profiling continues the entire time it is running. A value of `"true"` enables 42 | /// the object to target profiling at a specific set of operations. The default 43 | /// value is `"false"`. 44 | #[yaserde(attribute = true, prefix = "android", rename = "handleProfiling")] 45 | pub handle_profiling: Option, 46 | /// An icon that represents the Instrumentation class. This attribute must be set as a 47 | /// reference to a drawable resource. 48 | #[yaserde(attribute = true, prefix = "android")] 49 | pub icon: Option, 50 | /// A user-readable label for the Instrumentation class. The label can be set as a raw 51 | /// string or a reference to a string resource. 52 | #[yaserde(attribute = true, prefix = "android")] 53 | pub label: Option, 54 | /// The name of the [`Instrumentation`] subclass. This should be a fully qualified 55 | /// class name (such as, `"com.example.project.StringInstrumentation"`). However, 56 | /// as a shorthand, if the first character of the name is a period, it is 57 | /// appended to the package name specified in the [``] element. 58 | /// There is no default. The name must be specified. 59 | /// 60 | /// [`Instrumentation`]: https://developer.android.com/reference/android/app/Instrumentation 61 | /// [``]: crate::AndroidManifest 62 | #[yaserde(attribute = true, prefix = "android")] 63 | pub name: String, 64 | /// The application that the [`Instrumentation`] object will run against. An 65 | /// application is identified by the package name assigned in its manifest file by 66 | /// the [``] element. 67 | /// 68 | /// [`Instrumentation`]: https://developer.android.com/reference/android/app/Instrumentation 69 | /// [``]: crate::AndroidManifest 70 | #[yaserde(attribute = true, prefix = "android", rename = "targetPackage")] 71 | pub target_package: Option, 72 | /// The processes that the [`Instrumentation`] object will run against. A 73 | /// comma-separated list indicates that the instrumentation will run against those 74 | /// specific processes. A value of `"*"` indicates that the instrumentation will 75 | /// run against all processes of the app defined in [`android:targetPackage`]. If 76 | /// this value isn't provided in the manifest, the instrumentation will run only 77 | /// against the main process of the app defined in [`android:targetPackage`]. 78 | /// 79 | /// [`Instrumentation`]: https://developer.android.com/reference/android/app/Instrumentation 80 | /// [`android:targetPackage`]: crate::Instrumentation#structfield.target_package 81 | #[yaserde(attribute = true, prefix = "android", rename = "targetProcesses")] 82 | pub target_processes: Option, 83 | } 84 | -------------------------------------------------------------------------------- /src/resources/any.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | DrawableResource, Resource, ResourceType, StringResource, StyleResource, XmlResource, 3 | parse_resource, 4 | }; 5 | use serde::{ 6 | Deserialize, Deserializer, Serialize, Serializer, 7 | de::{self, Visitor}, 8 | }; 9 | use std::fmt; 10 | use std::io::{Read, Write}; 11 | use yaserde::{YaDeserialize, YaSerialize}; 12 | 13 | /// Enum used when the value can be any of available resources. 14 | #[derive(Debug, PartialEq, Eq, Clone)] 15 | pub enum AnyResource { 16 | String(Resource), 17 | Drawable(Resource), 18 | Xml(Resource), 19 | Style(Resource), 20 | } 21 | 22 | impl Serialize for AnyResource { 23 | fn serialize(&self, serializer: S) -> Result 24 | where 25 | S: Serializer, 26 | { 27 | match self { 28 | AnyResource::String(r) => Serialize::serialize(&r, serializer), 29 | AnyResource::Drawable(r) => Serialize::serialize(&r, serializer), 30 | AnyResource::Xml(r) => Serialize::serialize(&r, serializer), 31 | AnyResource::Style(r) => Serialize::serialize(&r, serializer), 32 | } 33 | } 34 | } 35 | 36 | impl YaSerialize for AnyResource { 37 | fn serialize(&self, writer: &mut yaserde::ser::Serializer) -> Result<(), String> { 38 | match self { 39 | AnyResource::String(r) => YaSerialize::serialize(r, writer), 40 | AnyResource::Drawable(r) => YaSerialize::serialize(r, writer), 41 | AnyResource::Xml(r) => YaSerialize::serialize(r, writer), 42 | AnyResource::Style(r) => YaSerialize::serialize(r, writer), 43 | } 44 | } 45 | 46 | fn serialize_attributes( 47 | &self, 48 | attributes: Vec, 49 | namespace: xml::namespace::Namespace, 50 | ) -> Result< 51 | ( 52 | Vec, 53 | xml::namespace::Namespace, 54 | ), 55 | String, 56 | > { 57 | Ok((attributes, namespace)) 58 | } 59 | } 60 | 61 | fn parse_any_resource(v: &str) -> Result { 62 | if v.is_empty() { 63 | return Err("value of attribute is empty".to_string()); 64 | }; 65 | let (package, resource_type, name) = parse_resource(v)?; 66 | let any = if StringResource::resource_type() == resource_type { 67 | AnyResource::String(Resource::::new_with_package(&name, package)) 68 | } else if DrawableResource::resource_type() == resource_type { 69 | AnyResource::Drawable(Resource::::new_with_package( 70 | &name, package, 71 | )) 72 | } else if XmlResource::resource_type() == resource_type { 73 | AnyResource::Xml(Resource::::new_with_package(&name, package)) 74 | } else if StyleResource::resource_type() == resource_type { 75 | AnyResource::Style(Resource::::new_with_package(&name, package)) 76 | } else { 77 | return Err(format!("unsuported resource type: {}", resource_type)); 78 | }; 79 | Ok(any) 80 | } 81 | 82 | struct AnyResourceVisitor; 83 | 84 | impl<'de> Visitor<'de> for AnyResourceVisitor { 85 | type Value = AnyResource; 86 | 87 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 88 | formatter.write_str("an resource in format @resource_type/resource_name") 89 | } 90 | 91 | fn visit_str(self, v: &str) -> Result 92 | where 93 | E: de::Error, 94 | { 95 | parse_any_resource(v).map_err(|e| E::custom(e)) 96 | } 97 | } 98 | 99 | impl<'de> Deserialize<'de> for AnyResource { 100 | fn deserialize(deserializer: D) -> Result 101 | where 102 | D: Deserializer<'de>, 103 | { 104 | deserializer.deserialize_string(AnyResourceVisitor) 105 | } 106 | } 107 | 108 | impl YaDeserialize for AnyResource { 109 | fn deserialize(reader: &mut yaserde::de::Deserializer) -> Result { 110 | loop { 111 | match reader.next_event()? { 112 | xml::reader::XmlEvent::StartElement { .. } => {} 113 | xml::reader::XmlEvent::Characters(ref v) => { 114 | return parse_any_resource(v); 115 | } 116 | _ => { 117 | break; 118 | } 119 | } 120 | } 121 | Err("Unable to parse attribute".to_string()) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/uses_permission.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Specifies a system permission that the user must grant in order for the app 4 | /// to operate correctly. 5 | /// 6 | /// Permissions are granted by the user when the application is installed (on devices 7 | /// running Android 5.1 and lower) or while the app is running (on devices running Android 8 | /// 6.0 and higher). For more information on permissions, see the [`Permissions`] section 9 | /// in the introduction and the separate [`System Permissions`] API guide. A list of 10 | /// permissions defined by the base platform can be found at 11 | /// [`android.Manifest.permission`]. 12 | /// 13 | /// ## Note 14 | /// In some cases, the permissions that you request through 15 | /// `` can affect how your application is filtered by Google Play. 16 | /// 17 | /// If you request a hardware-related permission — `CAMERA`, for example — Google Play 18 | /// assumes that your application requires the underlying hardware feature and filters the 19 | /// application from devices that do not offer it. 20 | /// 21 | /// To control filtering, always explicitly declare hardware features in `` 22 | /// elements, rather than relying on Google Play to "discover" the requirements in 23 | /// `` elements. Then, if you want to disable filtering for a particular 24 | /// feature, you can add a `android:required`="`false`" attribute to the 25 | /// declaration. 26 | /// 27 | /// For a list of permissions that imply hardware features, see the documentation for the 28 | /// [``] element. 29 | /// 30 | /// ## XML Syntax 31 | /// ```xml 32 | /// 34 | /// ``` 35 | /// 36 | /// ## Contained in 37 | /// * [``] 38 | /// 39 | /// ## Introduced in 40 | /// API Level 1 41 | /// 42 | /// [`Permissions`]: https://developer.android.com/guide/topics/manifest/manifest-intro#perms 43 | /// [`System Permissions`]: https://developer.android.com/guide/topics/permissions/overview 44 | /// [`android.Manifest.permission`]: https://developer.android.com/reference/android/Manifest.permission 45 | /// [``]: https://developer.android.com/guide/topics/manifest/uses-feature-element#permissions-features 46 | /// [``]: crate::AndroidManifest 47 | #[derive( 48 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 49 | )] 50 | pub struct UsesPermission { 51 | /// The name of the permission. It can be a permission defined by theapplication with 52 | /// the [``] element, a permission defined by another application, or 53 | /// one of the standard system permissions (such as [`android.permission.CAMERA`] 54 | /// or [`android.permission.READ_CONTACTS`]). As these examples show, a 55 | /// permission name typically includes the package name as a prefix. 56 | /// 57 | /// [``]: crate::Permission 58 | /// [`android.permission.CAMERA`]: https://developer.android.com/reference/android/Manifest.permission#CAMERA 59 | /// [`android.permission.READ_CONTACTS`]: https://developer.android.com/reference/android/Manifest.permission#READ_CONTACTS 60 | #[yaserde(attribute = true, prefix = "android")] 61 | pub name: Option, 62 | /// The highest API level at which this permission should be granted to your app. 63 | /// Setting this attribute is useful if the permission your app requires is no 64 | /// longer needed beginning at a certain API level. 65 | /// 66 | /// ## XML Examples 67 | /// Beginning with Android 4.4 (API level 19), it's no longer necessary for your app 68 | /// to request the [`WRITE_EXTERNAL_STORAGE`] permission when your app wants to 69 | /// write to its own application-specific directories on external storage (the 70 | /// directories provided by [`getExternalFilesDir()`]). However, the permission is 71 | /// required for API level 18 and lower. So you can declare that this permission 72 | /// is needed only up to API level 18 with a declaration such as this: 73 | /// 74 | /// ```xml 75 | /// 77 | /// ``` 78 | /// This way, beginning with API level 19, the system will no longer grant your app 79 | /// the [`WRITE_EXTERNAL_STORAGE`] permission. 80 | /// 81 | /// This attribute was added in API level 19. 82 | /// 83 | /// [`WRITE_EXTERNAL_STORAGE`]: https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE 84 | /// [`getExternalFilesDir()`]: https://developer.android.com/reference/android/content/Context#getExternalFilesDir(java.lang.String) 85 | #[yaserde(attribute = true, prefix = "android", rename = "maxSdkVersion")] 86 | pub max_sdk_version: Option, 87 | } 88 | -------------------------------------------------------------------------------- /src/resources/res_or_string.rs: -------------------------------------------------------------------------------- 1 | use super::{Resource, ResourceType, ResourceVisitor, StringResource, parse_resource_with_type}; 2 | use serde::{ 3 | Deserialize, Deserializer, Serialize, Serializer, 4 | de::{self, Visitor}, 5 | }; 6 | use std::fmt; 7 | use std::io::{Read, Write}; 8 | use yaserde::{YaDeserialize, YaSerialize}; 9 | 10 | /// Enum used when the value can be string resource or just a row string. 11 | #[derive(Debug, PartialEq, Eq, Clone)] 12 | pub enum StringResourceOrString { 13 | StringResource(Resource), 14 | String(String), 15 | } 16 | 17 | impl StringResourceOrString { 18 | pub fn resource(name: &str, package: Option) -> StringResourceOrString { 19 | Self::StringResource(StringResource::new(name, package)) 20 | } 21 | 22 | pub fn string(s: &str) -> StringResourceOrString { 23 | Self::String(s.to_string()) 24 | } 25 | } 26 | 27 | impl fmt::Display for StringResourceOrString { 28 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 29 | match self { 30 | Self::StringResource(r) => write!(f, "{}", r), 31 | Self::String(v) => write!(f, "{}", v), 32 | } 33 | } 34 | } 35 | 36 | impl Serialize for StringResourceOrString { 37 | fn serialize(&self, serializer: S) -> Result 38 | where 39 | S: Serializer, 40 | { 41 | match self { 42 | StringResourceOrString::StringResource(resource) => { 43 | Serialize::serialize(&resource, serializer) 44 | } 45 | StringResourceOrString::String(value) => serializer.serialize_str(value), 46 | } 47 | } 48 | } 49 | 50 | impl YaSerialize for StringResourceOrString { 51 | fn serialize(&self, writer: &mut yaserde::ser::Serializer) -> Result<(), String> { 52 | match self { 53 | StringResourceOrString::StringResource(resource) => { 54 | YaSerialize::serialize(resource, writer)?; 55 | } 56 | StringResourceOrString::String(value) => { 57 | let _ret = writer.write(xml::writer::XmlEvent::characters(value)); 58 | } 59 | } 60 | Ok(()) 61 | } 62 | 63 | fn serialize_attributes( 64 | &self, 65 | attributes: Vec, 66 | namespace: xml::namespace::Namespace, 67 | ) -> Result< 68 | ( 69 | Vec, 70 | xml::namespace::Namespace, 71 | ), 72 | String, 73 | > { 74 | Ok((attributes, namespace)) 75 | } 76 | } 77 | 78 | struct StringResourceOrStringVisitor; 79 | 80 | impl<'de> Visitor<'de> for StringResourceOrStringVisitor { 81 | type Value = StringResourceOrString; 82 | 83 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 84 | formatter.write_str("an string resource in format @string/resource_name or string") 85 | } 86 | 87 | fn visit_str(self, v: &str) -> Result 88 | where 89 | E: de::Error, 90 | { 91 | if v.is_empty() { 92 | return Err(E::custom("value of attribute is empty")); 93 | }; 94 | if v.starts_with('@') { 95 | Ok(StringResourceOrString::StringResource( 96 | ResourceVisitor::::new().visit_str(v)?, 97 | )) 98 | } else { 99 | Ok(StringResourceOrString::String(v.to_owned())) 100 | } 101 | } 102 | } 103 | 104 | impl<'de> Deserialize<'de> for StringResourceOrString { 105 | fn deserialize(deserializer: D) -> Result 106 | where 107 | D: Deserializer<'de>, 108 | { 109 | deserializer.deserialize_string(StringResourceOrStringVisitor) 110 | } 111 | } 112 | 113 | impl YaDeserialize for StringResourceOrString { 114 | fn deserialize(reader: &mut yaserde::de::Deserializer) -> Result { 115 | loop { 116 | match reader.next_event()? { 117 | xml::reader::XmlEvent::StartElement { .. } => {} 118 | xml::reader::XmlEvent::Characters(text_content) => { 119 | if text_content.is_empty() { 120 | return Err("value of attribute is empty".to_string()); 121 | }; 122 | if text_content.starts_with('@') { 123 | return Ok(StringResourceOrString::StringResource( 124 | parse_resource_with_type(&text_content)?, 125 | )); 126 | } else { 127 | return Ok(StringResourceOrString::String(text_content)); 128 | } 129 | } 130 | _ => { 131 | break; 132 | } 133 | } 134 | } 135 | Err("Unable to parse attribute".to_string()) 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/var_or_bool.rs: -------------------------------------------------------------------------------- 1 | use serde::{ 2 | Deserialize, Deserializer, Serialize, Serializer, 3 | de::{self, Visitor}, 4 | }; 5 | use std::fmt; 6 | use std::io::{Read, Write}; 7 | use yaserde::{YaDeserialize, YaSerialize}; 8 | 9 | /// Enum used when the value can be string resource or just a row string. 10 | #[derive(Debug, PartialEq, Eq, Clone)] 11 | pub enum VarOrBool { 12 | Var(String), 13 | Bool(bool), 14 | } 15 | 16 | impl Default for VarOrBool { 17 | fn default() -> Self { 18 | Self::bool(false) 19 | } 20 | } 21 | 22 | impl From for VarOrBool { 23 | fn from(value: bool) -> Self { 24 | Self::bool(value) 25 | } 26 | } 27 | 28 | impl From<&str> for VarOrBool { 29 | fn from(value: &str) -> Self { 30 | Self::var(value) 31 | } 32 | } 33 | 34 | impl VarOrBool { 35 | pub fn var(name: impl Into) -> VarOrBool { 36 | Self::Var(name.into()) 37 | } 38 | 39 | pub fn bool(s: bool) -> VarOrBool { 40 | Self::Bool(s) 41 | } 42 | } 43 | 44 | impl fmt::Display for VarOrBool { 45 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 46 | match self { 47 | Self::Var(r) => write!(f, "{}", r), 48 | Self::Bool(v) => write!(f, "{}", v), 49 | } 50 | } 51 | } 52 | 53 | impl Serialize for VarOrBool { 54 | fn serialize(&self, serializer: S) -> Result 55 | where 56 | S: Serializer, 57 | { 58 | match self { 59 | VarOrBool::Var(variable) => Serialize::serialize(&variable, serializer), 60 | VarOrBool::Bool(value) => serializer.serialize_bool(*value), 61 | } 62 | } 63 | } 64 | 65 | impl YaSerialize for VarOrBool { 66 | fn serialize(&self, writer: &mut yaserde::ser::Serializer) -> Result<(), String> { 67 | match self { 68 | VarOrBool::Var(variable) => { 69 | let _ret = writer.write(xml::writer::XmlEvent::characters(variable)); 70 | } 71 | VarOrBool::Bool(value) => { 72 | let _ret = writer.write(xml::writer::XmlEvent::characters(&value.to_string())); 73 | } 74 | } 75 | Ok(()) 76 | } 77 | 78 | fn serialize_attributes( 79 | &self, 80 | attributes: Vec, 81 | namespace: xml::namespace::Namespace, 82 | ) -> Result< 83 | ( 84 | Vec, 85 | xml::namespace::Namespace, 86 | ), 87 | String, 88 | > { 89 | Ok((attributes, namespace)) 90 | } 91 | } 92 | 93 | struct VarOrBoolVisitor; 94 | 95 | impl<'de> Visitor<'de> for VarOrBoolVisitor { 96 | type Value = VarOrBool; 97 | 98 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 99 | formatter.write_str("a boolean value or a variable in the \"${variable}\" format") 100 | } 101 | 102 | fn visit_bool(self, v: bool) -> Result 103 | where 104 | E: de::Error, 105 | { 106 | Ok(v.into()) 107 | } 108 | 109 | fn visit_str(self, v: &str) -> Result 110 | where 111 | E: de::Error, 112 | { 113 | if v.is_empty() { 114 | return Err(E::custom("value of attribute is empty")); 115 | }; 116 | if v.starts_with("${") && v.ends_with('}') { 117 | Ok(VarOrBool::var(v)) 118 | } else { 119 | Ok(VarOrBool::Bool(v.parse().map_err(|_| { 120 | E::custom(format!("value `{v}` is not a valid boolean")) 121 | })?)) 122 | } 123 | } 124 | } 125 | 126 | impl<'de> Deserialize<'de> for VarOrBool { 127 | fn deserialize(deserializer: D) -> Result 128 | where 129 | D: Deserializer<'de>, 130 | { 131 | deserializer.deserialize_string(VarOrBoolVisitor) 132 | } 133 | } 134 | 135 | impl YaDeserialize for VarOrBool { 136 | fn deserialize(reader: &mut yaserde::de::Deserializer) -> Result { 137 | loop { 138 | match reader.next_event()? { 139 | xml::reader::XmlEvent::StartElement { .. } => {} 140 | xml::reader::XmlEvent::Characters(text_content) => { 141 | if text_content.is_empty() { 142 | return Err("value of attribute is empty".to_string()); 143 | }; 144 | if text_content.starts_with("${") && text_content.ends_with('}') { 145 | return Ok(VarOrBool::Var(text_content)); 146 | } else { 147 | return Ok(VarOrBool::Bool(text_content.parse().map_err(|_| { 148 | format!("value {text_content} is not a valid boolean") 149 | })?)); 150 | } 151 | } 152 | _ => { 153 | break; 154 | } 155 | } 156 | } 157 | Err("Unable to parse attribute".to_string()) 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/resources/mipmap_or_drawable.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | DrawableResource, MipmapResource, Resource, ResourceType, ResourceVisitor, 3 | parse_resource_with_type, 4 | }; 5 | use serde::{ 6 | Deserialize, Deserializer, Serialize, Serializer, 7 | de::{self, Visitor}, 8 | }; 9 | use std::fmt; 10 | use std::io::{Read, Write}; 11 | use yaserde::{YaDeserialize, YaSerialize}; 12 | 13 | /// Enum used when the value can be string resource or just a row string. 14 | #[derive(Debug, PartialEq, Eq, Clone)] 15 | pub enum MipmapOrDrawableResource { 16 | Mipmap(Resource), 17 | Drawable(Resource), 18 | } 19 | 20 | impl MipmapOrDrawableResource { 21 | pub fn mipmap(name: &str, package: Option) -> MipmapOrDrawableResource { 22 | Self::Mipmap(MipmapResource::new(name, package)) 23 | } 24 | 25 | pub fn drawable(name: &str, package: Option) -> MipmapOrDrawableResource { 26 | Self::Drawable(DrawableResource::new(name, package)) 27 | } 28 | } 29 | 30 | impl fmt::Display for MipmapOrDrawableResource { 31 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 32 | match self { 33 | Self::Mipmap(r) => write!(f, "{}", r), 34 | Self::Drawable(r) => write!(f, "{}", r), 35 | } 36 | } 37 | } 38 | 39 | impl Serialize for MipmapOrDrawableResource { 40 | fn serialize(&self, serializer: S) -> Result 41 | where 42 | S: Serializer, 43 | { 44 | match self { 45 | Self::Mipmap(r) => Serialize::serialize(&r, serializer), 46 | Self::Drawable(r) => Serialize::serialize(&r, serializer), 47 | } 48 | } 49 | } 50 | 51 | impl YaSerialize for MipmapOrDrawableResource { 52 | fn serialize(&self, writer: &mut yaserde::ser::Serializer) -> Result<(), String> { 53 | match self { 54 | Self::Mipmap(r) => YaSerialize::serialize(r, writer), 55 | Self::Drawable(r) => YaSerialize::serialize(r, writer), 56 | } 57 | } 58 | 59 | fn serialize_attributes( 60 | &self, 61 | attributes: Vec, 62 | namespace: xml::namespace::Namespace, 63 | ) -> Result< 64 | ( 65 | Vec, 66 | xml::namespace::Namespace, 67 | ), 68 | String, 69 | > { 70 | Ok((attributes, namespace)) 71 | } 72 | } 73 | 74 | struct MipmapOrDrawableResourceVisitor; 75 | 76 | impl<'de> Visitor<'de> for MipmapOrDrawableResourceVisitor { 77 | type Value = MipmapOrDrawableResource; 78 | 79 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 80 | formatter 81 | .write_str("an resource in format @mipmap/resource_name or @drawable/resource_name") 82 | } 83 | 84 | fn visit_str(self, v: &str) -> Result 85 | where 86 | E: de::Error, 87 | { 88 | if v.is_empty() { 89 | return Err(E::custom("value of attribute is empty")); 90 | }; 91 | if v.starts_with("@mipmap") { 92 | Ok(MipmapOrDrawableResource::Mipmap( 93 | ResourceVisitor::::new().visit_str(v)?, 94 | )) 95 | } else if v.starts_with("@drawable") { 96 | Ok(MipmapOrDrawableResource::Drawable( 97 | ResourceVisitor::::new().visit_str(v)?, 98 | )) 99 | } else { 100 | Err(E::custom(format!("wrong resource type: {}", v))) 101 | } 102 | } 103 | } 104 | 105 | impl<'de> Deserialize<'de> for MipmapOrDrawableResource { 106 | fn deserialize(deserializer: D) -> Result 107 | where 108 | D: Deserializer<'de>, 109 | { 110 | deserializer.deserialize_string(MipmapOrDrawableResourceVisitor) 111 | } 112 | } 113 | 114 | impl YaDeserialize for MipmapOrDrawableResource { 115 | fn deserialize(reader: &mut yaserde::de::Deserializer) -> Result { 116 | loop { 117 | match reader.next_event()? { 118 | xml::reader::XmlEvent::StartElement { .. } => {} 119 | xml::reader::XmlEvent::Characters(text_content) => { 120 | if text_content.is_empty() { 121 | return Err("value of attribute is empty".to_string()); 122 | }; 123 | if text_content.starts_with("@mipmap") { 124 | return Ok(MipmapOrDrawableResource::Mipmap(parse_resource_with_type( 125 | &text_content, 126 | )?)); 127 | } else if text_content.starts_with("@drawable") { 128 | return Ok(MipmapOrDrawableResource::Drawable( 129 | parse_resource_with_type(&text_content)?, 130 | )); 131 | } else { 132 | return Err(format!("wrong resource type: {}", text_content)); 133 | } 134 | } 135 | _ => { 136 | break; 137 | } 138 | } 139 | } 140 | Err("Unable to parse attribute".to_string()) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/attribute_list.rs: -------------------------------------------------------------------------------- 1 | use serde::{ 2 | Deserialize, Deserializer, Serialize, Serializer, 3 | de::{self, DeserializeOwned, Visitor}, 4 | ser::Error, 5 | }; 6 | use std::fmt; 7 | use std::io::{Read, Write}; 8 | use std::marker::PhantomData; 9 | use yaserde::{YaDeserialize, YaSerialize}; 10 | 11 | pub trait Delimiter { 12 | fn delimiter_symbol() -> &'static str; 13 | } 14 | 15 | #[derive(Debug, PartialEq, Eq, Default, Clone)] 16 | pub struct Semicolon; 17 | 18 | impl Delimiter for Semicolon { 19 | fn delimiter_symbol() -> &'static str { 20 | ";" 21 | } 22 | } 23 | 24 | #[derive(Debug, PartialEq, Eq, Default, Clone)] 25 | pub struct VerticalBar; 26 | 27 | impl Delimiter for VerticalBar { 28 | fn delimiter_symbol() -> &'static str { 29 | "|" 30 | } 31 | } 32 | 33 | #[derive(Debug, PartialEq, Eq, Default, Clone)] 34 | pub struct AttributeList { 35 | vec: Vec, 36 | phantom: PhantomData, 37 | } 38 | 39 | impl AttributeList { 40 | pub fn new() -> Self { 41 | AttributeList { 42 | vec: Vec::new(), 43 | phantom: PhantomData, 44 | } 45 | } 46 | 47 | pub fn from_vec(vec: Vec) -> Self { 48 | AttributeList { 49 | vec, 50 | phantom: PhantomData, 51 | } 52 | } 53 | 54 | pub fn vec(&self) -> &Vec { 55 | &self.vec 56 | } 57 | 58 | pub fn is_empty(&self) -> bool { 59 | self.vec.is_empty() 60 | } 61 | } 62 | 63 | impl From> for AttributeList { 64 | fn from(vec: Vec) -> Self { 65 | AttributeList { 66 | vec, 67 | phantom: PhantomData, 68 | } 69 | } 70 | } 71 | 72 | impl Serialize for AttributeList { 73 | fn serialize(&self, serializer: S) -> Result 74 | where 75 | S: Serializer, 76 | { 77 | if self.is_empty() { 78 | return Err(S::Error::custom("a value list can't be empty")); 79 | }; 80 | serializer.serialize_str( 81 | &self 82 | .vec() 83 | .iter() 84 | .map(|v| serde_plain::to_string(v).unwrap()) 85 | .collect::>() 86 | .join(D::delimiter_symbol()), 87 | ) 88 | } 89 | } 90 | 91 | impl YaSerialize for AttributeList { 92 | fn serialize(&self, writer: &mut yaserde::ser::Serializer) -> Result<(), String> { 93 | // if self.is_empty() { 94 | // println!("1"); 95 | // return Err("a value list can't be empty".to_string()); 96 | // }; 97 | let _ret = writer.write(xml::writer::XmlEvent::characters( 98 | &self 99 | .vec() 100 | .iter() 101 | .map(|v| serde_plain::to_string(v).unwrap()) 102 | .collect::>() 103 | .join(D::delimiter_symbol()), 104 | )); 105 | Ok(()) 106 | } 107 | 108 | fn serialize_attributes( 109 | &self, 110 | attributes: Vec, 111 | namespace: xml::namespace::Namespace, 112 | ) -> Result< 113 | ( 114 | Vec, 115 | xml::namespace::Namespace, 116 | ), 117 | String, 118 | > { 119 | Ok((attributes, namespace)) 120 | } 121 | } 122 | 123 | fn parse_list_with_delimiter( 124 | v: &str, 125 | ) -> Result, String> { 126 | if v.is_empty() { 127 | return Err( 128 | "there is no default value list. at least one value must be specified".to_string(), 129 | ); 130 | }; 131 | let values = v 132 | .replace(' ', "") 133 | .split(D::delimiter_symbol()) 134 | .map(|s| serde_plain::from_str(s).unwrap()) 135 | .collect(); 136 | Ok(AttributeList::from_vec(values)) 137 | } 138 | 139 | struct ListVisitor { 140 | delimiter: PhantomData, 141 | value_type: PhantomData, 142 | } 143 | 144 | impl ListVisitor { 145 | pub fn new() -> Self { 146 | ListVisitor { 147 | delimiter: PhantomData, 148 | value_type: PhantomData, 149 | } 150 | } 151 | } 152 | 153 | impl<'de, D: Delimiter, T: Serialize + DeserializeOwned> Visitor<'de> for ListVisitor { 154 | type Value = AttributeList; 155 | 156 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 157 | formatter.write_str(&format!( 158 | "an value list in format 'value1' or 'value1{}value2{}value3'", 159 | D::delimiter_symbol(), 160 | D::delimiter_symbol() 161 | )) 162 | } 163 | 164 | fn visit_str(self, v: &str) -> Result 165 | where 166 | E: de::Error, 167 | { 168 | parse_list_with_delimiter(v).map_err(|e| E::custom(e)) 169 | } 170 | } 171 | 172 | impl<'de, D: Delimiter, T: Serialize + DeserializeOwned> Deserialize<'de> for AttributeList { 173 | fn deserialize(deserializer: De) -> Result 174 | where 175 | De: Deserializer<'de>, 176 | { 177 | deserializer.deserialize_string(ListVisitor::new()) 178 | } 179 | } 180 | 181 | impl YaDeserialize for AttributeList { 182 | fn deserialize(reader: &mut yaserde::de::Deserializer) -> Result { 183 | loop { 184 | match reader.next_event()? { 185 | xml::reader::XmlEvent::StartElement { .. } => {} 186 | xml::reader::XmlEvent::Characters(ref v) => { 187 | return parse_list_with_delimiter(v); 188 | } 189 | _ => { 190 | break; 191 | } 192 | } 193 | } 194 | Err("Unable to parse attribute".to_string()) 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/supports_gl_texture.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Declares a single GL texture compression format that the app supports. 4 | /// 5 | /// An application "supports" a GL texture compression format if it is capable of 6 | /// providing texture assets that are compressed in that format, once the application is 7 | /// installed on a device. The application can provide the compressed assets locally, from 8 | /// inside the .apk, or it can download them from a server at runtime. 9 | /// 10 | /// Each `` element declares exactly one supported texture 11 | /// compression format, specified as the value of a `android:name` attribute. If your 12 | /// application supports multiple texture compression formats, you can declare multiple 13 | /// `` elements. 14 | /// 15 | /// ## XML Example 16 | /// ```xml 17 | /// 19 | /// 21 | /// ``` 22 | /// 23 | /// Declared elements are informational, meaning that the Android 24 | /// system itself does not examine the elements at install time to ensure matching support 25 | /// on the device. However, other services (such as Google Play) or applications can check 26 | /// your application's declarations as part of handling or 27 | /// interacting with your application. For this reason, it's very important that you 28 | /// declare all of the texture compression formats (from the list below) that your 29 | /// application is capable of supporting. 30 | /// 31 | /// Applications and devices typically declare their supported GL texture compression 32 | /// formats using the same set of well-known strings, as listed below. The set of format 33 | /// strings may grow over time, as needed, and since the values are strings, applications 34 | /// are free to declare other formats as needed. 35 | /// 36 | /// Assuming that the application is built with SDK Platform Tools r3 or higher, filtering 37 | /// based on the `` element is activated for all API levels. 38 | /// 39 | /// ## Note 40 | /// Google Play filters applications according to the texture compression formats that 41 | /// they support, to ensure that they can be installed only on devices that can handle 42 | /// their textures properly. You can use texture compression filtering as a way of 43 | /// targeting specific device types, based on GPU platform. 44 | /// 45 | /// For important information about how Google Play uses `` 46 | /// elements as the basis for filtering, read [`Google Play and texture compression 47 | /// filtering`], below. 48 | /// 49 | /// ## XML Syntax 50 | /// ```xml 51 | /// 53 | /// ``` 54 | /// 55 | /// ## Contained in 56 | /// * [``] 57 | /// 58 | /// [`Google Play and texture compression filtering`]: https://developer.android.com/guide/topics/manifest/supports-gl-texture-element#market-texture-filtering 59 | /// [``]: crate::AndroidManifest 60 | #[derive( 61 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 62 | )] 63 | pub struct SupportsGlTexture { 64 | /// Specifies a single GL texture compression format supported by the application, as 65 | /// a descriptor string. Common descriptor values are listed in the table below. 66 | /// `GL_OES_compressed_ETC1_RGB8_texture` Ericsson texture compression. Specified 67 | /// in OpenGL ES 2.0 and available in all Android-powered devices that support 68 | /// OpenGL ES 2.0. `GL_OES_compressed_paletted_texture` Generic paletted texture 69 | /// compression. `GL_AMD_compressed_3DC_texture` ATI 3Dc texture 70 | /// compression. `GL_AMD_compressed_ATC_texture` ATI texture 71 | /// compression. Available on devices running Adreno GPU, including HTC 72 | /// Nexus One, Droid Incredible, EVO, and others. For widest 73 | /// compatibility, devices may also declare a element 74 | /// with the descriptor GL_ATI_texture_compression_atitc. 75 | /// `GL_EXT_texture_compression_latc` Luminance alpha texture compression. 76 | /// `GL_EXT_texture_compression_dxt1` S3 DXT1 texture compression. Supported 77 | /// on devices running Nvidia Tegra2 platform, including Motorala Xoom, 78 | /// Motorola Atrix, Droid Bionic, and others. 79 | /// `GL_EXT_texture_compression_s3tc` S3 texture compression, nonspecific to 80 | /// DXT variant. Supported on devices running Nvidia Tegra2 platform, 81 | /// including Motorala Xoom, Motorola Atrix, Droid Bionic, and others. 82 | /// If your application requires a specific DXT variant, declare that 83 | /// descriptor instead of this one. `GL_IMG_texture_compression_pvrtc` 84 | /// PowerVR texture compression. Available in devices running PowerVR 85 | /// SGX530/540 GPU, such as Motorola DROID series; Samsung Galaxy S, Nexus 86 | /// S, and Galaxy Tab; and others. 87 | #[yaserde(attribute = true, prefix = "android")] 88 | pub name: Option, 89 | } 90 | 91 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 92 | #[allow(non_camel_case_types)] 93 | #[derive(Default)] 94 | pub enum SupportsGlTextureName { 95 | /// Ericsson texture compression. Specified in OpenGL ES 2.0 and available in all 96 | /// Android-powered devices that support OpenGL ES 2.0. 97 | #[default] 98 | GL_OES_compressed_ETC1_RGB8_texture, 99 | /// Generic paletted texture compression. 100 | GL_OES_compressed_paletted_texture, 101 | /// ATI 3Dc texture compression 102 | GL_AMD_compressed_3DC_texture, 103 | /// ATI texture compression. Available on devices running Adreno GPU, including HTC 104 | /// Nexus One, Droid Incredible, EVO, and others. For widest compatibility, 105 | /// devices may also declare a `` element with the descriptor 106 | /// `GL_ATI_texture_compression_atitc`. 107 | GL_AMD_compressed_ATC_texture, 108 | /// Luminance alpha texture compression. 109 | GL_EXT_texture_compression_latc, 110 | /// S3 DXT1 texture compression. Supported on devices running Nvidia Tegra2 platform, 111 | /// including Motorala Xoom, Motorola Atrix, Droid Bionic, and others. 112 | GL_EXT_texture_compression_dxt1, 113 | /// S3 texture compression, nonspecific to DXT variant. Supported on devices running 114 | /// Nvidia Tegra2 platform, including Motorala Xoom, Motorola Atrix, Droid Bionic, 115 | /// and others If your application requires a specific DXT variant, declare that 116 | /// descriptor instead of this one. 117 | GL_EXT_texture_compression_s3tc, 118 | /// PowerVR texture compression. Available in devices running PowerVR SGX530/540 GPU, 119 | /// such as Motorola DROID series; Samsung Galaxy S, Nexus S, and Galaxy Tab; and 120 | /// others. 121 | GL_IMG_texture_compression_pvrtc, 122 | } 123 | -------------------------------------------------------------------------------- /src/resources/mod.rs: -------------------------------------------------------------------------------- 1 | mod any; 2 | mod mipmap_or_drawable; 3 | mod res_or_string; 4 | mod types; 5 | 6 | pub use any::*; 7 | pub use mipmap_or_drawable::*; 8 | pub use res_or_string::*; 9 | 10 | use serde::{ 11 | Deserialize, Deserializer, Serialize, Serializer, 12 | de::{self, Visitor}, 13 | }; 14 | use std::{ 15 | fmt, 16 | io::{Read, Write}, 17 | marker::PhantomData, 18 | str::FromStr, 19 | }; 20 | pub use types::*; 21 | use yaserde::{YaDeserialize, YaSerialize}; 22 | 23 | /// Trait implemented by types that can be used as resource. 24 | pub trait ResourceType: FromStr { 25 | /// Creates new instance of [`Resource`](crate::Resource). 26 | fn new(name: &str, package: Option) -> Resource { 27 | Resource { 28 | name: name.to_string(), 29 | package, 30 | phantom: PhantomData, 31 | } 32 | } 33 | /// Returns string representation of the `resource_type`. 34 | fn resource_type() -> &'static str; 35 | } 36 | 37 | /// Generic resource type. 38 | #[derive(Debug, PartialEq, Eq, Clone)] 39 | pub struct Resource { 40 | name: String, 41 | package: Option, 42 | phantom: PhantomData, 43 | } 44 | 45 | impl Resource { 46 | pub fn new(name: &str) -> Self { 47 | Self { 48 | name: name.to_string(), 49 | package: None, 50 | phantom: PhantomData, 51 | } 52 | } 53 | 54 | pub fn new_with_package(name: &str, package: Option) -> Self { 55 | Self { 56 | name: name.to_string(), 57 | package, 58 | phantom: PhantomData, 59 | } 60 | } 61 | 62 | pub fn name(&self) -> &str { 63 | &self.name 64 | } 65 | 66 | pub fn resource_type(&self) -> &'static str { 67 | T::resource_type() 68 | } 69 | } 70 | 71 | impl fmt::Display for Resource { 72 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 73 | if let Some(package) = &self.package { 74 | write!(f, "@{}:{}/{}", package, T::resource_type(), self.name) 75 | } else { 76 | write!(f, "@{}/{}", T::resource_type(), self.name) 77 | } 78 | } 79 | } 80 | 81 | impl Serialize for Resource { 82 | fn serialize(&self, serializer: S) -> Result 83 | where 84 | S: Serializer, 85 | { 86 | serializer.serialize_str(&self.to_string()) 87 | } 88 | } 89 | 90 | impl YaSerialize for Resource { 91 | fn serialize(&self, writer: &mut yaserde::ser::Serializer) -> Result<(), String> { 92 | if let Some(package) = &self.package { 93 | let _ret = writer.write(xml::writer::XmlEvent::characters(&format!( 94 | "@{}:{}/{}", 95 | package, 96 | T::resource_type(), 97 | self.name 98 | ))); 99 | } else { 100 | let _ret = writer.write(xml::writer::XmlEvent::characters(&format!( 101 | "@{}/{}", 102 | T::resource_type(), 103 | self.name 104 | ))); 105 | } 106 | Ok(()) 107 | } 108 | 109 | fn serialize_attributes( 110 | &self, 111 | attributes: Vec, 112 | namespace: xml::namespace::Namespace, 113 | ) -> Result< 114 | ( 115 | Vec, 116 | xml::namespace::Namespace, 117 | ), 118 | String, 119 | > { 120 | Ok((attributes, namespace)) 121 | } 122 | } 123 | 124 | struct ResourceVisitor { 125 | phantom: PhantomData, 126 | } 127 | 128 | impl ResourceVisitor { 129 | pub fn new() -> Self { 130 | ResourceVisitor { 131 | phantom: PhantomData, 132 | } 133 | } 134 | } 135 | 136 | impl<'de, T: ResourceType> Visitor<'de> for ResourceVisitor { 137 | type Value = Resource; 138 | 139 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 140 | formatter.write_str(&format!( 141 | "an {} resource in format @[package:]{}/resource_name", 142 | T::resource_type(), 143 | T::resource_type() 144 | )) 145 | } 146 | 147 | fn visit_str(self, v: &str) -> Result 148 | where 149 | E: de::Error, 150 | { 151 | parse_resource_with_type(v).map_err(E::custom) 152 | } 153 | } 154 | 155 | impl<'de, T: ResourceType> Deserialize<'de> for Resource { 156 | fn deserialize(deserializer: D) -> Result 157 | where 158 | D: Deserializer<'de>, 159 | { 160 | deserializer.deserialize_string(ResourceVisitor::new()) 161 | } 162 | } 163 | 164 | impl YaDeserialize for Resource { 165 | fn deserialize(reader: &mut yaserde::de::Deserializer) -> Result { 166 | loop { 167 | match reader.next_event()? { 168 | xml::reader::XmlEvent::StartElement { .. } => {} 169 | xml::reader::XmlEvent::Characters(ref text_content) => { 170 | return parse_resource_with_type(text_content); 171 | } 172 | _ => { 173 | break; 174 | } 175 | } 176 | } 177 | Err("Unable to parse attribute".to_string()) 178 | } 179 | } 180 | 181 | /// Parses a resource string in format 182 | /// `@[package:]resource_type/resource_name` into three parts 183 | fn parse_resource(resource: &str) -> Result<(Option, String, String), String> { 184 | if resource.is_empty() { 185 | return Err("value of attribute is empty".to_string()); 186 | }; 187 | let split_str: Vec<_> = resource.split('/').collect(); 188 | if split_str.len() != 2 { 189 | return Err( 190 | "a wrong resource format, expected format @[package:]resource_type/resource_name" 191 | .to_string(), 192 | ); 193 | }; 194 | let first_part = split_str.first().unwrap(); // Can be unwraped because we checked the length. 195 | let resource_type = &first_part[1..]; 196 | let split_type: Vec<_> = resource_type.split(':').collect(); 197 | let (resource_type, package) = if split_type.len() == 2 { 198 | (split_type[1], Some(split_type[0].to_string())) 199 | } else { 200 | (split_type[0], None) 201 | }; 202 | let resource_name = split_str.get(1).unwrap(); // Can be unwraped because we checked the length. 203 | Ok(( 204 | package, 205 | resource_type.to_string(), 206 | resource_name.to_string(), 207 | )) 208 | } 209 | 210 | /// Parses a resource string into given `Resource` 211 | fn parse_resource_with_type(resource: &str) -> Result, String> { 212 | let (package, resource_type, resource_name) = parse_resource(resource)?; 213 | if resource_type != T::resource_type() { 214 | return Err(format!( 215 | "a wrong resource type, expected @[package:]{}/{}, found {}", 216 | T::resource_type(), 217 | resource_name, 218 | resource 219 | )); 220 | }; 221 | Ok(Resource { 222 | name: resource_name, 223 | package, 224 | phantom: PhantomData, 225 | }) 226 | } 227 | -------------------------------------------------------------------------------- /src/activity_alias.rs: -------------------------------------------------------------------------------- 1 | use crate::VarOrBool; 2 | 3 | use super::intent_filter::IntentFilter; 4 | use super::meta_data::MetaData; 5 | use super::resources::{MipmapOrDrawableResource, Resource, StringResource}; 6 | use serde::{Deserialize, Serialize}; 7 | 8 | /// An alias for an activity, named by the `targetActivity` attribute. 9 | /// 10 | /// The target must be in the same application as the alias and it must be declared before 11 | /// the alias in the manifest. 12 | /// 13 | /// The alias presents the target activity as an independent entity. It can have its own 14 | /// set of intent filters, and they, rather than the intent filters on the target activity 15 | /// itself, determine which intents can activate the target through the alias and how the 16 | /// system treats the alias. For example, the intent filters on the alias may specify the 17 | /// "[`android.intent.action.MAIN`]" and "[`android.intent.category.LAUNCHER`]" flags, 18 | /// causing it to be represented in the application launcher, even though none of the 19 | /// filters on the target activity itself set these flags. 20 | /// 21 | /// With the exception of `targetActivity`, `` attributes are a subset of 22 | /// [``] attributes. For attributes in the subset, none of the values set for 23 | /// the target carry over to the alias. However, for attributes not in the subset, the 24 | /// values set for the target activity also apply to the alias. 25 | /// 26 | /// ## XML Syntax 27 | /// ```xml 28 | /// 35 | /// ... 36 | /// 37 | /// ``` 38 | /// 39 | /// ## Contained in 40 | /// * [``] 41 | /// 42 | /// ## Can contain 43 | /// * [``] 44 | /// * [``] 45 | /// 46 | /// ## Introduced in 47 | /// API Level 1 48 | /// 49 | /// [``]: crate::Application 50 | /// [``]: crate::IntentFilter 51 | /// [``]: crate::MetaData 52 | /// [``]: crate::Activity 53 | /// [`android.intent.action.MAIN`]: https://developer.android.com/reference/android/content/Intent#ACTION_MAIN 54 | /// [`android.intent.category.LAUNCHER`]: https://developer.android.com/reference/android/content/Intent#CATEGORY_LAUNCHER 55 | #[derive( 56 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 57 | )] 58 | pub struct ActivityAlias { 59 | /// Whether or not the target activity can be instantiated by the system through this 60 | /// alias — "`true`" if it can be, and "`false`" if not. The default value is 61 | /// "`true`". 62 | /// 63 | /// The [``] element has its own [`enabled`] attribute that applies to 64 | /// all application components, including activity aliases. The [``] 65 | /// and `` attributes must both be "`true`" for the system 66 | /// to be able to instantiate the target activity through the alias. If 67 | /// either is "`false`", the alias does not work. 68 | /// 69 | /// [``]: crate::Application 70 | /// [`enabled`]: crate::Application#structfield.enabled 71 | #[yaserde(attribute = true, prefix = "android")] 72 | pub enabled: Option, 73 | /// Whether the broadcast receiver can receive messages from non-system sources 74 | /// outside its application — "`true`" if it can, and "`false`" if 75 | /// not. If "`false`", the target activity can be launched through the 76 | /// alias only by components of the same application as the alias or 77 | /// applications with the same user ID. 78 | /// 79 | /// The default value depends on whether the alias contains intent filters. The 80 | /// absence of any filters means that the activity can be invoked through the 81 | /// alias only by specifying the exact name of the alias. This implies that the 82 | /// alias is intended only for application-internal use (since others would not 83 | /// know its name) — so the default value is "`false`". On the other hand, the 84 | /// presence of at least one filter implies that the alias is intended for 85 | /// external use — so the default value is "`true`". 86 | #[yaserde(attribute = true, prefix = "android")] 87 | pub exported: Option, 88 | /// An icon for the target activity when presented to users through the alias. See the 89 | /// [``] element's [`icon`] attribute for more information. 90 | /// 91 | /// [``]: crate::Activity 92 | /// [`icon`]: crate::Activity#structfield.icon 93 | #[yaserde(attribute = true, prefix = "android")] 94 | pub icon: Option, 95 | /// A user-readable label for the alias when presented to users through the alias. See 96 | /// the [``] element's [`label`] attribute for more information. 97 | /// 98 | /// [``]: crate::Activity 99 | /// [`label`]: crate::Activity#structfield.label 100 | #[yaserde(attribute = true, prefix = "android")] 101 | pub label: Option>, 102 | /// A unique name for the alias. The name should resemble a fully qualified class 103 | /// name. But, unlike the name of the target activity, the alias name 104 | /// is arbitrary; it does not refer to an actual class. 105 | #[yaserde(attribute = true, prefix = "android")] 106 | pub name: Option, 107 | /// The name of a permission that clients must have to launch the target activity or 108 | /// get it to do something via the alias. If a caller of [`startActivity()`] or 109 | /// [`startActivityForResult()`] has not been granted the specified permission, 110 | /// the target activity will not be activated. 111 | /// 112 | /// This attribute supplants any permission set for the target activity itself. If it 113 | /// is not set, a permission is not needed to activate the target through the 114 | /// alias. 115 | /// 116 | /// For more information on permissions, see the [`Permissions`] section in 117 | /// the introduction. 118 | /// 119 | /// [`startActivity()`]: https://developer.android.com/reference/android/content/Context#startActivity(android.content.Intent) 120 | /// [`startActivityForResult()`]: https://developer.android.com/reference/android/app/Activity#startActivityForResult(android.content.Intent,%20int) 121 | /// [`Permissions`]: https://developer.android.com/guide/topics/manifest/manifest-intro#perms 122 | #[yaserde(attribute = true, prefix = "android")] 123 | pub permission: Option, 124 | /// The name of the activity that can be activated through the alias. This name must 125 | /// match the `name` attribute of an [``] element that precedes the 126 | /// alias in the manifest. 127 | /// 128 | /// [``]: crate::Activity 129 | #[yaserde(attribute = true, prefix = "android", rename = "targetActivity")] 130 | pub target_activity: Option, 131 | /// List of `` tags. 132 | #[yaserde(rename = "intent-filter")] 133 | #[serde(default, skip_serializing_if = "Vec::is_empty")] 134 | pub intent_filter: Vec, 135 | /// List of `` tags. 136 | #[yaserde(rename = "meta-data")] 137 | #[serde(default, skip_serializing_if = "Vec::is_empty")] 138 | pub meta_data: Vec, 139 | } 140 | -------------------------------------------------------------------------------- /src/uses_configuration.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | use crate::VarOrBool; 4 | 5 | /// Indicates what hardware and software features the application requires. 6 | /// 7 | /// For example, an application might specify that it requires a physical keyboard or a 8 | /// particular navigation device, like a trackball. The specification is used to avoid 9 | /// installing the application on devices where it will not work. 10 | /// 11 | /// ## Note 12 | /// `Most apps should not use this manifest tag` . You should always support input with 13 | /// a directional pad (d-pad) in order to assist sight-impaired users and support devices 14 | /// that provide d-pad input in addition to or instead of touch. information about how to 15 | /// support d-pad input in your app, read [`Enabling Focus Navigation`]. If your app 16 | /// absolutely cannot function without a touchscreen, then instead use the 17 | /// [``] tag to declare the required touchscreen type, ranging from 18 | /// `"android.hardware.faketouch"` for basic touch-style events to more advanced touch 19 | /// types such as `"android.hardware.touchscreen.multitouch.jazzhand"` for distinct input 20 | /// from multiple fingers. 21 | /// 22 | /// ## XML Syntax 23 | /// ```xml 24 | /// 29 | /// ``` 30 | /// 31 | /// ## Contained in 32 | /// * [``] 33 | /// 34 | /// ## Introduced in 35 | /// API Level 3 36 | /// 37 | /// [`Enabling Focus Navigation`]: https://developer.android.com/guide/topics/ui/accessibility/apps#focus-nav 38 | /// [``]: crate::UsesFeature 39 | /// [``]: crate::AndroidManifest 40 | #[derive( 41 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 42 | )] 43 | pub struct UsesConfiguration { 44 | /// Whether or not the application requires a five-way navigation control — `"true"` 45 | /// if it does, and `"false"` if not. A five-way control is one that can move the 46 | /// selection up, down, right, or left, and also provides a way of invoking the 47 | /// current selection. It could be a D-pad (directional pad), trackball, or other 48 | /// device. 49 | /// 50 | /// If an application requires a directional control, but not a control of 51 | /// a particular type, it can set this attribute to "true" and ignore the 52 | /// [`reqNavigation`] attribute. However, if it requires a particular type 53 | /// of directional control, it can ignore this attribute and set 54 | /// `reqNavigation` instead. 55 | /// 56 | /// [`reqNavigation`]: crate::UsesConfiguration#structfield.req_navigation 57 | #[yaserde(attribute = true, prefix = "android", rename = "reqFiveWayNav")] 58 | pub req_five_way_nav: Option, 59 | /// Whether or not the application requires a hardware keyboard — `"true"` if it does, 60 | /// and `"false"` if not. 61 | #[yaserde(attribute = true, prefix = "android", rename = "reqHardKeyboard")] 62 | pub req_hard_keyboard: Option, 63 | /// The type of keyboard the application requires, if any at all. This attribute does 64 | /// not distinguish between hardware and software keyboards. If a hardware 65 | /// keyboard of a certain type is required, specify the type here and also set the 66 | /// reqHardKeyboard attribute to `"true"`. 67 | #[yaserde(attribute = true, prefix = "android", rename = "reqKeyboardType")] 68 | pub req_keyboard_type: Option, 69 | /// The navigation device required by the application, if any. 70 | /// 71 | /// If an application requires a navigational control, but the exact type of 72 | /// control doesn't matter, it can set the [`reqFiveWayNav`] attribute to "true" 73 | /// rather than set this one. 74 | /// 75 | /// [`reqFiveWayNav`]: crate::UsesConfiguration#structfield.req_five_way_nav 76 | #[yaserde(attribute = true, prefix = "android", rename = "reqNavigation")] 77 | pub req_navigation: Option, 78 | /// The type of touch screen the application requires, if any at all. 79 | #[yaserde(attribute = true, prefix = "android", rename = "reqTouchScreen")] 80 | pub req_touch_screen: Option, 81 | } 82 | 83 | /// The type of keyboard the application requires, if any at all. 84 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 85 | #[serde(rename_all = "camelCase")] 86 | #[derive(Default)] 87 | pub enum ReqKeyboardType { 88 | /// The application does not require a keyboard. (A keyboard requirement is 89 | /// not defined.) This is the default value. 90 | #[yaserde(rename = "undefined")] 91 | #[default] 92 | Undefined, 93 | /// The application does not require a keyboard. 94 | #[yaserde(rename = "nokeys")] 95 | Nokeys, 96 | /// The application requires a standard QWERTY keyboard. 97 | #[yaserde(rename = "qwerty")] 98 | Qwerty, 99 | /// The application requires a twelve-key keypad, like those on most phones 100 | /// — with keys for the digits from 0 through 9 plus star (*) and pound (#) 101 | /// keys. 102 | #[yaserde(rename = "twelvekey")] 103 | Twelvekey, 104 | } 105 | 106 | /// The navigation device required by the application, if any. 107 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 108 | #[serde(rename_all = "camelCase")] 109 | #[derive(Default)] 110 | pub enum ReqNavigation { 111 | /// The application does not require any type of navigation control. (The 112 | /// navigation requirement is not defined.) This is the default value. 113 | #[yaserde(rename = "undefined")] 114 | #[default] 115 | Undefined, 116 | /// The application does not require a navigation control. 117 | #[yaserde(rename = "nonav")] 118 | Nonav, 119 | /// The application requires a D-pad (directional pad) for navigation. 120 | #[yaserde(rename = "dpad")] 121 | Dpad, 122 | /// The application requires a trackball for navigation. 123 | #[yaserde(rename = "trackball")] 124 | Trackball, 125 | /// The application requires a navigation wheel. 126 | #[yaserde(rename = "wheel")] 127 | Wheel, 128 | } 129 | 130 | /// The type of touch screen the application requires, if any at all. 131 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 132 | #[serde(rename_all = "camelCase")] 133 | #[derive(Default)] 134 | pub enum ReqTouchScreen { 135 | /// The application doesn't require a touch screen. (The touch screen 136 | /// requirement is undefined.) This is the default value. 137 | #[yaserde(rename = "undefined")] 138 | #[default] 139 | Undefined, 140 | /// The application doesn't require a touch screen. 141 | #[yaserde(rename = "notouch")] 142 | Notouch, 143 | /// The application requires a touch screen that's operated with a stylus. 144 | #[yaserde(rename = "stylus")] 145 | Stylus, 146 | /// The application requires a touch screen that can be operated with a 147 | /// finger. 148 | /// 149 | /// ## Node 150 | /// If some type of touch input is required for your app, you should 151 | /// instead use the [``] tag to declare the required touchscreen 152 | /// type, beginning with `"android.hardware.faketouch"` for basic touch-style 153 | /// events. 154 | /// 155 | /// [``]: crate::UsesFeature 156 | #[yaserde(rename = "finger")] 157 | Finger, 158 | } 159 | -------------------------------------------------------------------------------- /src/layout.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Affect how an activity behaves in multi-window mode. 4 | /// 5 | /// With Android 7.0, the manifest element supports several attributes that 6 | /// affect how an activity behaves in multi-window mode: 7 | /// 8 | /// ## Contained in 9 | /// * [``] 10 | /// 11 | /// [``]: crate::Activity 12 | #[derive( 13 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 14 | )] 15 | pub struct Layout { 16 | /// Default width of the activity when launched in freeform mode. 17 | #[yaserde(attribute = true, prefix = "android", rename = "defaultWidth")] 18 | pub default_width: Option, 19 | /// Default height of the activity when launched in freeform mode. 20 | #[yaserde(attribute = true, prefix = "android", rename = "defaultHeight")] 21 | pub default_height: Option, 22 | /// Initial placement of the activity when launched in freeform mode. See the Gravity 23 | /// reference for suitable values. 24 | #[yaserde(attribute = true, prefix = "android")] 25 | pub gravity: Gravity, 26 | /// Minimum height and minimum width for the activity in both split-screen and 27 | /// freeform modes. If the user moves the divider in split-screen mode to make an 28 | /// activity smaller than the specified minimum, the system crops the activity to 29 | /// the size the user requests. 30 | /// 31 | /// For example, the following code shows how to specify an activity's default size 32 | /// and location, and its minimum size, when the activity is displayed in freeform 33 | /// mode: 34 | /// 35 | /// ## XML Example 36 | /// ```xml 37 | /// 38 | /// 43 | /// 44 | /// ``` 45 | #[yaserde(attribute = true, prefix = "android", rename = "minHeight")] 46 | pub min_height: Option, 47 | /// Minimum height and minimum width for the activity in both split-screen and 48 | /// freeform modes. If the user moves the divider in split-screen mode to make an 49 | /// activity smaller than the specified minimum, the system crops the activity to 50 | /// the size the user requests. 51 | /// 52 | /// For example, the following code shows how to specify an activity's default size 53 | /// and location, and its minimum size, when the activity is displayed in freeform 54 | /// mode: 55 | /// 56 | /// ## XML Example 57 | /// ```xml 58 | /// 59 | /// 64 | /// 65 | /// ``` 66 | #[yaserde(attribute = true, prefix = "android", rename = "minWidth")] 67 | pub min_width: Option, 68 | } 69 | 70 | /// Standard constants and tools for placing an object within a potentially 71 | /// larger container. 72 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 73 | #[serde(rename_all = "camelCase")] 74 | #[derive(Default)] 75 | pub enum Gravity { 76 | /// Raw bit controlling whether the right/bottom edge is clipped to its 77 | /// container, based on the gravity direction being applied. 78 | #[yaserde(rename = "axisClip")] 79 | #[default] 80 | AxisClip, 81 | /// Raw bit controlling how the right/bottom edge is placed. 82 | #[yaserde(rename = "axisPullAfter")] 83 | AxisPullAfter, 84 | /// Raw bit controlling how the left/top edge is placed. 85 | #[yaserde(rename = "axisPullBefore")] 86 | AxisPullBefore, 87 | /// Raw bit indicating the gravity for an axis has been specified. 88 | #[yaserde(rename = "axisSpecified")] 89 | AxisSpecified, 90 | /// Bits defining the horizontal axis. 91 | #[yaserde(rename = "axisXShift")] 92 | AxisXShift, 93 | /// Bits defining the vertical axis. 94 | #[yaserde(rename = "axisYShift")] 95 | AxisYShift, 96 | /// Push object to the bottom of its container, not changing its size. 97 | #[yaserde(rename = "bottom")] 98 | Bottom, 99 | /// Place the object in the center of its container in both the vertical and 100 | /// horizontal axis, not changing its size. 101 | #[yaserde(rename = "center")] 102 | Center, 103 | /// Place object in the horizontal center of its container, not changing its 104 | /// size. 105 | #[yaserde(rename = "centerHorizontal")] 106 | CenterHorizontal, 107 | /// Place object in the vertical center of its container, not changing its 108 | /// size. 109 | #[yaserde(rename = "centerVertical")] 110 | CenterVertical, 111 | /// Flag to clip the edges of the object to its container along the 112 | /// horizontal axis. 113 | #[yaserde(rename = "clipHorizontal")] 114 | ClipHorizontal, 115 | /// Flag to clip the edges of the object to its container along the vertical 116 | /// axis. 117 | #[yaserde(rename = "clipVertical")] 118 | ClipVertical, 119 | /// Special constant to enable clipping to an overall display along the 120 | /// horizontal dimension. 121 | #[yaserde(rename = "displayClipHorizontal")] 122 | DisplayClipHorizontal, 123 | /// Special constant to enable clipping to an overall display along the 124 | /// vertical dimension. 125 | #[yaserde(rename = "displayClipVertical")] 126 | DisplayClipVertical, 127 | /// Push object to x-axis position at the end of its container, not changing 128 | /// its size. 129 | #[yaserde(rename = "end")] 130 | End, 131 | /// Grow the horizontal and vertical size of the object if needed so it 132 | /// completely fills its container. 133 | #[yaserde(rename = "fill")] 134 | Fill, 135 | /// Grow the horizontal size of the object if needed so it completely fills 136 | /// its container. 137 | #[yaserde(rename = "fillHorizontal")] 138 | FillHorizontal, 139 | /// Grow the vertical size of the object if needed so it completely fills 140 | /// its container. 141 | #[yaserde(rename = "fillVertical")] 142 | FillVertical, 143 | /// Binary mask to get the absolute horizontal gravity of a gravity. 144 | #[yaserde(rename = "horizontalGravityMask")] 145 | HorizontalGravityMask, 146 | /// Push object to the left of its container, not changing its size. 147 | #[yaserde(rename = "left")] 148 | Left, 149 | /// Constant indicating that no gravity has been set * 150 | #[yaserde(rename = "noGravity")] 151 | NoGravity, 152 | /// Binary mask for the horizontal gravity and script specific direction 153 | /// bit. 154 | #[yaserde(rename = "relativeHorizontalGravityMask")] 155 | RelativeHorizontalGravityMask, 156 | /// Raw bit controlling whether the layout direction is relative or not 157 | /// (START/END instead of absolute LEFT/RIGHT). 158 | #[yaserde(rename = "relativeLayoutDirection")] 159 | RelativeLayoutDirection, 160 | /// Push object to the right of its container, not changing its size. 161 | #[yaserde(rename = "right")] 162 | Right, 163 | /// Push object to x-axis position at the start of its container, not 164 | /// changing its size. 165 | #[yaserde(rename = "start")] 166 | Start, 167 | /// Push object to the top of its container, not changing its size. 168 | #[yaserde(rename = "top")] 169 | Top, 170 | /// Binary mask to get the vertical gravity of a gravity. 171 | #[yaserde(rename = "verticalGravityMask")] 172 | VerticalGravityMask, 173 | } 174 | -------------------------------------------------------------------------------- /src/permission.rs: -------------------------------------------------------------------------------- 1 | use super::resources::{ 2 | MipmapOrDrawableResource, Resource, StringResource, StringResourceOrString, 3 | }; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | /// Declares a security permission. 7 | /// 8 | /// That can be used to limit access to specific components or features of this 9 | /// or other applications. See the [`Permissions`] section in the introduction, and the 10 | /// [`Security and Permissions`] document for more information on how permissions work. 11 | /// 12 | /// ## XML Syntax 13 | /// ```xml 14 | /// 21 | /// ``` 22 | /// 23 | /// ## Contained in 24 | /// * [``] 25 | /// 26 | /// ## Introduced in 27 | /// API Level 1 28 | /// 29 | /// [``]: crate::AndroidManifest 30 | /// [`Permissions`]: https://developer.android.com/guide/topics/manifest/manifest-intro#perms 31 | /// [`Security and Permissions`]: https://developer.android.com/training/articles/security-tips 32 | #[derive( 33 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 34 | )] 35 | pub struct Permission { 36 | /// A user-readable description of the permission, longer and more informative than 37 | /// the label. It may be displayed to explain the permission to the user — for 38 | /// example, when the user is asked whether to grant the permission to another 39 | /// application. 40 | /// 41 | /// This attribute must be set as a reference to a string resource; unlike the `label` 42 | /// unlike the `label` attribute, it cannot be a raw string. 43 | #[yaserde(attribute = true, prefix = "android")] 44 | pub description: Option>, 45 | /// A reference to a drawable resource for an icon that represents the permission. 46 | #[yaserde(attribute = true, prefix = "android")] 47 | pub icon: Option, 48 | /// A name for the permission, one that can be displayed to users. As a convenience, 49 | /// the label can be directly set as a raw string while you're developing the 50 | /// application. However, when the application is ready to be published, it should 51 | /// be set as a reference to a string resource, so that it can be localized like 52 | /// other strings in the user interface. 53 | #[yaserde(attribute = true, prefix = "android")] 54 | pub label: Option, 55 | /// The name of the permission. This is the name that will be used in code to refer to 56 | /// the permission — for example, in a [``] element and the 57 | /// permission attributes of application components. 58 | /// 59 | /// ## Note 60 | /// The system does not allow multiple packages to declare a permission with 61 | /// the same name, unless all the packages are signed with the same 62 | /// certificate. If a package declares a permission, the system does not 63 | /// permit the user to install other packages with the same permission 64 | /// name, unless those packages are signed with the same certificate as 65 | /// the first package. To avoid naming collisions, we recommend using 66 | /// reverse-domain-style naming for custom permissions, for example 67 | /// `com.example.myapp.ENGAGE_HYPERSPACE`. 68 | /// 69 | /// [``]: crate::UsesPermission 70 | #[yaserde(attribute = true, prefix = "android")] 71 | pub name: Option, 72 | /// Assigns this permission to a group. The value of this attribute is the name of the 73 | /// group, which must be declared with the [``] element in this 74 | /// or another application. If this attribute is not set, the permission does not 75 | /// belong to a group. 76 | /// 77 | /// [``]: crate::PermissionGroup 78 | #[yaserde(attribute = true, prefix = "android", rename = "permissionGroup")] 79 | pub permission_group: Option, 80 | /// Characterizes the potential risk implied in the permission and indicates the 81 | /// procedure the system should follow when determining whether or not to grant 82 | /// the permission to an application requesting it. 83 | /// 84 | /// Each protection level consists of a base permission type and zero or more flags. 85 | /// For example, the `"dangerous"` protection level has no flags. In contrast, 86 | /// the protection level `"signature|privileged"` is a combination of the 87 | /// `"signature"` base permission type and the `"privileged"` flag. 88 | #[yaserde(attribute = true, prefix = "android", rename = "protectionLevel")] 89 | pub protection_level: Option, 90 | } 91 | 92 | /// The following table shows all base permission types. For a list of flags, 93 | /// see [`protectionLevel`]. 94 | /// 95 | /// [`protectionLevel`]: https://developer.android.com/reference/android/R.attr#protectionLevel 96 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 97 | #[serde(rename_all = "camelCase")] 98 | #[derive(Default)] 99 | pub enum ProtectionLevel { 100 | /// The default value. A lower-risk permission that gives requesting applications 101 | /// access to isolated application-level features, with minimal risk to other 102 | /// applications, the system, or the user. The system automatically grants this 103 | /// type of permission to a requesting application at installation, without asking 104 | /// for the user's explicit approval (though the user always has the option to 105 | /// review these permissions before installing). 106 | #[yaserde(rename = "normal")] 107 | #[default] 108 | Normal, 109 | /// A higher-risk permission that would give a requesting application access to 110 | /// private user data or control over the device that can negatively impact the 111 | /// user. Because this type of permission introduces potential risk, the system 112 | /// may not automatically grant it to the requesting application. For example, any 113 | /// dangerous permissions requested by an application may be displayed to the user 114 | /// and require confirmation before proceeding, or some other approach may 115 | /// be taken to avoid the user automatically allowing the use of such 116 | /// facilities. 117 | #[yaserde(rename = "dangerous")] 118 | Dangerous, 119 | /// A permission that the system grants only if the requesting application is signed 120 | /// with the same certificate as the application that declared the permission. If 121 | /// the certificates match, the system automatically grants the permission without 122 | /// notifying the user or asking for the user's explicit approval. 123 | #[yaserde(rename = "signature")] 124 | Signature, 125 | /// Old synonym for `"signature|privileged"`. Deprecated in API level 23. A permission 126 | /// that the system grants only to applications that are in a dedicated folder on 127 | /// the Android system image or that are signed with the same certificate as the 128 | /// application that declared the permission. Avoid using this option, as the 129 | /// signature protection level should be sufficient for most needs and works 130 | /// regardless of exactly where apps are installed. 131 | /// The "signatureOrSystem" permission is used for certain special 132 | /// situations where multiple vendors have applications 133 | /// built into a system image and need to share specific features 134 | /// explicitly because they are being built together. 135 | #[yaserde(rename = "signatureOrSystem")] 136 | SignatureOrSystem, 137 | } 138 | -------------------------------------------------------------------------------- /src/data.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Adds a data specification to an intent filter. 4 | /// 5 | /// The specification can be just a data type (the mimeType attribute), 6 | /// just a URI, or both a data type and a URI. A URI is specified 7 | /// by separate attributes for each of its parts: 8 | /// 9 | /// ```xml 10 | /// ://:[||] 11 | /// ``` 12 | /// 13 | /// ## XML Examples 14 | /// These attributes that specify the URL format are optional, but also mutually 15 | /// dependent: 16 | /// * If a [`scheme`] is not specified for the intent filter, all the other URI attributes 17 | /// are ignored. 18 | /// * If a [`host`] is not specified for the filter, the port attribute and all the path 19 | /// attributes are ignored. 20 | /// 21 | /// All the `` elements contained within the same [``] 22 | /// element contribute to the same filter. So, for example, the following filter 23 | /// specification, 24 | /// 25 | /// ```xml 26 | /// 27 | /// 28 | /// ... 29 | /// 30 | /// ``` 31 | /// 32 | /// is equivalent to this one: 33 | /// 34 | /// ```xml 35 | /// 36 | /// 37 | /// 38 | /// ... 39 | /// 40 | /// ``` 41 | /// 42 | /// You can place any number of elements inside an [``] to 43 | /// give it multiple data options. None of its attributes have default values. 44 | /// 45 | /// Information on how intent filters work, including the rules for how Intent objects are 46 | /// matched against filters, can be found in another document, [`Intents and Intent 47 | /// Filters`]. See also the [`Intent Filters`] section in the manifest file overview. 48 | /// 49 | /// ## XML Syntax 50 | /// ```xml 51 | /// 58 | /// ``` 59 | /// 60 | /// ## Contained in 61 | /// * [``] 62 | /// 63 | /// ## Introduced in 64 | /// API Level 1 65 | /// 66 | /// [`scheme`]: crate::Data#structfield.scheme 67 | /// [`host`]: crate::Data#structfield.host 68 | /// [``]: crate::IntentFilter 69 | /// [`Intents and Intent Filters`]: https://developer.android.com/guide/components/intents-filters 70 | /// [`Intent Filters`]: https://developer.android.com/guide/topics/manifest/manifest-intro#ifs 71 | #[derive( 72 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 73 | )] 74 | pub struct Data { 75 | /// The scheme part of a URI. This is the minimal essential attribute for specifying a 76 | /// URI; at least one scheme attribute must be set for the filter, or none of the 77 | /// other URI attributes are meaningful. 78 | /// 79 | /// A scheme is specified without the trailing colon (for example, http, rather than 80 | /// http:). 81 | /// 82 | /// If the filter has a data type set (the [`mimeType`] attribute) but no scheme, the 83 | /// `content:` and `file:` schemes are assumed. 84 | /// 85 | /// ## Note 86 | /// Scheme matching in the Android framework is case-sensitive, unlike the RFC. As a 87 | /// result, you should always specify schemes using lowercase letters. 88 | /// 89 | /// [`mimeType`]: crate::Data#structfield.mime_type 90 | #[yaserde(attribute = true, prefix = "android")] 91 | pub scheme: Option, 92 | /// The host part of a URI authority. This attribute is meaningless unless a 93 | /// [`scheme`] attribute is also specified for the filter. To match multiple 94 | /// subdomains, use an asterisk (*) to match zero or more characters in the 95 | /// host. For example, the host `*.google.com` matches `www.google.com`, 96 | /// `.google.com`, and `developer.google.com.` 97 | /// 98 | /// The asterisk must be the first character of the host attribute. For example, the 99 | /// host `google.co.` is invalid because the asterisk wildcard is not the first 100 | /// character. 101 | /// 102 | /// ## Note 103 | /// host name matching in the Android framework is case-sensitive, 104 | /// unlike the formal RFC. As a result, you should always specify host names 105 | /// using lowercase letters. 106 | /// 107 | /// [`scheme`]: crate::Data#structfield.scheme 108 | #[yaserde(attribute = true, prefix = "android")] 109 | pub host: Option, 110 | /// The port part of a URI authority. This attribute is meaningful only if the 111 | /// [`scheme`] and [`host`] attributes are also specified for the filter. 112 | /// 113 | /// [`scheme`]: crate::Data#structfield.scheme 114 | /// [`host`]: crate::Data#structfield.host 115 | #[yaserde(attribute = true, prefix = "android")] 116 | pub port: Option, 117 | /// The path part of a URI which must begin with a /. The path attribute specifies a 118 | /// complete path that is matched against the complete path in an Intent object. 119 | /// The `pathPrefix` attribute specifies a partial path that is matched against 120 | /// only the initial part of the path in the Intent object. The pathPattern 121 | /// attribute specifies a complete path that is matched against the complete path 122 | /// in the Intent object, but it can contain the following wildcards: 123 | /// 124 | /// * An asterisk `('*')` matches a sequence of 0 to many occurrences of the 125 | /// immediately preceding character. 126 | /// * A period followed by an asterisk `(".*")` matches any sequence of 0 to many 127 | /// characters. 128 | /// 129 | /// Because `'\'` is used as an escape character when the string is read from XML 130 | /// (before it is parsed as a pattern) , you will need to double-escape: For 131 | /// example, a literal `'*'` would be written as `"\\*"` and a literal `'\'` would 132 | /// be written as `"\\\\"`. This is basically the same as what you would need to 133 | /// write if constructing the string in Java code. 134 | /// 135 | /// For more information on these three types of patterns, see the descriptions of 136 | /// [`PATTERN_LITERAL`], [`PATTERN_PREFIX`], and [`PATTERN_SIMPLE_GLOB`] in the 137 | /// [`PatsternMatcher`] class. 138 | /// 139 | /// These attributes are meaningful only if the [`scheme`] and [`host`] attributes are 140 | /// also specified for the filter. 141 | /// 142 | /// [`PATTERN_LITERAL`]: https://developer.android.com/reference/android/os/PatternMatcher#PATTERN_LITERAL 143 | /// [`PATTERN_PREFIX`]: https://developer.android.com/reference/android/os/PatternMatcher#PATTERN_PREFIX 144 | /// [`PATTERN_SIMPLE_GLOB`]: https://developer.android.com/reference/android/os/PatternMatcher#PATTERN_SIMPLE_GLOB 145 | /// [`PatsternMatcher`]: https://developer.android.com/reference/android/os/PatternMatcher 146 | /// [`scheme`]: crate::Data#structfield.scheme 147 | /// [`host`]: crate::Data#structfield.host 148 | #[yaserde(attribute = true, prefix = "android")] 149 | pub path: Option, 150 | #[yaserde(attribute = true, prefix = "android", rename = "pathPattern")] 151 | pub path_pattern: Option, 152 | #[yaserde(attribute = true, prefix = "android", rename = "pathPrefix")] 153 | pub path_prefix: Option, 154 | /// A MIME media type, such as `image/jpeg` or `audio/mpeg4-generic`. The 155 | /// subtype can be the asterisk wildcard (*) to indicate that any subtype 156 | /// matches. 157 | /// 158 | /// It's common for an intent filter to declare a `` that includes only the 159 | /// android:mimeType attribute. 160 | /// 161 | /// ## Note 162 | /// MIME type matching in the Android framework is case-sensitive, 163 | /// unlike formal RFC MIME types. As a result, you should always specify 164 | /// MIME types using lowercase letters. 165 | #[yaserde(attribute = true, prefix = "android", rename = "mimeType")] 166 | pub mime_type: Option, 167 | } 168 | -------------------------------------------------------------------------------- /src/uses_sdk.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Lets you express an application's compatibility with one or more versions of the 4 | /// Android platform, by means of an API Level integer. 5 | /// 6 | /// The API Level expressed by an application will be compared to the API Level of a given 7 | /// Android system, which may vary among different Android devices. 8 | /// Despite its name, this element is used to specify the API Level, not the version 9 | /// number of the SDK (software development kit) or Android platform. The API Level is 10 | /// always a single integer. You cannot derive the API Level from its associated Android 11 | /// version number (for example, it is not the same as the major version or the sum of the 12 | /// major and minor versions). [`Versioning Your Applications.`] 13 | /// 14 | /// ## Note 15 | /// Google Play uses the attributes declared in your app manifest to filter 16 | /// your app from devices that do not meet its platform version requirements. Before 17 | /// setting these attributes, make sure that you understand [`Google Play filters`]. 18 | /// 19 | /// ## XML Syntax 20 | /// ```xml 21 | /// 24 | /// ``` 25 | /// 26 | /// ## Contained in 27 | /// [``] 28 | /// 29 | /// ## introduced in 30 | /// API Level 1 31 | /// 32 | /// [`Versioning Your Applications.`]: https://developer.android.com/studio/publish/versioning 33 | /// [`Google Play filters`]: https://developer.android.com/google/play/filters 34 | /// [``]: crate::AndroidManifest 35 | #[derive( 36 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 37 | )] 38 | pub struct UsesSdk { 39 | /// An integer designating the minimum API Level required for the application to run. 40 | /// The Android system will prevent the user from installing the application if 41 | /// the system's API Level is lower than the value specified in this attribute. 42 | /// You should always declare this attribute. 43 | /// 44 | /// ## Caution 45 | /// If you do not declare this attribute, the system assumes a default value of "1", 46 | /// which indicates that your application is compatible with all versions of 47 | /// Android. If your application is not compatible with all versions (for 48 | /// instance, it uses APIs introduced in API Level 3) and you have not declared 49 | /// the proper `minSdkVersion`, then when installed on a system with an API Level 50 | /// less than 3, the application will crash during runtime when attempting to 51 | /// access the unavailable APIs. For this reason, be certain to declare the 52 | /// appropriate API Level in the `minSdkVersion` attribute. 53 | #[yaserde(attribute = true, prefix = "android", rename = "minSdkVersion")] 54 | pub min_sdk_version: Option, 55 | /// An integer designating the API Level that the application targets. If not set, the 56 | /// default value equals that given to `minSdkVersion`. This attribute informs the 57 | /// system that you have tested against the target version and the system should 58 | /// not enable any compatibility behaviors to maintain your app's 59 | /// forward-compatibility with the target version. The application is still able 60 | /// to run on older versions (down to minSdkVersion). As Android evolves with each 61 | /// new version, some behaviors and even appearances might change. However, if the 62 | /// API level of the platform is higher than the version declared by your app's 63 | /// targetSdkVersion the system may enable compatibility behaviors to 64 | /// ensure that your app continues to work the way you expect.You can 65 | /// disable such compatibility behaviors by specifying targetSdkVersion 66 | /// to match the API level of the platform on which it's running. For 67 | /// example, setting this value to "11" or higher allows the system to apply 68 | /// a new default theme (Holo) to your app when running on Android 3.0 69 | /// or higher and also disables [`screen compatibility mode`] when running on 70 | /// larger screens (because support for API level 11 implicitly supports 71 | /// larger screens). 72 | /// 73 | /// There are many compatibility behaviors that the system may enable based on the 74 | /// value you set for this attribute. Several of these behaviors are described by 75 | /// the corresponding platform versions in the [`Build.VERSION_CODES`] reference. 76 | /// 77 | /// To maintain your application along with each Android release, you should increase 78 | /// the value of this attribute to match the latest API level, then thoroughly 79 | /// test your application on the corresponding platform version. 80 | /// 81 | /// Introduced in: API Level 4 82 | /// 83 | /// [`screen compatibility mode`]: https://developer.android.com/guide/topics/manifest/supports-screens-element#compat-mode 84 | /// [`Build.VERSION_CODES`]: https://developer.android.com/reference/android/os/Build.VERSION_CODES 85 | #[yaserde(attribute = true, prefix = "android", rename = "targetSdkVersion")] 86 | pub target_sdk_version: Option, 87 | /// An integer designating the maximum API Level on which the application is designed 88 | /// to run. In Android 1.5, 1.6, 2.0, and 2.0.1, the system checks the value of 89 | /// this attribute when installing an application and when re-validating the 90 | /// application after a system update. In either case, if the application's 91 | /// maxSdkVersion attribute is lower than the API Level used by the system itself, 92 | /// then the system will not allow the application to be installed. In the case of 93 | /// re-validation after system update, this effectively removes your application 94 | /// from the device. 95 | /// 96 | /// To illustrate how this attribute can affect your application 97 | /// after system updates, consider the following example: 98 | /// 99 | /// An application declaring maxSdkVersion="5" in its manifest is published on Google 100 | /// Play. A user whose device is running Android 1.6 (API Level 4) downloads and 101 | /// installs the app. After a few weeks, the user receives an 102 | /// over-the-air system update to Android 2.0 (API Level 5). After the 103 | /// update is installed, the system checks the application's maxSdkVersion 104 | /// and successfully re-validates it. The application functions as 105 | /// normal. However, some time later, the device receives another system 106 | /// update, this time to Android 2.0.1 (API Level 6). After the update, the 107 | /// system can no longer re-validate the application because the system's 108 | /// own API Level (6) is now higher than the maximum supported by the 109 | /// application (5). The system prevents the application from being 110 | /// visible to the user, in effect removing it from the device. 111 | /// 112 | /// ## Warning 113 | /// Declaring this attribute is not recommended. First, there is no need to set the 114 | /// attribute as means of blocking deployment of your application onto new 115 | /// versions of the Android platform as they are released. By design, new versions 116 | /// of the platform are fully backward-compatible. Your application should work 117 | /// properly on new versions, provided it uses only standard APIs and follows 118 | /// development best practices. Second, note that in some cases, declaring 119 | /// the attribute can result in your application being removed from users' 120 | /// devices after a system update to a higher API Level. Most devices on 121 | /// which your application is likely to be installed will receive periodic 122 | /// system updates over the air, so you should consider their effect on your 123 | /// application before setting this attribute. 124 | /// 125 | /// Introduced in: API Level 4 126 | /// 127 | /// ## Important 128 | /// Future versions of Android (beyond Android 2.0.1) will no longer check or enforce 129 | /// the `maxSdkVersion` attribute during installation or re-validation. Google Play 130 | /// will continue to use the attribute as a filter, however, when presenting users 131 | /// with applications available for download. 132 | #[yaserde(attribute = true, prefix = "android", rename = "maxSdkVersion")] 133 | pub max_sdk_version: Option, 134 | } 135 | -------------------------------------------------------------------------------- /src/uses_feature.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | use crate::VarOrBool; 4 | 5 | /// Declares a single hardware or software feature that is used by the 6 | /// application. 7 | /// 8 | /// The purpose of a declaration is to inform any external entity 9 | /// of the set of hardware and software features on which your application 10 | /// depends. The element offers a required attribute that lets you specify 11 | /// whether your application requires and cannot function without the declared 12 | /// feature, or whether it prefers to have the feature but can function without 13 | /// it. Because feature support can vary across Android devices, the 14 | /// element serves an important role in letting an application 15 | /// describe the device-variable features that it uses. 16 | /// 17 | /// The set of available features that your application declares corresponds to 18 | /// the set of feature constants made available by the Android [`PackageManager`], 19 | /// which are listed for convenience in the [`Features Reference`] sections at the 20 | /// bottom of this document. 21 | /// 22 | /// You must specify each feature in a separate `` element, so if 23 | /// your application requires multiple features, it would declare multiple 24 | /// `` elements. For example, an application that requires both 25 | /// 26 | /// Bluetooth and camera features in the device would declare these two 27 | /// elements: 28 | /// 29 | /// ```xml 30 | /// 31 | /// 32 | /// ``` 33 | /// In general, you should always make sure to declare `` elements 34 | /// for all of the features that your application requires. 35 | /// 36 | /// Declared `` elements are informational only, meaning that the 37 | /// Android system itself does not check for matching feature support on the 38 | /// device before installing an application. However, other services (such as 39 | /// Google Play) or applications may check your application's `` 40 | /// declarations as part of handling or interacting with your application. For 41 | /// this reason, it's very important that you declare all of the features (from 42 | /// the list below) that your application uses. 43 | /// 44 | /// For some features, there may exist a specific attribute that allows you to 45 | /// define a version of the feature, such as the version of Open GL used 46 | /// (declared with [`glEsVersion`]). Other features that either do or do not exist 47 | /// for a device, such as a camera, are declared using the [`name`] attribute. 48 | /// 49 | /// Although the element is only activated for devices running 50 | /// API Level 4 or higher, it is recommended to include these elements for all 51 | /// applications, even if the [`minSdkVersion`] is "3" or lower. Devices running 52 | /// older versions of the platform will simply ignore the element. 53 | /// 54 | /// ## Note 55 | /// When declaring a feature, remember that you must also request permissions as 56 | /// appropriate. For example, you must still request the [`CAMERA`] permission 57 | /// before your application can access the camera API. Requesting the permission 58 | /// grants your application access to the appropriate hardware and software, 59 | /// while declaring the features used by your application ensures proper device 60 | /// compatibility. 61 | /// 62 | /// ## Important 63 | /// Google Play uses the elements declared in your app manifest to filter 64 | /// your app from devices that do not meet its hardware and software feature requirements. 65 | /// 66 | /// By specifying the features that your application requires, you enable Google Play to 67 | /// present your application only to users whose devices meet the application's feature 68 | /// requirements, rather than presenting it to all users.s 69 | /// 70 | /// For important information about how Google Play uses features as the basis for 71 | /// filtering, please read [`Google Play and Feature-Based Filtering`], below. 72 | /// 73 | /// ## XML Syntax 74 | /// ```xml 75 | /// 78 | /// ``` 79 | /// 80 | /// ## Contained in 81 | /// * [``] 82 | /// 83 | /// ## Introduced in 84 | /// API Level 4 85 | /// 86 | /// [`PackageManager`]: https://developer.android.com/reference/android/content/pm/PackageManagers 87 | /// [`Features Reference`]: https://developer.android.com/guide/topics/manifest/uses-feature-element#features-reference 88 | /// [`glEsVersion`]: crate::UsesFeature#structfield.gl_es_version 89 | /// [`name`]: crate::UsesFeature#structfield.name 90 | /// [`CAMERA`]: https://developer.android.com/reference/android/Manifest.permission#CAMERA 91 | /// [`minSdkVersion`]: crate::UsesSdk#structfield.min_sdk_version 92 | /// [`Google Play and Feature-Based Filtering`]: https://developer.android.com/guide/topics/manifest/uses-feature-element#market-feature-filtering 93 | /// [``]: crate::AndroidManifest 94 | #[derive( 95 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 96 | )] 97 | pub struct UsesFeature { 98 | /// Specifies a single hardware or software feature used by the application, 99 | /// as a descriptor string. Valid attribute values are listed in the 100 | /// [`Hardware features`] and [`Software features`] sections. These attribute 101 | /// values are case-sensitive. 102 | /// 103 | /// [`Hardware features`]: https://developer.android.com/guide/topics/manifest/uses-feature-element#hw-features 104 | /// [`Software features`]: https://developer.android.com/guide/topics/manifest/uses-feature-element#sw-features 105 | #[yaserde(attribute = true, prefix = "android")] 106 | pub name: Option, 107 | /// Boolean value that indicates whether the application requires the feature 108 | /// specified in `android:name`. 109 | /// 110 | /// * When you declare `android:required="true"` for a feature, you are specifying 111 | /// that the 112 | /// application cannot function, or is not designed to function, when the 113 | /// specified feature is not present on the device. 114 | /// * When you declare `android:required="false"` for a feature, it means that the 115 | /// application 116 | /// prefers to use the feature if present on the device, but that it is designed to 117 | /// function without the specified feature, if necessary. 118 | /// 119 | /// The default value for android:required if not declared is `"true"`. 120 | #[yaserde(attribute = true, prefix = "android")] 121 | pub required: Option, 122 | /// The OpenGL ES version required by the application. The higher 16 bits represent 123 | /// the major number and the lower 16 bits represent the minor number. For 124 | /// example, to specify OpenGL ES version 2.0, you would set the value as 125 | /// "0x00020000", or to specify OpenGL ES 3.2, you would set the value as 126 | /// "0x00030002". An application should specify at most one `android:glEsVersion` 127 | /// attribute in its manifest. If it specifies more than one, the android: 128 | /// glEsVersion` with the numerically highest value is used and any other values 129 | /// are ignored. 130 | /// 131 | /// If an application does not specify an android:glEsVersion 132 | /// attribute, then it is assumed that the application requires only OpenGL ES 133 | /// 1.0, which is supported by all Android-powered devices. 134 | /// 135 | /// An application can assume that if a platform supports a given OpenGL ES version, 136 | /// it also supports all numerically lower OpenGL ES versions. Therefore, an 137 | /// application that requires both OpenGL ES 1.0 and OpenGL ES 2.0 must specify 138 | /// that it requires OpenGL ES 2.0. 139 | /// 140 | /// An application that can work with any of several OpenGL ES versions should only 141 | /// specify the numerically lowest version of OpenGL ES that it requires. 142 | /// 143 | /// For more information about using OpenGL ES, including how to check the 144 | /// supported OpenGL ES version at runtime, see the [`OpenGL ES API guide`]. 145 | /// 146 | /// [`OpenGL ES API guide`]: https://developer.android.com/guide/topics/graphics/opengl 147 | #[yaserde(attribute = true, prefix = "android", rename = "glEsVersion")] 148 | pub gl_es_version: Option, 149 | } 150 | -------------------------------------------------------------------------------- /src/intent_filter.rs: -------------------------------------------------------------------------------- 1 | use super::action::Action; 2 | use super::category::Category; 3 | use super::data::Data; 4 | use super::resources::{MipmapOrDrawableResource, StringResourceOrString}; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | /// Specifies the types of intents that an activity, service, or broadcast receiver can 8 | /// respond to. 9 | /// 10 | /// An intent filter declares the capabilities of its parent component — what an activity 11 | /// or service can do and what types of broadcasts a receiver can handle. It opens the 12 | /// component to receiving intents of the advertised type, while filtering out those that 13 | /// are not meaningful for the component. Most of the contents of the filter are 14 | /// described by its [``], [``], and [``] subelements. 15 | /// 16 | /// For a more detailed discussion of filters, see the separate [`Intents and Intent 17 | /// Filters`] document, as well as the [`Intents Filters`] 18 | /// section in the introduction. 19 | /// 20 | /// ## XML Syntax 21 | /// ```xml 22 | /// 25 | /// ... 26 | /// 27 | /// ``` 28 | /// 29 | /// ## Contained in 30 | /// * [``] 31 | /// * [``] 32 | /// * [``] 33 | /// * [``] 34 | /// * [``] 35 | /// 36 | /// ## Must contain 37 | /// * [``] 38 | /// 39 | /// ## Can contain 40 | /// * [``] 41 | /// * [``] 42 | /// 43 | /// ## Introduced in 44 | /// API Level 1 45 | /// 46 | /// [`Intents and Intent Filters`]: https://developer.android.com/guide/components/intents-filters 47 | /// [`Intents Filters`]: https://developer.android.com/guide/topics/manifest/manifest-intro#ifs 48 | /// [``]: crate::Activity 49 | /// [``]: crate::ActivityAlias 50 | /// [``]: crate::Service 51 | /// [``]: crate::Receiver 52 | /// [``]: crate::Provider 53 | /// [``]: crate::Action 54 | /// [``]: crate::Category 55 | /// [``]: crate::Data 56 | #[derive( 57 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 58 | )] 59 | pub struct IntentFilter { 60 | /// An icon that represents the parent activity, service, or broadcast receiver when 61 | /// that component is presented to the user as having the capability described by 62 | /// the filter. 63 | /// 64 | /// This attribute must be set as a reference to a drawable resource containing the 65 | /// image definition. The default value is the icon set by the parent component's 66 | /// icon attribute. If the parent does not specify an icon, the default is the 67 | /// icon set by the [``] element. 68 | /// 69 | /// For more on intent filter icons, see [`Icons and Labels`] in the introduction. 70 | /// 71 | /// [``]: crate::Application 72 | /// [`Icons and Labels`]: https://developer.android.com/guide/topics/manifest/manifest-intro#iconlabel 73 | #[yaserde(attribute = true, prefix = "android")] 74 | pub icon: Option, 75 | /// A user-readable label for the parent component. This label, rather than the one 76 | /// set by the parent component, is used when the component is presented to the 77 | /// user as having the capability described by the filter. The label should be set 78 | /// as a reference to a string resource, so that it can be localized like other 79 | /// strings in the user interface. However, as a convenience while you're 80 | /// developing the application, it can also be set as a raw string. 81 | /// 82 | /// The default value is the label set by the parent component. If the parent does not 83 | /// specify a label, the default is the label set by the [``] 84 | /// element's [`label`] attribute.s 85 | /// 86 | /// For more on intent filter labels, see [`Icons and Labels`] in the introduction. 87 | /// 88 | /// [``]: crate::Application 89 | /// [`label`]: crate::Application#structfield.label 90 | /// [`Icons and Labels`]: https://developer.android.com/guide/topics/manifest/manifest-intro#iconlabel 91 | #[yaserde(attribute = true, prefix = "android")] 92 | pub label: Option, 93 | /// The priority that should be given to the parent component with regard to handling 94 | /// intents of the type described by the filter. This attribute has meaning for 95 | /// both activities and broadcast receivers: 96 | /// 97 | /// * It provides information about how able an activity is to respond to an intent 98 | /// that matches the filter, relative 99 | /// to other activities that could also respond to the intent. When an intent 100 | /// could be handled by multiple activities with different priorities, Android 101 | /// will consider only those with higher priority values as potential targets for 102 | /// the intent. 103 | /// * It controls the order in which broadcast receivers are executed to 104 | /// receive broadcast messages. Those with higher priority values are called 105 | /// before those with lower values. (The order applies only to 106 | /// synchronous messages; it's ignored for asynchronous messages.) 107 | /// 108 | /// Use this attribute only if you really need to impose a specific order in 109 | /// which the broadcasts are received, or want to force Android to prefer 110 | /// one activity over others. The value must be an integer, such as 111 | /// "100". Higher numbers have a higher priority. The default value is 0 112 | /// In certain circumstances the requested priority is ignored and the value 113 | /// is capped to 0. This occurs when: 114 | /// 115 | /// * A non-privileged application requests any priority > 0 116 | /// * A privileged application requests a priority > 0 for [`ACTION_VIEW`], 117 | /// [`ACTION_SEND`], [`ACTION_SENDTO`] or 118 | /// [`ACTION_SEND_MULTIPLE`] 119 | /// 120 | /// Also see [`setPriority()`]. 121 | /// 122 | /// [`ACTION_VIEW`]: https://developer.android.com/reference/android/content/Intent#ACTION_VIEW 123 | /// [`ACTION_SEND`]: https://developer.android.com/reference/android/content/Intent#ACTION_SEND 124 | /// [`ACTION_SENDTO`]: https://developer.android.com/reference/android/content/Intent#ACTION_SENDTO 125 | /// [`ACTION_SEND_MULTIPLE`]: https://developer.android.com/reference/android/content/Intent#ACTION_SEND_MULTIPLE 126 | /// [`setPriority()`]: https://developer.android.com/reference/android/content/IntentFilter#setPriority(int) 127 | #[yaserde(attribute = true, prefix = "android")] 128 | pub priority: Option, 129 | /// The order in which the filter should be processed when multiple filters match. 130 | /// order differs from priority in that priority applies across apps, while order 131 | /// disambiguates multiple matching filters in a single app. 132 | /// 133 | /// When multiple filters could match, use a directed intent instead. 134 | /// 135 | /// The value must be an integer, such as "100". Higher numbers are matched first. The 136 | /// default value is 0. 137 | /// 138 | /// This attribute was introduced in API Level 28. 139 | #[yaserde(attribute = true, prefix = "android")] 140 | pub order: Option, 141 | /// List of `` tags. 142 | #[serde(default, skip_serializing_if = "Vec::is_empty")] 143 | pub action: Vec, 144 | /// List of `` tags. 145 | #[serde(default, skip_serializing_if = "Vec::is_empty")] 146 | pub category: Vec, 147 | /// List of `` tags. 148 | #[serde(default, skip_serializing_if = "Vec::is_empty")] 149 | pub data: Vec, 150 | /// This attribute signals to the system that it should verify whether your app 151 | /// belongs to the URL domains used in your intent filters. 152 | /// 153 | /// See [`verify-android-applinks`] for more information. 154 | /// 155 | /// [`verify-android-applinks`]: https://developer.android.com/training/app-links/verify-android-applinks 156 | #[yaserde(attribute = true, prefix = "android", rename = "autoVerify")] 157 | pub auto_verify: Option, 158 | } 159 | 160 | #[cfg(test)] 161 | mod tests { 162 | use super::*; 163 | 164 | #[test] 165 | fn test_intent_filter_toml_serialize_deserialize() { 166 | let value = IntentFilter { 167 | order: Some(100), 168 | action: vec![Action { 169 | name: Some("android.intent.action.MAIN".to_string()), 170 | }], 171 | category: vec![Category { 172 | name: Some("android.intent.category.LAUNCHER".to_string()), 173 | }], 174 | ..Default::default() 175 | }; 176 | let string = toml::to_string_pretty(&value).unwrap(); 177 | let _value: IntentFilter = toml::from_str(&string).unwrap(); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/compatible_screens.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | /// Specifies each screen configuration with which the application is 4 | /// compatible. 5 | /// 6 | /// Only one instance of the `` element is 7 | /// allowed in the manifest, but it can contain multiple `` elements. 8 | /// Each element specifies a specific screen size-density combination 9 | /// with which the application is compatible. 10 | /// 11 | /// The Android system does not read the `` manifest element (neither 12 | /// at install-time nor at runtime). This element is informational only and may be used by 13 | /// external services (such as Google Play) to better understand the application's 14 | /// compatibility with specific screen configurations and enable filtering for 15 | /// users. Any screen configuration that is not declared in this element is a 16 | /// screen with which the application is not compatible. Thus, external services (such as 17 | /// Google Play) should not provide the application to devices with such screens. 18 | /// 19 | /// ## Caution 20 | /// Normally, you should not use this manifest element. Using this 21 | /// element can dramatically reduce the potential user base for your 22 | /// application, by not allowing users to install your application if they have 23 | /// a device with a screen configuration that you have not listed. You should 24 | /// use it only as a last resort, when the application absolutely does not work 25 | /// with specific screen configurations. Instead of using this element, you 26 | /// should follow the guide to [`Supporting Multiple Screens`] to provide scalable 27 | /// support for multiple screens using alternative layouts and bitmaps for 28 | /// different screen sizes and densities. 29 | /// 30 | /// If you want to set only a minimum screen size for your your application, 31 | /// then you should use the [``] element. For example, if you 32 | /// want your application to be available only for large and xlarge screen 33 | /// devices, the [``] element allows you to declare that your 34 | /// application does not support small and normal screen sizes. External 35 | /// services (such as Google Play) will filter your application accordingly. You 36 | /// can also use the [``] element to declare whether the system 37 | /// should resize your application for different screen sizes. 38 | /// 39 | /// Also see the [`Filters on Google Play`] document for more information about how Google 40 | /// Play filters applications using this and other manifest elements. 41 | /// 42 | /// ## XML Syntax 43 | /// ```xml 44 | /// 45 | /// 48 | /// ... 49 | /// 50 | /// ``` 51 | /// 52 | /// ## Contained in 53 | /// * [``] 54 | /// 55 | /// ## Introduced in 56 | /// API Level 9 57 | /// 58 | /// [`Supporting Multiple Screens`]: https://developer.android.com/guide/practices/screens_support 59 | /// [``]: crate::SupportsScreens 60 | /// [`Filters on Google Play`]: https://developer.android.com/google/play/filters 61 | /// [``]: crate::AndroidManifest 62 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 63 | pub struct CompatibleScreens { 64 | pub screen: Vec, 65 | } 66 | 67 | /// Specifies a single screen configuration with which the application is 68 | /// compatible. 69 | /// 70 | /// At least one instance of this element must be placed inside the 71 | /// `` element. This element must include both the 72 | /// `android:screenSize` and `android:screenDensity` attributes (if you do not 73 | /// declare both attributes, then the element is ignored). 74 | /// 75 | /// ## XML Example 76 | /// If your application is compatible with only small and normal screens, regardless of 77 | /// screen density, then you must specify twelve different elements, because each 78 | /// screen size has six different density configurations. You must declare each one of 79 | /// these; any combination of size and density that you do not specify is considered a 80 | /// screen configuration with which your application is not compatible. Here's what the 81 | /// manifest entry looks like if your application is compatible with only small and normal 82 | /// screens: 83 | /// ```xml 84 | /// 85 | /// ... 86 | /// 87 | /// 88 | /// 89 | /// 90 | /// 91 | /// 92 | /// 93 | /// 94 | /// 95 | /// 96 | /// 97 | /// 98 | /// 99 | /// 100 | /// 101 | /// 102 | /// 103 | /// ... 104 | /// 105 | /// 106 | /// ``` 107 | /// 108 | /// Contained in: 109 | /// [``] 110 | /// 111 | /// [``]: crate::CompatibleScreens 112 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 113 | pub struct Screen { 114 | /// `Required`. Specifies the screen size for this screen configuration. 115 | /// 116 | /// For information about the different screen sizes, see [`Supporting Multiple 117 | /// Screens`]. 118 | /// 119 | /// [`Supporting Multiple Screens`]: https://developer.android.com/guide/practices/screens_support#range 120 | #[yaserde(attribute = true, prefix = "android", rename = "screenSize")] 121 | pub screen_size: ScreenSize, 122 | /// `Required.` Specifies the screen density for this screen configuration. 123 | /// 124 | /// For information about the different screen densities, see [`Supporting Multiple 125 | /// Screens`]. 126 | /// 127 | /// Accepted values: 128 | /// * "ldpi" (approximately 120 dpi) 129 | /// * "mdpi" (approximately 160 dpi) 130 | /// * "hdpi" (approximately 240 dpi) 131 | /// * "xhdpi" (approximately 320 dpi) 132 | /// * "280" 133 | /// * "360" 134 | /// * "420" 135 | /// * "480" 136 | /// * "560" 137 | /// 138 | /// [`Supporting Multiple Screens`]: https://developer.android.com/guide/practices/screens_support#range 139 | #[yaserde(attribute = true, prefix = "android", rename = "screenDensity")] 140 | pub screen_density: String, 141 | } 142 | 143 | /// Android runs on a variety of devices that have different screen sizes and pixel 144 | /// densities. The system performs basic scaling and resizing to adapt your user interface 145 | /// to different screens. 146 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 147 | #[serde(rename_all = "camelCase")] 148 | #[derive(Default)] 149 | pub enum ScreenSize { 150 | /// Screens that are of similar size to a low-density QVGA screen. The minimum layout 151 | /// size for a small screen is approximately 320x426 dp units. Examples are QVGA 152 | /// low-density and VGA high density. 153 | #[yaserde(rename = "small")] 154 | Small, 155 | /// Screens that are of similar size to a medium-density HVGA screen. The minimum 156 | /// layout size for a normal screen is approximately 320x470 dp units. Examples of 157 | /// such screens a WQVGA low-density, HVGA medium-density, WVGA high-density. 158 | #[yaserde(rename = "normal")] 159 | #[default] 160 | Normal, 161 | /// Screens that are of similar size to a medium-density VGA screen. The minimum 162 | /// layout size for a large screen is approximately 480x640 dp units. Examples are VGA 163 | /// and WVGA medium-density screens. 164 | #[yaserde(rename = "large")] 165 | Large, 166 | /// Screens that are considerably larger than the traditional medium-density HVGA 167 | /// screen. The minimum layout size for an xlarge screen is approximately 720x960 dp 168 | /// units. In most cases, devices with extra-large screens would be too large to carry 169 | /// in a pocket and would most likely be tablet-style devices. Added in API level 9. 170 | #[yaserde(rename = "xlarge")] 171 | Xlarge, 172 | } 173 | -------------------------------------------------------------------------------- /src/queries.rs: -------------------------------------------------------------------------------- 1 | use super::action::Action; 2 | use super::attribute_list::{AttributeList, Semicolon}; 3 | use super::data::Data; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | /// Specifies the set of other apps that an app intends to interact with. 7 | /// 8 | /// These other apps can be specified by package name, by intent signature, or by 9 | /// provider authority, as described in later sections on this page. 10 | /// 11 | /// ## Node 12 | /// Some packages are [`visible automatically`]. Your app can always see these packages in 13 | /// its queries for other installed apps. To view other packages, declare your app's need 14 | /// for increased package visibility using the element. 15 | /// 16 | /// Learn more about how to use the element in the guide on [`package visibility 17 | /// filtering`]. 18 | /// 19 | /// ## XML Syntax 20 | /// ```xml 21 | /// 22 | /// 23 | /// 24 | /// ... 25 | /// 26 | /// 27 | /// 28 | /// ``` 29 | /// 30 | /// ## Contained in 31 | /// * [``] 32 | /// 33 | /// ## Introduced in 34 | /// API Level 30 35 | /// 36 | /// [``]: crate::AndroidManifest 37 | /// [`package visibility filtering`]: https://developer.android.com/training/package-visibility 38 | /// [`visible automatically`]: https://developer.android.com/training/package-visibility/automatic 39 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 40 | pub struct Queries { 41 | /// Specifies a single app that your app intends to access. This other app might 42 | /// integrate with your app, or your app might use services that the other app 43 | /// provides. 44 | pub package: Option, 45 | /// Specifies an [`intent filter signature`]. Your app can discover other apps that 46 | /// have matching [``] elements. 47 | pub intent: Option, 48 | /// Specifies one or more [`content provider authorities`]. Your app can discover 49 | /// other apps whose content providers use the specified authorities. 50 | /// 51 | /// ## Note 52 | /// There are some restrictions on the options that you can include in this 53 | /// `` element, compared to a typical [``] manifest element. 54 | /// Usually, you only specify the `android:authorities` attribute. 55 | /// 56 | /// [``]: crate::Provider 57 | /// [`content provider authorities`]: https://developer.android.com/guide/topics/providers/content-provider-basics#ContentURIs 58 | #[serde(default, skip_serializing_if = "Vec::is_empty")] 59 | pub provider: Vec, 60 | } 61 | 62 | /// Specifies a single app that your app intends to access. This other app might integrate 63 | /// with your app, or your app might use services that the other app provides. 64 | #[derive(Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Clone)] 65 | pub struct Package { 66 | /// `Required`. Specifies the package name of the other app. 67 | #[yaserde(attribute = true, prefix = "android")] 68 | pub name: String, 69 | } 70 | 71 | /// Specifies an [`intent filter signature`]. Your app can discover other apps that have 72 | /// matching [``] elements. 73 | /// 74 | /// ## Node 75 | /// There are some restrictions on the options that you can include in this 76 | /// element, compared to a typical intent filter signature. Learn more about these 77 | /// restrictions in the "intent filter signature" section of the guide to [`declaring 78 | /// package visibility needs`]. 79 | /// 80 | /// [``]: crate::IntentFilter 81 | /// [`intent filter signature`]: https://developer.android.com/training/basics/intents/filters 82 | /// [`declaring package visibility needs`]: https://developer.android.com/training/package-visibility/declaring#intent-filter-signature 83 | #[derive( 84 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 85 | )] 86 | pub struct Intent { 87 | pub action: Action, 88 | #[serde(default, skip_serializing_if = "Vec::is_empty")] 89 | pub data: Vec, 90 | } 91 | 92 | /// Declares a content provider component used in [``]. 93 | /// 94 | /// A content provider is a subclass of [`ContentProvider`] that supplies structured 95 | /// access to data managed by the application. All content providers in your application 96 | /// must be defined in a `` element in the manifest file; otherwise, the system 97 | /// is unaware of them and doesn't run them. 98 | /// 99 | /// You only declare content providers that are part of your application. Content 100 | /// providers in other applications that you use in your application should not be 101 | /// declared. 102 | /// 103 | /// The Android system stores references to content providers according to an authority 104 | /// string, part of the provider's content URI. For example, suppose you want to access a 105 | /// content provider that stores information about health care professionals. 106 | /// To do this, you call the method [`ContentResolver.query()`], 107 | /// which among other arguments takes a URI that identifies the provider: 108 | /// 109 | /// ## XML Example 110 | /// ```xml 111 | /// content://com.example.project.healthcareprovider/nurses/rn 112 | /// ``` 113 | /// 114 | /// The `content:` `scheme` identifies the URI as a content URI pointing to an Android 115 | /// content provider. The authority `com.example.project.healthcareprovider` identifies 116 | /// the provider itself; the Android system looks up the authority in its list of known 117 | /// providers and their authorities. The substring `nurses/rn` is a `path`, which the 118 | /// content provider can use to identify subsets of the provider data. 119 | /// 120 | /// In cases where you need to query a content provider but don't know the specific 121 | /// package names, you can declare that provider authority in a element, 122 | /// as shown in the following snippet: 123 | /// 124 | /// ## XML Example 125 | /// ```xml 126 | /// 127 | /// 128 | /// 129 | /// 130 | /// ... 131 | /// 132 | /// ``` 133 | /// 134 | /// ## Node 135 | /// If your element includes a element, you might see an editor 136 | /// warning in Android Studio related to the element. As long as you're using 137 | /// the latest "dot" release of the Android Gradle plugin, your build is unaffected, so 138 | /// you can disregard the warning. Learn more in the blog post about [`Preparing your 139 | /// Gradle build for package visibility in Android 11`]. 140 | /// 141 | /// ## Contained in 142 | /// * [``] 143 | /// 144 | /// ## Introduced in 145 | /// API Level 30 146 | /// 147 | /// [`ContentProvider`]: https://developer.android.com/reference/android/content/ContentProvider 148 | /// [`ContentResolver.query()`]: https://developer.android.com/reference/android/content/ContentResolver#query(android.net.Uri,%20java.lang.String[],%20android.os.Bundle,%20android.os.CancellationSignal) 149 | /// [`Content Providers`]: https://developer.android.com/guide/topics/providers/content-providers 150 | /// [``]: crate::Queries 151 | /// [`Preparing your Gradle build for package visibility in Android 11`]: https://android-developers.googleblog.com/2020/07/preparing-your-build-for-package-visibility-in-android-11.html 152 | #[derive( 153 | Debug, Deserialize, Serialize, YaSerialize, YaDeserialize, PartialEq, Eq, Default, Clone, 154 | )] 155 | #[serde(rename = "provider")] 156 | pub struct QueriesProvider { 157 | /// A list of one or more URI authorities that identify data offered by the content 158 | /// provider. Multiple authorities are listed by separating their names with a 159 | /// semicolon. To avoid conflicts, authority names should use a Java-style naming 160 | /// convention (such as com.example.provider.cartoonprovider). Typically, it's the 161 | /// name of the [`ContentProvider`] subclass that implements the provider 162 | /// 163 | /// There is no default. At least one authority must be specified. 164 | /// 165 | /// [`ContentProvider`]: https://developer.android.com/reference/android/content/ContentProvider 166 | #[yaserde( 167 | attribute = true, 168 | prefix = "android", 169 | skip_serializing_if = "check_authorities" 170 | )] 171 | #[serde(skip_serializing_if = "AttributeList::is_empty")] 172 | pub authorities: AttributeList, 173 | /// The name of the class that implements the content provider, a subclass of 174 | /// [`ContentProvider`]. This should be a fully qualified class name (such 175 | /// as, `"com.example.project.TransportationProvider"`). However, as a 176 | /// shorthand, if the first character of the name is a period, it is 177 | /// appended to the package name specified in the [``] element. 178 | /// 179 | /// There is no default. The name must be specified. 180 | /// 181 | /// [`ContentProvider`]: https://developer.android.com/reference/android/content/ContentProvider 182 | /// [``]: crate::AndroidManifest 183 | #[yaserde(attribute = true, prefix = "android")] 184 | pub name: String, 185 | } 186 | 187 | impl QueriesProvider { 188 | pub fn check_authorities(&self, value: &AttributeList) -> bool { 189 | value.is_empty() 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Android ### 2 | # Built application files 3 | *.apk 4 | *.aar 5 | *.ap_ 6 | *.aab 7 | 8 | # Files for the ART/Dalvik VM 9 | *.dex 10 | 11 | # Java class files 12 | *.class 13 | 14 | # Generated files 15 | bin/ 16 | gen/ 17 | out/ 18 | # Uncomment the following line in case you need and you don't have the release build type files in your app 19 | # release/ 20 | 21 | # Gradle files 22 | .gradle/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/gradle.xml 44 | .idea/assetWizardSettings.xml 45 | .idea/dictionaries 46 | .idea/libraries 47 | # Android Studio 3 in .gitignore file. 48 | .idea/caches 49 | .idea/modules.xml 50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 51 | .idea/navEditor.xml 52 | 53 | # Keystore files 54 | # Uncomment the following lines if you do not want to check your keystore files in. 55 | #*.jks 56 | #*.keystore 57 | 58 | # External native build folder generated in Android Studio 2.2 and later 59 | .externalNativeBuild 60 | .cxx/ 61 | 62 | # Google Services (e.g. APIs or Firebase) 63 | # google-services.json 64 | 65 | # Freeline 66 | freeline.py 67 | freeline/ 68 | freeline_project_description.json 69 | 70 | # fastlane 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | fastlane/readme.md 76 | 77 | # Version control 78 | vcs.xml 79 | 80 | # lint 81 | lint/intermediates/ 82 | lint/generated/ 83 | lint/outputs/ 84 | lint/tmp/ 85 | # lint/reports/ 86 | 87 | ### Android Patch ### 88 | gen-external-apklibs 89 | output.json 90 | 91 | # Replacement of .externalNativeBuild directories introduced 92 | # with Android Studio 3.5. 93 | 94 | ### C++ ### 95 | # Prerequisites 96 | *.d 97 | 98 | # Compiled Object files 99 | *.slo 100 | *.lo 101 | *.o 102 | *.obj 103 | 104 | # Precompiled Headers 105 | *.gch 106 | *.pch 107 | 108 | # Compiled Dynamic libraries 109 | *.so 110 | *.dylib 111 | *.dll 112 | 113 | # Fortran module files 114 | *.mod 115 | *.smod 116 | 117 | # Compiled Static libraries 118 | *.lai 119 | *.la 120 | *.a 121 | *.lib 122 | 123 | # Executables 124 | *.exe 125 | *.out 126 | *.app 127 | 128 | ### Java ### 129 | # Compiled class file 130 | 131 | # Log file 132 | 133 | # BlueJ files 134 | *.ctxt 135 | 136 | # Mobile Tools for Java (J2ME) 137 | .mtj.tmp/ 138 | 139 | # Package Files # 140 | *.jar 141 | *.war 142 | *.nar 143 | *.ear 144 | *.zip 145 | *.tar.gz 146 | *.rar 147 | 148 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 149 | hs_err_pid* 150 | 151 | ### Kotlin ### 152 | # Compiled class file 153 | 154 | # Log file 155 | 156 | # BlueJ files 157 | 158 | # Mobile Tools for Java (J2ME) 159 | 160 | # Package Files # 161 | 162 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 163 | 164 | ### Linux ### 165 | *~ 166 | 167 | # temporary files which can be created if a process still has a handle open of a deleted file 168 | .fuse_hidden* 169 | 170 | # KDE directory preferences 171 | .directory 172 | 173 | # Linux trash folder which might appear on any partition or disk 174 | .Trash-* 175 | 176 | # .nfs files are created when an open file is removed but is still being accessed 177 | .nfs* 178 | 179 | ### macOS ### 180 | # General 181 | .DS_Store 182 | .AppleDouble 183 | .LSOverride 184 | 185 | # Icon must end with two \r 186 | Icon 187 | 188 | # Thumbnails 189 | ._* 190 | 191 | # Files that might appear in the root of a volume 192 | .DocumentRevisions-V100 193 | .fseventsd 194 | .Spotlight-V100 195 | .TemporaryItems 196 | .Trashes 197 | .VolumeIcon.icns 198 | .com.apple.timemachine.donotpresent 199 | 200 | # Directories potentially created on remote AFP share 201 | .AppleDB 202 | .AppleDesktop 203 | Network Trash Folder 204 | Temporary Items 205 | .apdisk 206 | 207 | ### Objective-C ### 208 | # Xcode 209 | # 210 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 211 | 212 | ## User settings 213 | xcuserdata/ 214 | 215 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 216 | *.xcscmblueprint 217 | *.xccheckout 218 | 219 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 220 | DerivedData/ 221 | *.moved-aside 222 | *.pbxuser 223 | !default.pbxuser 224 | *.mode1v3 225 | !default.mode1v3 226 | *.mode2v3 227 | !default.mode2v3 228 | *.perspectivev3 229 | !default.perspectivev3 230 | 231 | ## Obj-C/Swift specific 232 | *.hmap 233 | 234 | ## App packaging 235 | *.ipa 236 | *.dSYM.zip 237 | *.dSYM 238 | 239 | # CocoaPods 240 | # We recommend against adding the Pods directory to your .gitignore. However 241 | # you should judge for yourself, the pros and cons are mentioned at: 242 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 243 | # Pods/ 244 | # Add this line if you want to avoid checking in source code from the Xcode workspace 245 | # *.xcworkspace 246 | 247 | # Carthage 248 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 249 | # Carthage/Checkouts 250 | 251 | Carthage/Build/ 252 | 253 | # fastlane 254 | # It is recommended to not store the screenshots in the git repo. 255 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 256 | # For more information about the recommended setup visit: 257 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 258 | 259 | fastlane/screenshots/**/*.png 260 | 261 | # Code Injection 262 | # After new code Injection tools there's a generated folder /iOSInjectionProject 263 | # https://github.com/johnno1962/injectionforxcode 264 | 265 | iOSInjectionProject/ 266 | 267 | ### Objective-C Patch ### 268 | 269 | ### Rust ### 270 | # Generated by Cargo 271 | # will have compiled files and executables 272 | target/ 273 | 274 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 275 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 276 | Cargo.lock 277 | 278 | # These are backup files generated by rustfmt 279 | **/*.rs.bk 280 | 281 | ### Swift ### 282 | # Xcode 283 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 284 | 285 | 286 | 287 | 288 | 289 | 290 | ## Playgrounds 291 | timeline.xctimeline 292 | playground.xcworkspace 293 | 294 | # Swift Package Manager 295 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 296 | # Packages/ 297 | # Package.pins 298 | # Package.resolved 299 | # *.xcodeproj 300 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 301 | # hence it is not needed unless you have added a package configuration file to your project 302 | # .swiftpm 303 | 304 | .build/ 305 | 306 | # CocoaPods 307 | # We recommend against adding the Pods directory to your .gitignore. However 308 | # you should judge for yourself, the pros and cons are mentioned at: 309 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 310 | # Pods/ 311 | # Add this line if you want to avoid checking in source code from the Xcode workspace 312 | # *.xcworkspace 313 | 314 | # Carthage 315 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 316 | # Carthage/Checkouts 317 | 318 | 319 | # Accio dependency management 320 | Dependencies/ 321 | .accio/ 322 | 323 | # fastlane 324 | # It is recommended to not store the screenshots in the git repo. 325 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 326 | # For more information about the recommended setup visit: 327 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 328 | 329 | 330 | # Code Injection 331 | # After new code Injection tools there's a generated folder /iOSInjectionProject 332 | # https://github.com/johnno1962/injectionforxcode 333 | 334 | 335 | ### Windows ### 336 | # Windows thumbnail cache files 337 | Thumbs.db 338 | Thumbs.db:encryptable 339 | ehthumbs.db 340 | ehthumbs_vista.db 341 | 342 | # Dump file 343 | *.stackdump 344 | 345 | # Folder config file 346 | [Dd]esktop.ini 347 | 348 | # Recycle Bin used on file shares 349 | $RECYCLE.BIN/ 350 | 351 | # Windows Installer files 352 | *.cab 353 | *.msi 354 | *.msix 355 | *.msm 356 | *.msp 357 | 358 | # Windows shortcuts 359 | *.lnk 360 | 361 | ### Xcode ### 362 | # Xcode 363 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 364 | 365 | 366 | 367 | 368 | ## Gcc Patch 369 | /*.gcno 370 | 371 | ### Xcode Patch ### 372 | *.xcodeproj/* 373 | !*.xcodeproj/project.pbxproj 374 | !*.xcodeproj/xcshareddata/ 375 | !*.xcworkspace/contents.xcworkspacedata 376 | **/xcshareddata/WorkspaceSettings.xcsettings 377 | 378 | ### XcodeInjection ### 379 | # Code Injection 380 | # After new code Injection tools there's a generated folder /iOSInjectionProject 381 | # https://github.com/johnno1962/injectionforxcode 382 | 383 | 384 | ### AndroidStudio ### 385 | # Covers files to be ignored for android development using Android Studio. 386 | 387 | # Built application files 388 | 389 | # Files for the ART/Dalvik VM 390 | 391 | # Java class files 392 | 393 | # Generated files 394 | 395 | # Gradle files 396 | .gradle 397 | 398 | # Signing files 399 | .signing/ 400 | 401 | # Local configuration file (sdk path, etc) 402 | 403 | # Proguard folder generated by Eclipse 404 | 405 | # Log Files 406 | 407 | # Android Studio 408 | /*/build/ 409 | /*/local.properties 410 | /*/out 411 | /*/*/build 412 | /*/*/production 413 | *.ipr 414 | *.swp 415 | 416 | # Android Patch 417 | 418 | # External native build folder generated in Android Studio 2.2 and later 419 | 420 | # NDK 421 | obj/ 422 | 423 | # IntelliJ IDEA 424 | *.iws 425 | /out/ 426 | 427 | # User-specific configurations 428 | .idea/caches/ 429 | .idea/libraries/ 430 | .idea/shelf/ 431 | .idea/.name 432 | .idea/compiler.xml 433 | .idea/copyright/profiles_settings.xml 434 | .idea/encodings.xml 435 | .idea/misc.xml 436 | .idea/scopes/scope_settings.xml 437 | .idea/vcs.xml 438 | .idea/jsLibraryMappings.xml 439 | .idea/datasources.xml 440 | .idea/dataSources.ids 441 | .idea/sqlDataSources.xml 442 | .idea/dynamic.xml 443 | .idea/uiDesigner.xml 444 | 445 | # OS-specific files 446 | .DS_Store? 447 | 448 | # Legacy Eclipse project files 449 | .classpath 450 | .project 451 | .cproject 452 | .settings/ 453 | 454 | # Mobile Tools for Java (J2ME) 455 | 456 | # Package Files # 457 | 458 | # virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml) 459 | 460 | ## Plugin-specific files: 461 | 462 | # mpeltonen/sbt-idea plugin 463 | .idea_modules/ 464 | 465 | # JIRA plugin 466 | atlassian-ide-plugin.xml 467 | 468 | # Mongo Explorer plugin 469 | .idea/mongoSettings.xml 470 | 471 | # Crashlytics plugin (for Android Studio and IntelliJ) 472 | com_crashlytics_export_strings.xml 473 | crashlytics.properties 474 | crashlytics-build.properties 475 | fabric.properties 476 | 477 | ### AndroidStudio Patch ### 478 | 479 | !/gradle/wrapper/gradle-wrapper.jar 480 | 481 | ### Ignore test gen. files 482 | docs/xml_example_write.xml -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 DodoRare, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate yaserde_derive; 3 | 4 | mod action; 5 | mod activity; 6 | mod activity_alias; 7 | mod application; 8 | mod attribute_list; 9 | mod category; 10 | mod compatible_screens; 11 | mod data; 12 | pub mod error; 13 | mod grant_uri_permission; 14 | mod instrumentation; 15 | mod intent_filter; 16 | mod layout; 17 | mod manifest; 18 | mod meta_data; 19 | mod path_permission; 20 | mod permission; 21 | mod permission_group; 22 | mod permission_tree; 23 | mod profileable; 24 | mod provider; 25 | mod queries; 26 | mod receiver; 27 | mod resources; 28 | mod service; 29 | mod supports_gl_texture; 30 | mod supports_screens; 31 | mod ui_options; 32 | mod uses_configuration; 33 | mod uses_feature; 34 | mod uses_library; 35 | mod uses_native_library; 36 | mod uses_permission; 37 | mod uses_permission_sdk_23; 38 | mod uses_sdk; 39 | mod var_or_bool; 40 | 41 | pub use action::*; 42 | pub use activity::*; 43 | pub use activity_alias::*; 44 | pub use application::*; 45 | pub use attribute_list::*; 46 | pub use category::*; 47 | pub use compatible_screens::*; 48 | pub use data::*; 49 | use error::{Error, Result}; 50 | pub use grant_uri_permission::*; 51 | pub use instrumentation::*; 52 | pub use intent_filter::*; 53 | pub use layout::*; 54 | pub use manifest::*; 55 | pub use meta_data::*; 56 | pub use path_permission::*; 57 | pub use permission::*; 58 | pub use permission_group::*; 59 | pub use permission_tree::*; 60 | pub use profileable::*; 61 | pub use provider::*; 62 | pub use queries::*; 63 | pub use receiver::*; 64 | pub use resources::*; 65 | pub use service::*; 66 | pub use supports_gl_texture::*; 67 | pub use supports_screens::*; 68 | pub use ui_options::*; 69 | pub use uses_configuration::*; 70 | pub use uses_feature::*; 71 | pub use uses_library::*; 72 | pub use uses_native_library::UsesNativeLibrary; 73 | pub use uses_permission::*; 74 | pub use uses_permission_sdk_23::*; 75 | pub use uses_sdk::*; 76 | pub use var_or_bool::*; 77 | 78 | /// Deserialize an instance of type [`AndroidManifest`](crate::AndroidManifest) from a 79 | /// string of XML text. 80 | pub fn from_str(s: &str) -> Result { 81 | yaserde::de::from_str(s).map_err(Error::FailedToDeserialize) 82 | } 83 | 84 | /// Deserialize an instance of type [`AndroidManifest`](crate::AndroidManifest) from an IO 85 | /// stream of XML text. 86 | pub fn from_reader(reader: R) -> Result { 87 | yaserde::de::from_reader(reader).map_err(Error::FailedToDeserialize) 88 | } 89 | 90 | /// Serialize the given [`AndroidManifest`](crate::AndroidManifest) structure as a String 91 | /// of XML text. 92 | pub fn to_string(manifest: &AndroidManifest) -> Result { 93 | yaserde::ser::to_string(manifest).map_err(Error::FailedToSerialize) 94 | } 95 | 96 | /// Serialize the given [`AndroidManifest`](crate::AndroidManifest) structure as a 97 | /// pretty-printed String of XML text. 98 | pub fn to_string_pretty(manifest: &AndroidManifest) -> Result { 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)] 108 | mod tests { 109 | use super::*; 110 | 111 | #[test] 112 | fn test_complex_manifest_deserialize() { 113 | let given_xml = r#" 114 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 126 | 127 | 128 | 129 | 134 | 135 | 136 | 137 | 138 | 139 | 143 | 147 | 148 | 149 | 150 | 151 | 152 | 155 | 156 | 157 | 158 | 159 | 162 | 163 | 164 | 165 | 166 | 169 | 170 | 171 | "#; 172 | let expected_manifest = AndroidManifest { 173 | package: Some("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 | } 295 | --------------------------------------------------------------------------------