diff --git a/build-tools/aaptcompiler/gradle.properties b/build-tools/aaptcompiler/gradle.properties
index 68918e44d..7744fbac5 100644
--- a/build-tools/aaptcompiler/gradle.properties
+++ b/build-tools/aaptcompiler/gradle.properties
@@ -1,2 +1,3 @@
#androidx.enableJetifier=false
android.jetifier.ignorelist=common-30.2.2.jar
+kotlin.suppressWarnings=true
diff --git a/build-tools/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceUtils.kt b/build-tools/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceUtils.kt
index 626055974..3f8ed9467 100755
--- a/build-tools/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceUtils.kt
+++ b/build-tools/aaptcompiler/src/main/java/com/android/aaptcompiler/ResourceUtils.kt
@@ -22,7 +22,7 @@ import com.android.aaptcompiler.android.parseHex
import com.android.aaptcompiler.android.stringToFloat
import com.android.aaptcompiler.android.stringToInt
-fun tryParseBool(string: String) : BinaryPrimitive? {
+fun tryParseBool(string: String): BinaryPrimitive? {
val boolean = parseAsBool(string)
boolean ?: return null
@@ -30,10 +30,14 @@ fun tryParseBool(string: String) : BinaryPrimitive? {
return BinaryPrimitive(ResValue(ResValue.DataType.INT_BOOLEAN, data))
}
-fun parseAsBool(string: String) : Boolean? =
+fun parseAsBool(string: String): Boolean? =
when (string.trim()) {
- "true", "True", "TRUE" -> true
- "false", "False", "FALSE" -> false
+ "true",
+ "True",
+ "TRUE" -> true
+ "false",
+ "False",
+ "FALSE" -> false
else -> null
}
@@ -46,15 +50,15 @@ fun tryParseNullOrEmpty(value: String): Item? {
}
}
-fun makeNull() : Reference {
+fun makeNull(): Reference {
return Reference()
}
-fun makeEmpty() : BinaryPrimitive {
+fun makeEmpty(): BinaryPrimitive {
return BinaryPrimitive(ResValue(ResValue.DataType.NULL, ResValue.NullFormat.EMPTY))
}
-fun tryParseInt(value: String) : BinaryPrimitive? {
+fun tryParseInt(value: String): BinaryPrimitive? {
val trimmedValue = value.trim()
val resValue = stringToInt(trimmedValue)
return if (resValue != null) BinaryPrimitive(resValue) else null
@@ -62,15 +66,17 @@ fun tryParseInt(value: String) : BinaryPrimitive? {
fun parseResourceId(value: String): Int? {
val resValue = stringToInt(value)
- if (resValue != null &&
- resValue.dataType == ResValue.DataType.INT_HEX &&
- resValue.data.isValidDynamicId()) {
+ if (
+ resValue != null &&
+ resValue.dataType == ResValue.DataType.INT_HEX &&
+ resValue.data.isValidDynamicId()
+ ) {
return resValue.data
}
return null
}
-fun tryParseFloat(value: String) : BinaryPrimitive? {
+fun tryParseFloat(value: String): BinaryPrimitive? {
val floatResource = stringToFloat(value)
floatResource ?: return null
@@ -141,7 +147,7 @@ fun tryParseColor(value: String): BinaryPrimitive? {
data class ReferenceInfo(val reference: Reference, val createNew: Boolean = false)
-fun tryParseReference(value: String) : ReferenceInfo? {
+fun tryParseReference(value: String): ReferenceInfo? {
val parsedReference = parseReference(value)
if (parsedReference != null) {
@@ -168,7 +174,7 @@ fun tryParseReference(value: String) : ReferenceInfo? {
*
* [ReferenceInfo.createNew] will be false, as Attributes cannot be created.
*/
-fun parseAttributeReference(value: String) : ReferenceInfo? {
+fun parseAttributeReference(value: String): ReferenceInfo? {
val trimmedValue = value.trim()
if (trimmedValue.isEmpty()) {
return null
@@ -194,7 +200,10 @@ fun parseAttributeReference(value: String) : ReferenceInfo? {
val reference = Reference()
reference.name =
ResourceName(
- possibleResourceName.packageName, AaptResourceType.ATTR, possibleResourceName.entry)
+ possibleResourceName.packageName,
+ AaptResourceType.ATTR,
+ possibleResourceName.entry
+ )
reference.referenceType = Reference.Type.ATTRIBUTE
return ReferenceInfo(reference, false)
}
@@ -205,10 +214,7 @@ fun parseAttributeReference(value: String) : ReferenceInfo? {
*
*
The reference must be of one of the following forms:
*
- * + "@"
- * + "@/"
- * + "@:"
- * + "@:/"
+ * + "@" + "@/" + "@:" + "@:/"
*
* Optionally, the '@' symbol can be followed by one of '+' or '*'. '+' means that the resource
* will be created and added to the resource table. This is only usable with id resources. The '*',
@@ -219,11 +225,10 @@ fun parseAttributeReference(value: String) : ReferenceInfo? {
* @return A [ReferenceInfo] representing the reference, or {@code null} if the input was invalid.
*
* + [ReferenceInfo.createNew] will be set if and only if a '+' followed the '@' and the reference
- * had a type of id.
- * + [ReferenceInfo.reference] will be set as private if and only if a '*' followed the '@' in the
- * input.
+ * had a type of id. + [ReferenceInfo.reference] will be set as private if and only if a '*'
+ * followed the '@' in the input.
*/
-fun parseReference(value: String) : ReferenceInfo? {
+fun parseReference(value: String): ReferenceInfo? {
val trimmedValue = value.trim()
if (trimmedValue.isEmpty()) {
return null
@@ -266,19 +271,16 @@ data class ResourceNameInfo(val resourceName: ResourceName, val isPrivate: Boole
*
*
The resource name must be in one of the following forms:
*
- * + ""
- * + "/"
- * + ":"
- * + ":/"
+ * + "" + "/" + ":" + ":/"
*
* The value may optionally be preceded by a '*' to represent that the resource name is private.
*
* @param value the value to be parsed.
* @return If parsing was successful, this function returns the [ResourceNameInfo] holding both the
- * valid [ResourceName] and whether the parsed name identifies a private resource. If the value
- * failed to parsed {@code null} is returned instead.
+ * valid [ResourceName] and whether the parsed name identifies a private resource. If the value
+ * failed to parsed {@code null} is returned instead.
*/
-fun parseResourceName(value: String) : ResourceNameInfo? {
+fun parseResourceName(value: String): ResourceNameInfo? {
if (value.isEmpty()) {
return null
@@ -305,12 +307,16 @@ fun parseResourceName(value: String) : ResourceNameInfo? {
return ResourceNameInfo(
ResourceName(possibleResourceName.packageName, resourceType, possibleResourceName.entry),
- isPrivate)
+ isPrivate
+ )
}
data class PossibleResourceName(
- val packageName: String, val typeName: String, val entry: String, val success: Boolean = true)
-
+ val packageName: String,
+ val typeName: String,
+ val entry: String,
+ val success: Boolean = true
+)
fun extractResourceName(value: String): PossibleResourceName {
var packageName = ""
@@ -341,8 +347,8 @@ fun extractResourceName(value: String): PossibleResourceName {
}
val entryName = value.substring(offsetCurrent)
- val success = !(hasPackageSeparator && packageName.isEmpty()) &&
- !((hasTypeSeparator) && typeName.isEmpty())
+ val success =
+ !(hasPackageSeparator && packageName.isEmpty()) && !((hasTypeSeparator) && typeName.isEmpty())
return PossibleResourceName(packageName, typeName, entryName, success)
}
@@ -350,7 +356,8 @@ fun extractResourceName(value: String): PossibleResourceName {
fun tryParseItemForAttribute(
value: String,
resourceTypeMask: Int,
- onCreateReference: ((name: ResourceName) -> Boolean)? = null): Item? {
+ onCreateReference: ((name: ResourceName) -> Boolean)? = null
+): Item? {
val nullOrEmpty = tryParseNullOrEmpty(value)
if (nullOrEmpty != null) {
@@ -362,8 +369,8 @@ fun tryParseItemForAttribute(
reference.reference.typeFlags = resourceTypeMask
if (reference.createNew) {
val result = onCreateReference?.invoke(reference.reference.name)
- if (result != null && !result) {
- return null
+ if (result != null && !result) {
+ return null
}
}
return reference.reference
@@ -390,13 +397,16 @@ fun tryParseItemForAttribute(
}
}
- val floatMask = Resources.Attribute.FormatFlags.FLOAT_VALUE or
- Resources.Attribute.FormatFlags.DIMENSION_VALUE or
- Resources.Attribute.FormatFlags.FRACTION_VALUE
+ val floatMask =
+ Resources.Attribute.FormatFlags.FLOAT_VALUE or
+ Resources.Attribute.FormatFlags.DIMENSION_VALUE or
+ Resources.Attribute.FormatFlags.FRACTION_VALUE
if ((resourceTypeMask and floatMask) != 0) {
val floatingPoint = tryParseFloat(value)
- if (floatingPoint != null &&
- (androidTypeToAttributeTypeMask(floatingPoint.resValue.dataType) and resourceTypeMask) != 0) {
+ if (
+ floatingPoint != null &&
+ (androidTypeToAttributeTypeMask(floatingPoint.resValue.dataType) and resourceTypeMask) != 0
+ ) {
return floatingPoint
}
}
@@ -568,11 +578,16 @@ fun parseStyleParentReference(str: String): ParsedParentInfo {
val resourceName =
ResourceName(
- possibleResourceName.packageName, AaptResourceType.STYLE, possibleResourceName.entry)
+ possibleResourceName.packageName,
+ AaptResourceType.STYLE,
+ possibleResourceName.entry
+ )
- if (!hasLeadingIdentifiers &&
- resourceName.pck!!.isEmpty() &&
- possibleResourceName.typeName.isNotEmpty()) {
+ if (
+ !hasLeadingIdentifiers &&
+ resourceName.pck!!.isEmpty() &&
+ possibleResourceName.typeName.isNotEmpty()
+ ) {
val errorString = "Invalid parent reference '$str'"
return ParsedParentInfo(null, errorString)
}
@@ -581,11 +596,9 @@ fun parseStyleParentReference(str: String): ParsedParentInfo {
result.name = resourceName
result.isPrivate = privateRef
-
return ParsedParentInfo(result, "")
}
-
fun parseXmlAttributeName(str: String): Reference {
val name = str.trim()
@@ -602,7 +615,7 @@ fun parseXmlAttributeName(str: String): Reference {
for (i in startOffset..(name.length - 1)) {
if (name.codePointAt(i) == ':'.toInt()) {
packageName = name.substring(startOffset, i)
- entryName = name.substring(i+1)
+ entryName = name.substring(i + 1)
}
}
@@ -629,7 +642,7 @@ fun tryParseFlagSymbol(attribute: AttributeResource, value: String): BinaryPrimi
// so we need to match against the 'entry' part of the identifier
val flagResourceName = symbol.symbol.name
if (trimmedPart == flagResourceName.entry) {
- flagsData = flagsData or symbol.value
+ flagsData = flagsData or symbol.value
flagSet = true
break
}
diff --git a/build-tools/classfile/src/test/java/com/itsaky/androidide/classfile/ClassFileReaderTest.kt b/build-tools/classfile/src/test/java/com/itsaky/androidide/classfile/ClassFileReaderTest.kt
index 8cb53880f..1586f6a4a 100644
--- a/build-tools/classfile/src/test/java/com/itsaky/androidide/classfile/ClassFileReaderTest.kt
+++ b/build-tools/classfile/src/test/java/com/itsaky/androidide/classfile/ClassFileReaderTest.kt
@@ -62,7 +62,9 @@ class ClassFileReaderTest {
private fun checkFIelds(file: IClassFile) {
file.fields
- .firstOrNull { (file.constantPool[it.nameIndex] as Utf8Constant).content() == "mTextActionWindow" }
+ .firstOrNull {
+ (file.constantPool[it.nameIndex] as Utf8Constant).content() == "mTextActionWindow"
+ }
.apply {
assertThat(this).isNotNull()
@@ -70,8 +72,9 @@ class ClassFileReaderTest {
assertThat(name).isEqualTo("mTextActionWindow")
val descriptor = (file.constantPool[this.descriptorIndex] as Utf8Constant).content()
- assertThat(descriptor).isEqualTo("Lio/github/rosemoe/sora/widget/component/EditorTextActionWindow;")
-
+ assertThat(descriptor)
+ .isEqualTo("Lio/github/rosemoe/sora/widget/component/EditorTextActionWindow;")
+
assertThat(this.accessFlags and ClassFileConstants.ACC_PROTECTED).isNotEqualTo(0)
assertThat(this.accessFlags and ClassFileConstants.ACC_PRIVATE).isEqualTo(0)
assertThat(this.accessFlags and ClassFileConstants.ACC_PUBLIC).isEqualTo(0)
diff --git a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt
index 207b7d77f..7eafe74f3 100644
--- a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt
+++ b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/AndroidModule.kt
@@ -118,7 +118,7 @@ open class AndroidModule( // Class must be open because BaseXMLTest mocks this..
private val log = ILogger.newInstance(javaClass.simpleName)
override var moduleData: SimpleModuleData? = null
-
+
init {
type = Android
}
diff --git a/build-tools/xml-utils/src/main/java/com/itsaky/androidide/xml/permissions/ManifestPermissionConstants.java b/build-tools/xml-utils/src/main/java/com/itsaky/androidide/xml/permissions/ManifestPermissionConstants.java
new file mode 100644
index 000000000..32531405a
--- /dev/null
+++ b/build-tools/xml-utils/src/main/java/com/itsaky/androidide/xml/permissions/ManifestPermissionConstants.java
@@ -0,0 +1,318 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.xml.permissions;
+
+/**
+ * Manifest permissions extracted from `android/Manifest$permission.class` android
+ * `android/Manifest$permission_group.class` entries in the `android.jar` of API 33.
+ *
+ * Auto-generated using ClassFileReader
+ *
+ *
TODO Check if we could eliminate this and extract these at runtime when the project is
+ * initialized.
+ *
+ * @author Akash Yadav
+ */
+public class ManifestPermissionConstants {
+ public static final String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
+ public static final String ACCESS_BACKGROUND_LOCATION =
+ "android.permission.ACCESS_BACKGROUND_LOCATION";
+ public static final String ACCESS_BLOBS_ACROSS_USERS =
+ "android.permission.ACCESS_BLOBS_ACROSS_USERS";
+ public static final String ACCESS_CHECKIN_PROPERTIES =
+ "android.permission.ACCESS_CHECKIN_PROPERTIES";
+ public static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
+ public static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
+ public static final String ACCESS_LOCATION_EXTRA_COMMANDS =
+ "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS";
+ public static final String ACCESS_MEDIA_LOCATION = "android.permission.ACCESS_MEDIA_LOCATION";
+ public static final String ACCESS_NETWORK_STATE = "android.permission.ACCESS_NETWORK_STATE";
+ public static final String ACCESS_NOTIFICATION_POLICY =
+ "android.permission.ACCESS_NOTIFICATION_POLICY";
+ public static final String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
+ public static final String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
+ public static final String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION";
+ public static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
+ public static final String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
+ public static final String BATTERY_STATS = "android.permission.BATTERY_STATS";
+ public static final String BIND_ACCESSIBILITY_SERVICE =
+ "android.permission.BIND_ACCESSIBILITY_SERVICE";
+ public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+ public static final String BIND_AUTOFILL_SERVICE = "android.permission.BIND_AUTOFILL_SERVICE";
+ public static final String BIND_CALL_REDIRECTION_SERVICE =
+ "android.permission.BIND_CALL_REDIRECTION_SERVICE";
+ public static final String BIND_CARRIER_MESSAGING_CLIENT_SERVICE =
+ "android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE";
+ public static final String BIND_CARRIER_MESSAGING_SERVICE =
+ "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
+ public static final String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
+ public static final String BIND_CHOOSER_TARGET_SERVICE =
+ "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+ public static final String BIND_COMPANION_DEVICE_SERVICE =
+ "android.permission.BIND_COMPANION_DEVICE_SERVICE";
+ public static final String BIND_CONDITION_PROVIDER_SERVICE =
+ "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
+ public static final String BIND_CONTROLS = "android.permission.BIND_CONTROLS";
+ public static final String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
+ public static final String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
+ public static final String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
+ public static final String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
+ public static final String BIND_MIDI_DEVICE_SERVICE =
+ "android.permission.BIND_MIDI_DEVICE_SERVICE";
+ public static final String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
+ public static final String BIND_NOTIFICATION_LISTENER_SERVICE =
+ "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
+ public static final String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
+ public static final String BIND_QUICK_ACCESS_WALLET_SERVICE =
+ "android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE";
+ public static final String BIND_QUICK_SETTINGS_TILE =
+ "android.permission.BIND_QUICK_SETTINGS_TILE";
+ public static final String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
+ public static final String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
+ public static final String BIND_TELECOM_CONNECTION_SERVICE =
+ "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
+ public static final String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
+ public static final String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
+ public static final String BIND_TV_INTERACTIVE_APP = "android.permission.BIND_TV_INTERACTIVE_APP";
+ public static final String BIND_VISUAL_VOICEMAIL_SERVICE =
+ "android.permission.BIND_VISUAL_VOICEMAIL_SERVICE";
+ public static final String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
+ public static final String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
+ public static final String BIND_VR_LISTENER_SERVICE =
+ "android.permission.BIND_VR_LISTENER_SERVICE";
+ public static final String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
+ public static final String BLUETOOTH = "android.permission.BLUETOOTH";
+ public static final String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
+ public static final String BLUETOOTH_ADVERTISE = "android.permission.BLUETOOTH_ADVERTISE";
+ public static final String BLUETOOTH_CONNECT = "android.permission.BLUETOOTH_CONNECT";
+ public static final String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
+ public static final String BLUETOOTH_SCAN = "android.permission.BLUETOOTH_SCAN";
+ public static final String BODY_SENSORS = "android.permission.BODY_SENSORS";
+ public static final String BODY_SENSORS_BACKGROUND = "android.permission.BODY_SENSORS_BACKGROUND";
+ public static final String BROADCAST_PACKAGE_REMOVED =
+ "android.permission.BROADCAST_PACKAGE_REMOVED";
+ public static final String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
+ public static final String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY";
+ public static final String BROADCAST_WAP_PUSH = "android.permission.BROADCAST_WAP_PUSH";
+ public static final String CALL_COMPANION_APP = "android.permission.CALL_COMPANION_APP";
+ public static final String CALL_PHONE = "android.permission.CALL_PHONE";
+ public static final String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
+ public static final String CAMERA = "android.permission.CAMERA";
+ public static final String CAPTURE_AUDIO_OUTPUT = "android.permission.CAPTURE_AUDIO_OUTPUT";
+ public static final String CHANGE_COMPONENT_ENABLED_STATE =
+ "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
+ public static final String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
+ public static final String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
+ public static final String CHANGE_WIFI_MULTICAST_STATE =
+ "android.permission.CHANGE_WIFI_MULTICAST_STATE";
+ public static final String CHANGE_WIFI_STATE = "android.permission.CHANGE_WIFI_STATE";
+ public static final String CLEAR_APP_CACHE = "android.permission.CLEAR_APP_CACHE";
+ public static final String CONTROL_LOCATION_UPDATES =
+ "android.permission.CONTROL_LOCATION_UPDATES";
+ public static final String DELETE_CACHE_FILES = "android.permission.DELETE_CACHE_FILES";
+ public static final String DELETE_PACKAGES = "android.permission.DELETE_PACKAGES";
+ public static final String DELIVER_COMPANION_MESSAGES =
+ "android.permission.DELIVER_COMPANION_MESSAGES";
+ public static final String DIAGNOSTIC = "android.permission.DIAGNOSTIC";
+ public static final String DISABLE_KEYGUARD = "android.permission.DISABLE_KEYGUARD";
+ public static final String DUMP = "android.permission.DUMP";
+ public static final String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
+ public static final String FACTORY_TEST = "android.permission.FACTORY_TEST";
+ public static final String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE";
+ public static final String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+ public static final String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
+ public static final String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
+ public static final String GET_TASKS = "android.permission.GET_TASKS";
+ public static final String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
+ public static final String HIDE_OVERLAY_WINDOWS = "android.permission.HIDE_OVERLAY_WINDOWS";
+ public static final String HIGH_SAMPLING_RATE_SENSORS =
+ "android.permission.HIGH_SAMPLING_RATE_SENSORS";
+ public static final String INSTALL_LOCATION_PROVIDER =
+ "android.permission.INSTALL_LOCATION_PROVIDER";
+ public static final String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
+ public static final String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
+ public static final String INSTANT_APP_FOREGROUND_SERVICE =
+ "android.permission.INSTANT_APP_FOREGROUND_SERVICE";
+ public static final String INTERACT_ACROSS_PROFILES =
+ "android.permission.INTERACT_ACROSS_PROFILES";
+ public static final String INTERNET = "android.permission.INTERNET";
+ public static final String KILL_BACKGROUND_PROCESSES =
+ "android.permission.KILL_BACKGROUND_PROCESSES";
+ public static final String LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK =
+ "android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK";
+ public static final String LOADER_USAGE_STATS = "android.permission.LOADER_USAGE_STATS";
+ public static final String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
+ public static final String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
+ public static final String MANAGE_EXTERNAL_STORAGE = "android.permission.MANAGE_EXTERNAL_STORAGE";
+ public static final String MANAGE_MEDIA = "android.permission.MANAGE_MEDIA";
+ public static final String MANAGE_ONGOING_CALLS = "android.permission.MANAGE_ONGOING_CALLS";
+ public static final String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
+ public static final String MANAGE_WIFI_INTERFACES = "android.permission.MANAGE_WIFI_INTERFACES";
+ public static final String MANAGE_WIFI_NETWORK_SELECTION =
+ "android.permission.MANAGE_WIFI_NETWORK_SELECTION";
+ public static final String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
+ public static final String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
+ public static final String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
+ public static final String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE";
+ public static final String MOUNT_FORMAT_FILESYSTEMS =
+ "android.permission.MOUNT_FORMAT_FILESYSTEMS";
+ public static final String MOUNT_UNMOUNT_FILESYSTEMS =
+ "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
+ public static final String NEARBY_WIFI_DEVICES = "android.permission.NEARBY_WIFI_DEVICES";
+ public static final String NFC = "android.permission.NFC";
+ public static final String NFC_PREFERRED_PAYMENT_INFO =
+ "android.permission.NFC_PREFERRED_PAYMENT_INFO";
+ public static final String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT";
+ public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
+ public static final String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
+ public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
+ public static final String POST_NOTIFICATIONS = "android.permission.POST_NOTIFICATIONS";
+ public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
+ public static final String QUERY_ALL_PACKAGES = "android.permission.QUERY_ALL_PACKAGES";
+ public static final String READ_ASSISTANT_APP_SEARCH_DATA =
+ "android.permission.READ_ASSISTANT_APP_SEARCH_DATA";
+ public static final String READ_BASIC_PHONE_STATE = "android.permission.READ_BASIC_PHONE_STATE";
+ public static final String READ_CALENDAR = "android.permission.READ_CALENDAR";
+ public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
+ public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
+ public static final String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
+ public static final String READ_HOME_APP_SEARCH_DATA =
+ "android.permission.READ_HOME_APP_SEARCH_DATA";
+ public static final String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
+ public static final String READ_LOGS = "android.permission.READ_LOGS";
+ public static final String READ_MEDIA_AUDIO = "android.permission.READ_MEDIA_AUDIO";
+ public static final String READ_MEDIA_IMAGES = "android.permission.READ_MEDIA_IMAGES";
+ public static final String READ_MEDIA_VIDEO = "android.permission.READ_MEDIA_VIDEO";
+ public static final String READ_NEARBY_STREAMING_POLICY =
+ "android.permission.READ_NEARBY_STREAMING_POLICY";
+ public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS";
+ public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
+ public static final String READ_PRECISE_PHONE_STATE =
+ "android.permission.READ_PRECISE_PHONE_STATE";
+ public static final String READ_SMS = "android.permission.READ_SMS";
+ public static final String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
+ public static final String READ_SYNC_STATS = "android.permission.READ_SYNC_STATS";
+ public static final String READ_VOICEMAIL = "com.android.voicemail.permission.READ_VOICEMAIL";
+ public static final String REBOOT = "android.permission.REBOOT";
+ public static final String RECEIVE_BOOT_COMPLETED = "android.permission.RECEIVE_BOOT_COMPLETED";
+ public static final String RECEIVE_MMS = "android.permission.RECEIVE_MMS";
+ public static final String RECEIVE_SMS = "android.permission.RECEIVE_SMS";
+ public static final String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
+ public static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
+ public static final String REORDER_TASKS = "android.permission.REORDER_TASKS";
+ public static final String REQUEST_COMPANION_PROFILE_APP_STREAMING =
+ "android.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING";
+ public static final String REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION =
+ "android.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION";
+ public static final String REQUEST_COMPANION_PROFILE_COMPUTER =
+ "android.permission.REQUEST_COMPANION_PROFILE_COMPUTER";
+ public static final String REQUEST_COMPANION_PROFILE_WATCH =
+ "android.permission.REQUEST_COMPANION_PROFILE_WATCH";
+ public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND =
+ "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
+ public static final String REQUEST_COMPANION_SELF_MANAGED =
+ "android.permission.REQUEST_COMPANION_SELF_MANAGED";
+ public static final String REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND =
+ "android.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND";
+ public static final String REQUEST_COMPANION_USE_DATA_IN_BACKGROUND =
+ "android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND";
+ public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
+ public static final String REQUEST_IGNORE_BATTERY_OPTIMIZATIONS =
+ "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+ public static final String REQUEST_INSTALL_PACKAGES =
+ "android.permission.REQUEST_INSTALL_PACKAGES";
+ public static final String REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE =
+ "android.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE";
+ public static final String REQUEST_PASSWORD_COMPLEXITY =
+ "android.permission.REQUEST_PASSWORD_COMPLEXITY";
+ public static final String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
+ public static final String SCHEDULE_EXACT_ALARM = "android.permission.SCHEDULE_EXACT_ALARM";
+ public static final String SEND_RESPOND_VIA_MESSAGE =
+ "android.permission.SEND_RESPOND_VIA_MESSAGE";
+ public static final String SEND_SMS = "android.permission.SEND_SMS";
+ public static final String SET_ALARM = "com.android.alarm.permission.SET_ALARM";
+ public static final String SET_ALWAYS_FINISH = "android.permission.SET_ALWAYS_FINISH";
+ public static final String SET_ANIMATION_SCALE = "android.permission.SET_ANIMATION_SCALE";
+ public static final String SET_DEBUG_APP = "android.permission.SET_DEBUG_APP";
+ public static final String SET_PREFERRED_APPLICATIONS =
+ "android.permission.SET_PREFERRED_APPLICATIONS";
+ public static final String SET_PROCESS_LIMIT = "android.permission.SET_PROCESS_LIMIT";
+ public static final String SET_TIME = "android.permission.SET_TIME";
+ public static final String SET_TIME_ZONE = "android.permission.SET_TIME_ZONE";
+ public static final String SET_WALLPAPER = "android.permission.SET_WALLPAPER";
+ public static final String SET_WALLPAPER_HINTS = "android.permission.SET_WALLPAPER_HINTS";
+ public static final String SIGNAL_PERSISTENT_PROCESSES =
+ "android.permission.SIGNAL_PERSISTENT_PROCESSES";
+ public static final String SMS_FINANCIAL_TRANSACTIONS =
+ "android.permission.SMS_FINANCIAL_TRANSACTIONS";
+ public static final String START_FOREGROUND_SERVICES_FROM_BACKGROUND =
+ "android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND";
+ public static final String START_VIEW_APP_FEATURES = "android.permission.START_VIEW_APP_FEATURES";
+ public static final String START_VIEW_PERMISSION_USAGE =
+ "android.permission.START_VIEW_PERMISSION_USAGE";
+ public static final String STATUS_BAR = "android.permission.STATUS_BAR";
+ public static final String SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE =
+ "android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE";
+ public static final String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
+ public static final String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
+ public static final String UNINSTALL_SHORTCUT =
+ "com.android.launcher.permission.UNINSTALL_SHORTCUT";
+ public static final String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
+ public static final String UPDATE_PACKAGES_WITHOUT_USER_ACTION =
+ "android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION";
+ public static final String USE_BIOMETRIC = "android.permission.USE_BIOMETRIC";
+ public static final String USE_EXACT_ALARM = "android.permission.USE_EXACT_ALARM";
+ public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
+ public static final String USE_FULL_SCREEN_INTENT = "android.permission.USE_FULL_SCREEN_INTENT";
+ public static final String USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER =
+ "android.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER";
+ public static final String USE_SIP = "android.permission.USE_SIP";
+ public static final String UWB_RANGING = "android.permission.UWB_RANGING";
+ public static final String VIBRATE = "android.permission.VIBRATE";
+ public static final String WAKE_LOCK = "android.permission.WAKE_LOCK";
+ public static final String WRITE_APN_SETTINGS = "android.permission.WRITE_APN_SETTINGS";
+ public static final String WRITE_CALENDAR = "android.permission.WRITE_CALENDAR";
+ public static final String WRITE_CALL_LOG = "android.permission.WRITE_CALL_LOG";
+ public static final String WRITE_CONTACTS = "android.permission.WRITE_CONTACTS";
+ public static final String WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";
+ public static final String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES";
+ public static final String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS";
+ public static final String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS";
+ public static final String WRITE_SYNC_SETTINGS = "android.permission.WRITE_SYNC_SETTINGS";
+ public static final String WRITE_VOICEMAIL = "com.android.voicemail.permission.WRITE_VOICEMAIL";
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public static final String GROUP_ACTIVITY_RECOGNITION =
+ "android.permission-group.ACTIVITY_RECOGNITION";
+ public static final String GROUP_CALENDAR = "android.permission-group.CALENDAR";
+ public static final String GROUP_CALL_LOG = "android.permission-group.CALL_LOG";
+ public static final String GROUP_CAMERA = "android.permission-group.CAMERA";
+ public static final String GROUP_CONTACTS = "android.permission-group.CONTACTS";
+ public static final String GROUP_LOCATION = "android.permission-group.LOCATION";
+ public static final String GROUP_MICROPHONE = "android.permission-group.MICROPHONE";
+ public static final String GROUP_NEARBY_DEVICES = "android.permission-group.NEARBY_DEVICES";
+ public static final String GROUP_NOTIFICATIONS = "android.permission-group.NOTIFICATIONS";
+ public static final String GROUP_PHONE = "android.permission-group.PHONE";
+ public static final String GROUP_READ_MEDIA_AURAL = "android.permission-group.READ_MEDIA_AURAL";
+ public static final String GROUP_READ_MEDIA_VISUAL = "android.permission-group.READ_MEDIA_VISUAL";
+ public static final String GROUP_SENSORS = "android.permission-group.SENSORS";
+ public static final String GROUP_SMS = "android.permission-group.SMS";
+ public static final String GROUP_STORAGE = "android.permission-group.STORAGE";
+}
diff --git a/build-tools/xml-utils/src/main/java/com/itsaky/androidide/xml/permissions/Permission.kt b/build-tools/xml-utils/src/main/java/com/itsaky/androidide/xml/permissions/Permission.kt
new file mode 100644
index 000000000..2074df2c1
--- /dev/null
+++ b/build-tools/xml-utils/src/main/java/com/itsaky/androidide/xml/permissions/Permission.kt
@@ -0,0 +1,234 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.xml.permissions
+
+/**
+ * Model for a permission entry.
+ *
+ * @property name The name of the permission as defined in the `android.Manifest.permission` class.
+ * @property constant The constant value of the permission.
+ * @author Akash Yadav
+ */
+enum class Permission constructor(val constant: String) {
+ ACCEPT_HANDOVER(ManifestPermissionConstants.ACCEPT_HANDOVER),
+ ACCESS_BACKGROUND_LOCATION(ManifestPermissionConstants.ACCESS_BACKGROUND_LOCATION),
+ ACCESS_BLOBS_ACROSS_USERS(ManifestPermissionConstants.ACCESS_BLOBS_ACROSS_USERS),
+ ACCESS_CHECKIN_PROPERTIES(ManifestPermissionConstants.ACCESS_CHECKIN_PROPERTIES),
+ ACCESS_COARSE_LOCATION(ManifestPermissionConstants.ACCESS_COARSE_LOCATION),
+ ACCESS_FINE_LOCATION(ManifestPermissionConstants.ACCESS_FINE_LOCATION),
+ ACCESS_LOCATION_EXTRA_COMMANDS(ManifestPermissionConstants.ACCESS_LOCATION_EXTRA_COMMANDS),
+ ACCESS_MEDIA_LOCATION(ManifestPermissionConstants.ACCESS_MEDIA_LOCATION),
+ ACCESS_NETWORK_STATE(ManifestPermissionConstants.ACCESS_NETWORK_STATE),
+ ACCESS_NOTIFICATION_POLICY(ManifestPermissionConstants.ACCESS_NOTIFICATION_POLICY),
+ ACCESS_WIFI_STATE(ManifestPermissionConstants.ACCESS_WIFI_STATE),
+ ACCOUNT_MANAGER(ManifestPermissionConstants.ACCOUNT_MANAGER),
+ ACTIVITY_RECOGNITION(ManifestPermissionConstants.ACTIVITY_RECOGNITION),
+ ADD_VOICEMAIL(ManifestPermissionConstants.ADD_VOICEMAIL),
+ ANSWER_PHONE_CALLS(ManifestPermissionConstants.ANSWER_PHONE_CALLS),
+ BATTERY_STATS(ManifestPermissionConstants.BATTERY_STATS),
+ BIND_ACCESSIBILITY_SERVICE(ManifestPermissionConstants.BIND_ACCESSIBILITY_SERVICE),
+ BIND_APPWIDGET(ManifestPermissionConstants.BIND_APPWIDGET),
+ BIND_AUTOFILL_SERVICE(ManifestPermissionConstants.BIND_AUTOFILL_SERVICE),
+ BIND_CALL_REDIRECTION_SERVICE(ManifestPermissionConstants.BIND_CALL_REDIRECTION_SERVICE),
+ BIND_CARRIER_MESSAGING_CLIENT_SERVICE(ManifestPermissionConstants.BIND_CARRIER_MESSAGING_CLIENT_SERVICE),
+ BIND_CARRIER_MESSAGING_SERVICE(ManifestPermissionConstants.BIND_CARRIER_MESSAGING_SERVICE),
+ BIND_CARRIER_SERVICES(ManifestPermissionConstants.BIND_CARRIER_SERVICES),
+ BIND_CHOOSER_TARGET_SERVICE(ManifestPermissionConstants.BIND_CHOOSER_TARGET_SERVICE),
+ BIND_COMPANION_DEVICE_SERVICE(ManifestPermissionConstants.BIND_COMPANION_DEVICE_SERVICE),
+ BIND_CONDITION_PROVIDER_SERVICE(ManifestPermissionConstants.BIND_CONDITION_PROVIDER_SERVICE),
+ BIND_CONTROLS(ManifestPermissionConstants.BIND_CONTROLS),
+ BIND_DEVICE_ADMIN(ManifestPermissionConstants.BIND_DEVICE_ADMIN),
+ BIND_DREAM_SERVICE(ManifestPermissionConstants.BIND_DREAM_SERVICE),
+ BIND_INCALL_SERVICE(ManifestPermissionConstants.BIND_INCALL_SERVICE),
+ BIND_INPUT_METHOD(ManifestPermissionConstants.BIND_INPUT_METHOD),
+ BIND_MIDI_DEVICE_SERVICE(ManifestPermissionConstants.BIND_MIDI_DEVICE_SERVICE),
+ BIND_NFC_SERVICE(ManifestPermissionConstants.BIND_NFC_SERVICE),
+ BIND_NOTIFICATION_LISTENER_SERVICE(ManifestPermissionConstants.BIND_NOTIFICATION_LISTENER_SERVICE),
+ BIND_PRINT_SERVICE(ManifestPermissionConstants.BIND_PRINT_SERVICE),
+ BIND_QUICK_ACCESS_WALLET_SERVICE(ManifestPermissionConstants.BIND_QUICK_ACCESS_WALLET_SERVICE),
+ BIND_QUICK_SETTINGS_TILE(ManifestPermissionConstants.BIND_QUICK_SETTINGS_TILE),
+ BIND_REMOTEVIEWS(ManifestPermissionConstants.BIND_REMOTEVIEWS),
+ BIND_SCREENING_SERVICE(ManifestPermissionConstants.BIND_SCREENING_SERVICE),
+ BIND_TELECOM_CONNECTION_SERVICE(ManifestPermissionConstants.BIND_TELECOM_CONNECTION_SERVICE),
+ BIND_TEXT_SERVICE(ManifestPermissionConstants.BIND_TEXT_SERVICE),
+ BIND_TV_INPUT(ManifestPermissionConstants.BIND_TV_INPUT),
+ BIND_TV_INTERACTIVE_APP(ManifestPermissionConstants.BIND_TV_INTERACTIVE_APP),
+ BIND_VISUAL_VOICEMAIL_SERVICE(ManifestPermissionConstants.BIND_VISUAL_VOICEMAIL_SERVICE),
+ BIND_VOICE_INTERACTION(ManifestPermissionConstants.BIND_VOICE_INTERACTION),
+ BIND_VPN_SERVICE(ManifestPermissionConstants.BIND_VPN_SERVICE),
+ BIND_VR_LISTENER_SERVICE(ManifestPermissionConstants.BIND_VR_LISTENER_SERVICE),
+ BIND_WALLPAPER(ManifestPermissionConstants.BIND_WALLPAPER),
+ BLUETOOTH(ManifestPermissionConstants.BLUETOOTH),
+ BLUETOOTH_ADMIN(ManifestPermissionConstants.BLUETOOTH_ADMIN),
+ BLUETOOTH_ADVERTISE(ManifestPermissionConstants.BLUETOOTH_ADVERTISE),
+ BLUETOOTH_CONNECT(ManifestPermissionConstants.BLUETOOTH_CONNECT),
+ BLUETOOTH_PRIVILEGED(ManifestPermissionConstants.BLUETOOTH_PRIVILEGED),
+ BLUETOOTH_SCAN(ManifestPermissionConstants.BLUETOOTH_SCAN),
+ BODY_SENSORS(ManifestPermissionConstants.BODY_SENSORS),
+ BODY_SENSORS_BACKGROUND(ManifestPermissionConstants.BODY_SENSORS_BACKGROUND),
+ BROADCAST_PACKAGE_REMOVED(ManifestPermissionConstants.BROADCAST_PACKAGE_REMOVED),
+ BROADCAST_SMS(ManifestPermissionConstants.BROADCAST_SMS),
+ BROADCAST_STICKY(ManifestPermissionConstants.BROADCAST_STICKY),
+ BROADCAST_WAP_PUSH(ManifestPermissionConstants.BROADCAST_WAP_PUSH),
+ CALL_COMPANION_APP(ManifestPermissionConstants.CALL_COMPANION_APP),
+ CALL_PHONE(ManifestPermissionConstants.CALL_PHONE),
+ CALL_PRIVILEGED(ManifestPermissionConstants.CALL_PRIVILEGED),
+ CAMERA(ManifestPermissionConstants.CAMERA),
+ CAPTURE_AUDIO_OUTPUT(ManifestPermissionConstants.CAPTURE_AUDIO_OUTPUT),
+ CHANGE_COMPONENT_ENABLED_STATE(ManifestPermissionConstants.CHANGE_COMPONENT_ENABLED_STATE),
+ CHANGE_CONFIGURATION(ManifestPermissionConstants.CHANGE_CONFIGURATION),
+ CHANGE_NETWORK_STATE(ManifestPermissionConstants.CHANGE_NETWORK_STATE),
+ CHANGE_WIFI_MULTICAST_STATE(ManifestPermissionConstants.CHANGE_WIFI_MULTICAST_STATE),
+ CHANGE_WIFI_STATE(ManifestPermissionConstants.CHANGE_WIFI_STATE),
+ CLEAR_APP_CACHE(ManifestPermissionConstants.CLEAR_APP_CACHE),
+ CONTROL_LOCATION_UPDATES(ManifestPermissionConstants.CONTROL_LOCATION_UPDATES),
+ DELETE_CACHE_FILES(ManifestPermissionConstants.DELETE_CACHE_FILES),
+ DELETE_PACKAGES(ManifestPermissionConstants.DELETE_PACKAGES),
+ DELIVER_COMPANION_MESSAGES(ManifestPermissionConstants.DELIVER_COMPANION_MESSAGES),
+ DIAGNOSTIC(ManifestPermissionConstants.DIAGNOSTIC),
+ DISABLE_KEYGUARD(ManifestPermissionConstants.DISABLE_KEYGUARD),
+ DUMP(ManifestPermissionConstants.DUMP),
+ EXPAND_STATUS_BAR(ManifestPermissionConstants.EXPAND_STATUS_BAR),
+ FACTORY_TEST(ManifestPermissionConstants.FACTORY_TEST),
+ FOREGROUND_SERVICE(ManifestPermissionConstants.FOREGROUND_SERVICE),
+ GET_ACCOUNTS(ManifestPermissionConstants.GET_ACCOUNTS),
+ GET_ACCOUNTS_PRIVILEGED(ManifestPermissionConstants.GET_ACCOUNTS_PRIVILEGED),
+ GET_PACKAGE_SIZE(ManifestPermissionConstants.GET_PACKAGE_SIZE),
+ GET_TASKS(ManifestPermissionConstants.GET_TASKS),
+ GLOBAL_SEARCH(ManifestPermissionConstants.GLOBAL_SEARCH),
+ HIDE_OVERLAY_WINDOWS(ManifestPermissionConstants.HIDE_OVERLAY_WINDOWS),
+ HIGH_SAMPLING_RATE_SENSORS(ManifestPermissionConstants.HIGH_SAMPLING_RATE_SENSORS),
+ INSTALL_LOCATION_PROVIDER(ManifestPermissionConstants.INSTALL_LOCATION_PROVIDER),
+ INSTALL_PACKAGES(ManifestPermissionConstants.INSTALL_PACKAGES),
+ INSTALL_SHORTCUT(ManifestPermissionConstants.INSTALL_SHORTCUT),
+ INSTANT_APP_FOREGROUND_SERVICE(ManifestPermissionConstants.INSTANT_APP_FOREGROUND_SERVICE),
+ INTERACT_ACROSS_PROFILES(ManifestPermissionConstants.INTERACT_ACROSS_PROFILES),
+ INTERNET(ManifestPermissionConstants.INTERNET),
+ KILL_BACKGROUND_PROCESSES(ManifestPermissionConstants.KILL_BACKGROUND_PROCESSES),
+ LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK(ManifestPermissionConstants.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK),
+ LOADER_USAGE_STATS(ManifestPermissionConstants.LOADER_USAGE_STATS),
+ LOCATION_HARDWARE(ManifestPermissionConstants.LOCATION_HARDWARE),
+ MANAGE_DOCUMENTS(ManifestPermissionConstants.MANAGE_DOCUMENTS),
+ MANAGE_EXTERNAL_STORAGE(ManifestPermissionConstants.MANAGE_EXTERNAL_STORAGE),
+ MANAGE_MEDIA(ManifestPermissionConstants.MANAGE_MEDIA),
+ MANAGE_ONGOING_CALLS(ManifestPermissionConstants.MANAGE_ONGOING_CALLS),
+ MANAGE_OWN_CALLS(ManifestPermissionConstants.MANAGE_OWN_CALLS),
+ MANAGE_WIFI_INTERFACES(ManifestPermissionConstants.MANAGE_WIFI_INTERFACES),
+ MANAGE_WIFI_NETWORK_SELECTION(ManifestPermissionConstants.MANAGE_WIFI_NETWORK_SELECTION),
+ MASTER_CLEAR(ManifestPermissionConstants.MASTER_CLEAR),
+ MEDIA_CONTENT_CONTROL(ManifestPermissionConstants.MEDIA_CONTENT_CONTROL),
+ MODIFY_AUDIO_SETTINGS(ManifestPermissionConstants.MODIFY_AUDIO_SETTINGS),
+ MODIFY_PHONE_STATE(ManifestPermissionConstants.MODIFY_PHONE_STATE),
+ MOUNT_FORMAT_FILESYSTEMS(ManifestPermissionConstants.MOUNT_FORMAT_FILESYSTEMS),
+ MOUNT_UNMOUNT_FILESYSTEMS(ManifestPermissionConstants.MOUNT_UNMOUNT_FILESYSTEMS),
+ NEARBY_WIFI_DEVICES(ManifestPermissionConstants.NEARBY_WIFI_DEVICES),
+ NFC(ManifestPermissionConstants.NFC),
+ NFC_PREFERRED_PAYMENT_INFO(ManifestPermissionConstants.NFC_PREFERRED_PAYMENT_INFO),
+ NFC_TRANSACTION_EVENT(ManifestPermissionConstants.NFC_TRANSACTION_EVENT),
+ OVERRIDE_WIFI_CONFIG(ManifestPermissionConstants.OVERRIDE_WIFI_CONFIG),
+ PACKAGE_USAGE_STATS(ManifestPermissionConstants.PACKAGE_USAGE_STATS),
+ PERSISTENT_ACTIVITY(ManifestPermissionConstants.PERSISTENT_ACTIVITY),
+ POST_NOTIFICATIONS(ManifestPermissionConstants.POST_NOTIFICATIONS),
+ PROCESS_OUTGOING_CALLS(ManifestPermissionConstants.PROCESS_OUTGOING_CALLS),
+ QUERY_ALL_PACKAGES(ManifestPermissionConstants.QUERY_ALL_PACKAGES),
+ READ_ASSISTANT_APP_SEARCH_DATA(ManifestPermissionConstants.READ_ASSISTANT_APP_SEARCH_DATA),
+ READ_BASIC_PHONE_STATE(ManifestPermissionConstants.READ_BASIC_PHONE_STATE),
+ READ_CALENDAR(ManifestPermissionConstants.READ_CALENDAR),
+ READ_CALL_LOG(ManifestPermissionConstants.READ_CALL_LOG),
+ READ_CONTACTS(ManifestPermissionConstants.READ_CONTACTS),
+ READ_EXTERNAL_STORAGE(ManifestPermissionConstants.READ_EXTERNAL_STORAGE),
+ READ_HOME_APP_SEARCH_DATA(ManifestPermissionConstants.READ_HOME_APP_SEARCH_DATA),
+ READ_INPUT_STATE(ManifestPermissionConstants.READ_INPUT_STATE),
+ READ_LOGS(ManifestPermissionConstants.READ_LOGS),
+ READ_MEDIA_AUDIO(ManifestPermissionConstants.READ_MEDIA_AUDIO),
+ READ_MEDIA_IMAGES(ManifestPermissionConstants.READ_MEDIA_IMAGES),
+ READ_MEDIA_VIDEO(ManifestPermissionConstants.READ_MEDIA_VIDEO),
+ READ_NEARBY_STREAMING_POLICY(ManifestPermissionConstants.READ_NEARBY_STREAMING_POLICY),
+ READ_PHONE_NUMBERS(ManifestPermissionConstants.READ_PHONE_NUMBERS),
+ READ_PHONE_STATE(ManifestPermissionConstants.READ_PHONE_STATE),
+ READ_PRECISE_PHONE_STATE(ManifestPermissionConstants.READ_PRECISE_PHONE_STATE),
+ READ_SMS(ManifestPermissionConstants.READ_SMS),
+ READ_SYNC_SETTINGS(ManifestPermissionConstants.READ_SYNC_SETTINGS),
+ READ_SYNC_STATS(ManifestPermissionConstants.READ_SYNC_STATS),
+ READ_VOICEMAIL(ManifestPermissionConstants.READ_VOICEMAIL),
+ REBOOT(ManifestPermissionConstants.REBOOT),
+ RECEIVE_BOOT_COMPLETED(ManifestPermissionConstants.RECEIVE_BOOT_COMPLETED),
+ RECEIVE_MMS(ManifestPermissionConstants.RECEIVE_MMS),
+ RECEIVE_SMS(ManifestPermissionConstants.RECEIVE_SMS),
+ RECEIVE_WAP_PUSH(ManifestPermissionConstants.RECEIVE_WAP_PUSH),
+ RECORD_AUDIO(ManifestPermissionConstants.RECORD_AUDIO),
+ REORDER_TASKS(ManifestPermissionConstants.REORDER_TASKS),
+ REQUEST_COMPANION_PROFILE_APP_STREAMING(ManifestPermissionConstants.REQUEST_COMPANION_PROFILE_APP_STREAMING),
+ REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION(ManifestPermissionConstants.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION),
+ REQUEST_COMPANION_PROFILE_COMPUTER(ManifestPermissionConstants.REQUEST_COMPANION_PROFILE_COMPUTER),
+ REQUEST_COMPANION_PROFILE_WATCH(ManifestPermissionConstants.REQUEST_COMPANION_PROFILE_WATCH),
+ REQUEST_COMPANION_RUN_IN_BACKGROUND(ManifestPermissionConstants.REQUEST_COMPANION_RUN_IN_BACKGROUND),
+ REQUEST_COMPANION_SELF_MANAGED(ManifestPermissionConstants.REQUEST_COMPANION_SELF_MANAGED),
+ REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND(ManifestPermissionConstants.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND),
+ REQUEST_COMPANION_USE_DATA_IN_BACKGROUND(ManifestPermissionConstants.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND),
+ REQUEST_DELETE_PACKAGES(ManifestPermissionConstants.REQUEST_DELETE_PACKAGES),
+ REQUEST_IGNORE_BATTERY_OPTIMIZATIONS(ManifestPermissionConstants.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS),
+ REQUEST_INSTALL_PACKAGES(ManifestPermissionConstants.REQUEST_INSTALL_PACKAGES),
+ REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE(ManifestPermissionConstants.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE),
+ REQUEST_PASSWORD_COMPLEXITY(ManifestPermissionConstants.REQUEST_PASSWORD_COMPLEXITY),
+ RESTART_PACKAGES(ManifestPermissionConstants.RESTART_PACKAGES),
+ SCHEDULE_EXACT_ALARM(ManifestPermissionConstants.SCHEDULE_EXACT_ALARM),
+ SEND_RESPOND_VIA_MESSAGE(ManifestPermissionConstants.SEND_RESPOND_VIA_MESSAGE),
+ SEND_SMS(ManifestPermissionConstants.SEND_SMS),
+ SET_ALARM(ManifestPermissionConstants.SET_ALARM),
+ SET_ALWAYS_FINISH(ManifestPermissionConstants.SET_ALWAYS_FINISH),
+ SET_ANIMATION_SCALE(ManifestPermissionConstants.SET_ANIMATION_SCALE),
+ SET_DEBUG_APP(ManifestPermissionConstants.SET_DEBUG_APP),
+ SET_PREFERRED_APPLICATIONS(ManifestPermissionConstants.SET_PREFERRED_APPLICATIONS),
+ SET_PROCESS_LIMIT(ManifestPermissionConstants.SET_PROCESS_LIMIT),
+ SET_TIME(ManifestPermissionConstants.SET_TIME),
+ SET_TIME_ZONE(ManifestPermissionConstants.SET_TIME_ZONE),
+ SET_WALLPAPER(ManifestPermissionConstants.SET_WALLPAPER),
+ SET_WALLPAPER_HINTS(ManifestPermissionConstants.SET_WALLPAPER_HINTS),
+ SIGNAL_PERSISTENT_PROCESSES(ManifestPermissionConstants.SIGNAL_PERSISTENT_PROCESSES),
+ SMS_FINANCIAL_TRANSACTIONS(ManifestPermissionConstants.SMS_FINANCIAL_TRANSACTIONS),
+ START_FOREGROUND_SERVICES_FROM_BACKGROUND(ManifestPermissionConstants.START_FOREGROUND_SERVICES_FROM_BACKGROUND),
+ START_VIEW_APP_FEATURES(ManifestPermissionConstants.START_VIEW_APP_FEATURES),
+ START_VIEW_PERMISSION_USAGE(ManifestPermissionConstants.START_VIEW_PERMISSION_USAGE),
+ STATUS_BAR(ManifestPermissionConstants.STATUS_BAR),
+ SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE(ManifestPermissionConstants.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE),
+ SYSTEM_ALERT_WINDOW(ManifestPermissionConstants.SYSTEM_ALERT_WINDOW),
+ TRANSMIT_IR(ManifestPermissionConstants.TRANSMIT_IR),
+ UNINSTALL_SHORTCUT(ManifestPermissionConstants.UNINSTALL_SHORTCUT),
+ UPDATE_DEVICE_STATS(ManifestPermissionConstants.UPDATE_DEVICE_STATS),
+ UPDATE_PACKAGES_WITHOUT_USER_ACTION(ManifestPermissionConstants.UPDATE_PACKAGES_WITHOUT_USER_ACTION),
+ USE_BIOMETRIC(ManifestPermissionConstants.USE_BIOMETRIC),
+ USE_EXACT_ALARM(ManifestPermissionConstants.USE_EXACT_ALARM),
+ USE_FINGERPRINT(ManifestPermissionConstants.USE_FINGERPRINT),
+ USE_FULL_SCREEN_INTENT(ManifestPermissionConstants.USE_FULL_SCREEN_INTENT),
+ USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER(ManifestPermissionConstants.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER),
+ USE_SIP(ManifestPermissionConstants.USE_SIP),
+ UWB_RANGING(ManifestPermissionConstants.UWB_RANGING),
+ VIBRATE(ManifestPermissionConstants.VIBRATE),
+ WAKE_LOCK(ManifestPermissionConstants.WAKE_LOCK),
+ WRITE_APN_SETTINGS(ManifestPermissionConstants.WRITE_APN_SETTINGS),
+ WRITE_CALENDAR(ManifestPermissionConstants.WRITE_CALENDAR),
+ WRITE_CALL_LOG(ManifestPermissionConstants.WRITE_CALL_LOG),
+ WRITE_CONTACTS(ManifestPermissionConstants.WRITE_CONTACTS),
+ WRITE_EXTERNAL_STORAGE(ManifestPermissionConstants.WRITE_EXTERNAL_STORAGE),
+ WRITE_GSERVICES(ManifestPermissionConstants.WRITE_GSERVICES),
+ WRITE_SECURE_SETTINGS(ManifestPermissionConstants.WRITE_SECURE_SETTINGS),
+ WRITE_SETTINGS(ManifestPermissionConstants.WRITE_SETTINGS),
+ WRITE_SYNC_SETTINGS(ManifestPermissionConstants.WRITE_SYNC_SETTINGS),
+ WRITE_VOICEMAIL(ManifestPermissionConstants.WRITE_VOICEMAIL);
+}
diff --git a/build-tools/xml-utils/src/main/java/com/itsaky/androidide/xml/permissions/PermissionGroup.kt b/build-tools/xml-utils/src/main/java/com/itsaky/androidide/xml/permissions/PermissionGroup.kt
new file mode 100644
index 000000000..e1d278135
--- /dev/null
+++ b/build-tools/xml-utils/src/main/java/com/itsaky/androidide/xml/permissions/PermissionGroup.kt
@@ -0,0 +1,42 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AndroidIDE is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.xml.permissions
+
+/**
+ * Model for a permission group entry.
+ *
+ * @property constant The constant value of the permission group.
+ * @author Akash Yadav
+ */
+enum class PermissionGroup(val constant: String) {
+ ACTIVITY_RECOGNITION(ManifestPermissionConstants.GROUP_ACTIVITY_RECOGNITION),
+ CALENDAR(ManifestPermissionConstants.GROUP_CALENDAR),
+ CALL_LOG(ManifestPermissionConstants.GROUP_CALL_LOG),
+ CAMERA(ManifestPermissionConstants.GROUP_CAMERA),
+ CONTACTS(ManifestPermissionConstants.GROUP_CONTACTS),
+ LOCATION(ManifestPermissionConstants.GROUP_LOCATION),
+ MICROPHONE(ManifestPermissionConstants.GROUP_MICROPHONE),
+ NEARBY_DEVICES(ManifestPermissionConstants.GROUP_NEARBY_DEVICES),
+ NOTIFICATIONS(ManifestPermissionConstants.GROUP_NOTIFICATIONS),
+ PHONE(ManifestPermissionConstants.GROUP_PHONE),
+ READ_MEDIA_AURAL(ManifestPermissionConstants.GROUP_READ_MEDIA_AURAL),
+ READ_MEDIA_VISUAL(ManifestPermissionConstants.GROUP_READ_MEDIA_VISUAL),
+ SENSORS(ManifestPermissionConstants.GROUP_SENSORS),
+ SMS(ManifestPermissionConstants.GROUP_SMS),
+ STORAGE(ManifestPermissionConstants.GROUP_STORAGE)
+}
\ No newline at end of file
diff --git a/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrValueCompletionProvider.kt b/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrValueCompletionProvider.kt
index 6906551d8..4638ede67 100644
--- a/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrValueCompletionProvider.kt
+++ b/lsp/xml/src/main/java/com/itsaky/androidide/lsp/xml/providers/completion/manifest/ManifestAttrValueCompletionProvider.kt
@@ -17,6 +17,7 @@
package com.itsaky.androidide.lsp.xml.providers.completion.manifest
+import com.android.SdkConstants
import com.android.SdkConstants.ANDROID_NS_NAME_PREFIX
import com.android.SdkConstants.ATTR_NAME
import com.android.SdkConstants.TAG_ACTIVITY
@@ -27,13 +28,16 @@ import com.android.aaptcompiler.ResourceGroup
import com.android.aaptcompiler.ResourceTable
import com.itsaky.androidide.lookup.Lookup
import com.itsaky.androidide.lsp.api.ICompletionProvider
+import com.itsaky.androidide.lsp.models.CompletionData
import com.itsaky.androidide.lsp.models.CompletionItem
+import com.itsaky.androidide.lsp.models.CompletionItemKind.FIELD
import com.itsaky.androidide.lsp.models.MatchLevel.NO_MATCH
import com.itsaky.androidide.lsp.xml.edits.QualifiedValueEditHandler
import com.itsaky.androidide.lsp.xml.providers.completion.common.AttrValueCompletionProvider
import com.itsaky.androidide.lsp.xml.providers.completion.match
import com.itsaky.androidide.projects.api.AndroidModule
import com.itsaky.androidide.projects.api.ModuleProject
+import com.itsaky.androidide.xml.permissions.Permission
import com.itsaky.androidide.xml.resources.ResourceTableRegistry
/**
@@ -54,13 +58,37 @@ class ManifestAttrValueCompletionProvider(provider: ICompletionProvider) :
when (this.nodeAtCursor.nodeName) {
"action" -> completeActionName(prefix, result)
"category" -> completeCategory(prefix, result)
- // "uses-permission" -> completePermission(prefix, result)
+ "uses-permission" -> completePermission(prefix, result)
"uses-feature" -> completeFeature(prefix, result)
}
}
super.completeInternal(attrName, prefix, groups, result)
}
+ // TODO we could add an action using the actions registry to make it easier to add permissions
+ // with a GUI interface
+ private fun completePermission(prefix: String, result: MutableList) {
+ for (value in Permission.values()) {
+ val match = match(value.name, value.constant, prefix)
+ if (match == NO_MATCH) {
+ continue
+ }
+
+ val item = createEnumOrFlagCompletionItem(ResourceTableRegistry.PCK_ANDROID, value.name, match)
+ item.insertText = "."
+ item.additionalEditHandler = QualifiedValueEditHandler()
+ item.overrideTypeText = "Permission"
+
+ // Show API information
+ item.kind = FIELD
+ item.data = CompletionData().apply {
+ this.className = SdkConstants.CLASS_MANIFEST_PERMISSION
+ this.memberName = value.name
+ }
+ result.add(item)
+ }
+ }
+
private fun completeActionName(prefix: String, result: MutableList) {
val parent = this.nodeAtCursor.parentNode ?: return
val parentOfParent = parent.parentNode ?: return
@@ -125,7 +153,7 @@ class ManifestAttrValueCompletionProvider(provider: ICompletionProvider) :
if (match == NO_MATCH) {
continue
}
-
+
val item = createEnumOrFlagCompletionItem(ResourceTableRegistry.PCK_ANDROID, entry, match)
item.insertText = "."
item.additionalEditHandler = QualifiedValueEditHandler()
diff --git a/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/providers/completion/ManifestAttrValueCompletionProviderTest.kt b/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/providers/completion/ManifestAttrValueCompletionProviderTest.kt
index 1eb55d4c8..5992bbbe2 100644
--- a/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/providers/completion/ManifestAttrValueCompletionProviderTest.kt
+++ b/lsp/xml/src/test/java/com/itsaky/androidide/lsp/xml/providers/completion/ManifestAttrValueCompletionProviderTest.kt
@@ -148,6 +148,23 @@ class ManifestAttrValueCompletionProviderTest : CompletionHelper by CompletionHe
)
}
}
+
+ @Test
+ fun `permission value completion test`() {
+ XMLLSPTest.apply {
+ assertHasSingleLineEntries(
+ "ManifestPermissionCompletionTest",
+ arrayOf(
+ "WRITE_EXTERNAL_STORAGE",
+ "WRITE_LOCK",
+ "WRITE_CONTACTS",
+ "WRITE_SETTINGS",
+ "WRITE_SECURE_SETTINGS",
+ "WRITE_VOICEMAIL"
+ )
+ )
+ }
+ }
private fun XMLLSPTest.assertHasSingleLineEntries(file: String, expect: Array) {
openFile("completion/$file")
diff --git a/tests/test-home/.androidide/init/model.jar b/tests/test-home/.androidide/init/model.jar
index 721ee0ea3..9ed0438b1 100644
Binary files a/tests/test-home/.androidide/init/model.jar and b/tests/test-home/.androidide/init/model.jar differ
diff --git a/tests/test-project/app/src/main/resources/completion/ManifestPermissionCompletionTest_template.xml b/tests/test-project/app/src/main/resources/completion/ManifestPermissionCompletionTest_template.xml
new file mode 100644
index 000000000..844c16235
--- /dev/null
+++ b/tests/test-project/app/src/main/resources/completion/ManifestPermissionCompletionTest_template.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+