/****************************************************************************
* Copyright 2019 Nreal Techonology Limited.All rights reserved.
*
* This file is part of NRSDK.
*
* https://www.nreal.ai/
*
*****************************************************************************/
namespace NRKernal
{
using System.Text;
using System.Xml;
/// An android XML document.
internal class AndroidXmlDocument : XmlDocument
{
/// Full pathname of the file.
protected string m_Path;
/// Manager for name space.
protected XmlNamespaceManager nameSpaceManager;
/// The android XML namespace.
public readonly string AndroidXmlNamespace = "http://schemas.android.com/apk/res/android";
/// The android tools XML namespace.
public readonly string AndroidToolsXmlNamespace = "http://schemas.android.com/tools";
/// Constructor.
/// Full pathname of the file.
public AndroidXmlDocument(string path)
{
m_Path = path;
using (var reader = new XmlTextReader(m_Path))
{
reader.Read();
Load(reader);
}
nameSpaceManager = new XmlNamespaceManager(NameTable);
nameSpaceManager.AddNamespace("android", AndroidXmlNamespace);
}
/// Gets the save.
/// A string.
public string Save()
{
return SaveAs(m_Path);
}
/// Saves as.
/// Full pathname of the file.
/// A string.
public string SaveAs(string path)
{
using (var writer = new XmlTextWriter(path, new UTF8Encoding(false)))
{
writer.Formatting = Formatting.Indented;
Save(writer);
}
return path;
}
}
/// A list of the android.
internal class AndroidManifest : AndroidXmlDocument
{
/// Element describing the application.
private readonly XmlElement ApplicationElement;
/// Constructor.
/// Full pathname of the file.
public AndroidManifest(string path) : base(path)
{
ApplicationElement = SelectSingleNode("/manifest/application") as XmlElement;
}
/// Creates android attribute.
/// The key.
/// The value.
/// (Optional) The name.
/// The new android attribute.
private XmlAttribute CreateAndroidAttribute(string key, string value, string name = "android")
{
XmlAttribute attr;
if (name.Equals("tools"))
{
attr = CreateAttribute(name, key, AndroidToolsXmlNamespace);
attr.Value = value;
}
else
{
attr = CreateAttribute(name, key, AndroidXmlNamespace);
attr.Value = value;
}
return attr;
}
/// Gets activity with launch intent.
/// The activity with launch intent.
internal XmlNode GetActivityWithLaunchIntent()
{
return SelectSingleNode("/manifest/application/activity[intent-filter/action/@android:name='android.intent.action.MAIN' and " +
"intent-filter/category/@android:name='android.intent.category.LAUNCHER']", nameSpaceManager);
}
/// Gets activity with information intent.
/// The activity with information intent.
internal XmlNode GetActivityWithInfoIntent()
{
return SelectSingleNode("/manifest/application/activity[intent-filter/action/@android:name='android.intent.action.MAIN' and " +
"intent-filter/category/@android:name='android.intent.category.INFO']", nameSpaceManager);
}
/// Sets external storage.
/// True to flag.
internal void SetExternalStorage(bool flag)
{
var activity = SelectSingleNode("/manifest/application");
var rightapplicationData = SelectSingleNode("/manifest/application[@android:requestLegacyExternalStorage='true']", nameSpaceManager);
if (flag)
{
if (rightapplicationData == null)
{
XmlAttribute newAttribute = CreateAndroidAttribute("requestLegacyExternalStorage", "true");
activity.Attributes.Append(newAttribute);
}
}
else
{
if (rightapplicationData != null)
{
activity.Attributes.RemoveNamedItem("android:requestLegacyExternalStorage");
}
}
}
/// Sets camera permission.
internal void SetCameraPermission()
{
var manifest = SelectSingleNode("/manifest");
if (!manifest.InnerXml.Contains("android.permission.CAMERA"))
{
XmlElement child = CreateElement("uses-permission");
manifest.AppendChild(child);
XmlAttribute newAttribute = CreateAndroidAttribute("name", "android.permission.CAMERA");
child.Attributes.Append(newAttribute);
}
//else
//{
// NRDebugger.Info("Already has the camera permission.");
//}
}
internal void SetPackageReadPermission()
{
var manifest = SelectSingleNode("/manifest");
if (!manifest.InnerXml.Contains("android.permission.QUERY_ALL_PACKAGES"))
{
XmlElement child = CreateElement("uses-permission");
manifest.AppendChild(child);
XmlAttribute newAttribute = CreateAndroidAttribute("name", "android.permission.QUERY_ALL_PACKAGES");
child.Attributes.Append(newAttribute);
}
//else
//{
// NRDebugger.Info("Already has the permission of 'android.permission.QUERY_ALL_PACKAGES'.");
//}
}
/// Sets blue tooth permission.
internal void SetBlueToothPermission()
{
var manifest = SelectSingleNode("/manifest");
if (!manifest.InnerXml.Contains("android.permission.BLUETOOTH"))
{
XmlElement child = CreateElement("uses-permission");
manifest.AppendChild(child);
XmlAttribute newAttribute = CreateAndroidAttribute("name", "android.permission.BLUETOOTH");
child.Attributes.Append(newAttribute);
// newAttribute = CreateAndroidAttribute("name", "android.permission.BLUETOOTH_ADMIN");
// child.Attributes.Append(newAttribute);
}
//else
//{
// NRDebugger.Info("Already has the bluetooth permission.");
//}
}
internal void SetAudioRecordPermission()
{
var manifest = SelectSingleNode("/manifest");
if (!manifest.InnerXml.Contains("android.permission.RECORD_AUDIO"))
{
XmlElement child = CreateElement("uses-permission");
manifest.AppendChild(child);
XmlAttribute newAttribute = CreateAndroidAttribute("name", "android.permission.RECORD_AUDIO");
child.Attributes.Append(newAttribute);
}
}
/// Sets sdk meta data.
internal void SetSDKMetaData()
{
var activity = SelectSingleNode("/manifest/application");
// metadata for "nreal_sdk
var newMetaNRSDK = SelectSingleNode("/manifest/application/meta-data[@android:name='nreal_sdk' and " +
"@android:value='true']", nameSpaceManager);
var oldMetaNRSDK = SelectSingleNode("/manifest/application/meta-data[@android:name='nreal_sdk']", nameSpaceManager);
if (newMetaNRSDK == null)
{
if (oldMetaNRSDK != null)
{
activity.RemoveChild(oldMetaNRSDK);
}
XmlElement child = CreateElement("meta-data");
activity.AppendChild(child);
XmlAttribute newAttribute = CreateAndroidAttribute("name", "nreal_sdk");
child.Attributes.Append(newAttribute);
newAttribute = CreateAndroidAttribute("value", "true");
child.Attributes.Append(newAttribute);
}
// metadata for "com.nreal.supportDevices"
string supportDevices = NRProjectConfigHelper.GetProjectConfig().GetTargetDeviceTypesDesc();
var newMetaDevices = SelectSingleNode("/manifest/application/meta-data[@android:name='com.nreal.supportDevices' and " +
"@android:value='']", nameSpaceManager);
var oldMetaDevices = SelectSingleNode("/manifest/application/meta-data[@android:name='com.nreal.supportDevices']", nameSpaceManager);
if (oldMetaDevices != null)
activity.RemoveChild(oldMetaDevices);
if (newMetaDevices == null)
{
XmlElement child = CreateElement("meta-data");
activity.AppendChild(child);
XmlAttribute newAttribute = CreateAndroidAttribute("name", "com.nreal.supportDevices");
child.Attributes.Append(newAttribute);
newAttribute = CreateAndroidAttribute("value", supportDevices);
child.Attributes.Append(newAttribute);
}
}
/// Sets a pk displayed on launcher.
/// True to show, false to hide.
internal void SetAPKDisplayedOnLauncher(bool show)
{
var activity = GetActivityWithLaunchIntent();
if (activity == null)
{
activity = GetActivityWithInfoIntent();
}
var intentfilter = SelectSingleNode("/manifest/application/activity/intent-filter[action/@android:name='android.intent.action.MAIN']", nameSpaceManager);
var categoryInfo = SelectSingleNode("/manifest/application/activity/intent-filter/category[@android:name='android.intent.category.INFO']", nameSpaceManager);
var categoryLauncher = SelectSingleNode("/manifest/application/activity/intent-filter/category[@android:name='android.intent.category.LAUNCHER']", nameSpaceManager);
if (show)
{
// Add launcher category
XmlElement newcategory = CreateElement("category");
XmlAttribute newAttribute = CreateAndroidAttribute("name", "android.intent.category.LAUNCHER");
newcategory.Attributes.Append(newAttribute);
if (categoryInfo != null)
{
intentfilter.ReplaceChild(newcategory, categoryInfo);
}
else if (categoryLauncher == null)
{
intentfilter.AppendChild(newcategory);
}
}
else
{
// Add info category
XmlElement newcategory = CreateElement("category");
XmlAttribute newAttribute = CreateAndroidAttribute("name", "android.intent.category.INFO");
newcategory.Attributes.Append(newAttribute);
newAttribute = CreateAndroidAttribute("node", "replace", "tools");
newcategory.Attributes.Append(newAttribute);
if (categoryLauncher != null)
{
intentfilter.ReplaceChild(newcategory, categoryLauncher);
}
else if (categoryInfo == null)
{
intentfilter.AppendChild(newcategory);
}
}
}
}
}