src/AndroidAppComponents.js
const Logger = require('./Logger.js')();
const _md5_ = require('md5');
const ANDROID_PREFIX = "android:";
const ANDROID_PREFIX_LEN = 8;
const UID_SEPARATOR = "-";
class IntentActionCriteria
{
static androidPrefixed = [];
constructor(){
this.__attr = {};
this.name = null;
}
getName(){
return this.name;
}
setAttributes(attr){
let n="";
for(let i in attr){
if(i.startsWith(ANDROID_PREFIX)){
n = i.substr(ANDROID_PREFIX_LEN);
if(IntentActionCriteria.androidPrefixed.indexOf(n)==-1)
IntentActionCriteria.androidPrefixed.push(n);
this.__attr[n] = attr[i];
}else{
this.__attr[i] = attr[i];
}
}
}
getAttributes(){
return this.__attr;
}
getAttribute(name){
return this.__attr[name];
}
static fromXml(xmlobj){
let o = new IntentActionCriteria();
o.setAttributes(xmlobj);
o.name = o.__attr.name;
return o;
}
toXmlObject(){
let o = {};
o.$ = {};
for(let i in this.attr){
if(IntentActionCriteria.androidPrefixed.indexOf(i)>-1)
o.$[ANDROID_PREFIX+i] = this.attr[i];
else
o.$[i] = this.attr[i];
}
return o;
}
toJsonObject(){
let o = new Object();
o.name = this.__attr.name;
return o;
}
}
class IntentCategoryCriteria
{
static androidPrefixed = [];
constructor(){
this.__attr = {};
this.name = null;
}
getName(){
return this.name;
}
setAttributes(attr){
let n="";
for(let i in attr){
if(i.startsWith(ANDROID_PREFIX)){
n = i.substr(ANDROID_PREFIX_LEN);
if(IntentCategoryCriteria.androidPrefixed.indexOf(n)==-1)
IntentCategoryCriteria.androidPrefixed.push(n);
this.__attr[n] = attr[i];
}else{
this.__attr[i] = attr[i];
}
}
}
getAttributes(){
return this.__attr;
}
getAttribute(name){
return this.__attr[name];
}
static fromXml(xmlobj){
let o = new IntentCategoryCriteria();
o.setAttributes(xmlobj);
o.name = o.__attr.name;
return o;
}
toXmlObject(){
let o = {};
o.$ = {};
for(let i in this.attr){
if(IntentCategoryCriteria.androidPrefixed.indexOf(i)>-1)
o.$[ANDROID_PREFIX+i] = this.attr[i];
else
o.$[i] = this.attr[i];
}
return o;
}
toJsonObject(){
let o = new Object();
o.name = this.__attr.name;
return o;
}
/*
constructor(){
this.name = null;
}
static fromXml(xmlobj){
let o = new IntentCategoryCriteria();
o.name = xmlobj['android:name'];
return o;
}
toJsonObject(){
let o = new Object();
o.name = this.name;
return o;
}*/
}
class IntentDataCriteria
{
constructor(){
this.scheme=null;
this.host=null;
this.port=null;
this.path=null;
this.pathPattern=null;
this.pathPrefix=null;
this.mimeType=null;
}
static fromXml(xmlobj){
let o = new IntentDataCriteria();
for(let i in xmlobj){
if(i.startsWith('android:')){
o[i.substring(8)] = xmlobj[i];
}else{
o[i] = xmlobj[i];
}
}
return o;
}
toJsonObject(){
let o = new Object();
o.scheme = this.scheme;
o.host = this.host;
o.port = this.port;
o.path = this.path;
o.pathPattern = this.pathPattern;
o.pathPrefix = this.pathPrefix;
o.mimeType = this.mimeType;
return o;
}
}
class IntentFilter
{
constructor(config){
this.__id = null;
this.action = [];
this.category = [];
this.data = [];
// auto config
if(config != null){
for(let i in config)
this[i] = config[i];
}
}
generateUID(parent){
this.__id = parent.getUID()+UID_SEPARATOR+parent.countIntentFilter();
}
getUid(){
return this.__id;
}
getActions(){
return this.action;
}
getCategories(){
return this.category;
}
getData(){
return this.data;
}
hasData(){
return this.data.length > 0;
}
toXmlObject(){
let o = {action:[], category:[], data:[]};
for(let i in this){
for(let j=0; j<this[i].length; j++){
o[i].push(this[i][j].toXmlObject());
}
}
return o;
}
static fromXml(xmlobj){
let intf = new IntentFilter();
if(xmlobj.action != null && xmlobj.action instanceof Array){
for(let i=0; i<xmlobj.action.length; i++){
intf.action.push(IntentActionCriteria.fromXml(xmlobj.action[i].$));
}
}
if(xmlobj.category != null && xmlobj.category instanceof Array){
for(let i=0; i<xmlobj.category.length; i++){
intf.category.push(IntentCategoryCriteria.fromXml(xmlobj.category[i].$));
}
}
if(xmlobj.data != null && xmlobj.data instanceof Array){
for(let i=0; i<xmlobj.data.length; i++){
intf.data.push(IntentDataCriteria.fromXml(xmlobj.data[i].$));
}
}
return intf;
}
/**
*
* @param {Activity} activity
* @returns {String} The next valid value for Intent Filter UID
* @function
*/
static generateIntentFilterUID(activity){
return activity.getUID()+UID_SEPARATOR+activity.intentFilters.length;
}
toJsonObject(){
let o = new Object();
o.__id = this.__id;
o.data = [];
this.data.map(x => o.data.push(x.toJsonObject()));
o.action = [];
this.action.map(x => o.action.push(x.toJsonObject()));
o.category = [];
this.category.map(x => o.category.push(x.toJsonObject()));
return o;
}
}
class AndroidPermissionSdk23
{
static MODEL = {
name:"string",
maxSdkVersion:"integer"
}
constructor(){
this.name = null;
this.maxSdkVersion = null;
}
static fromXml(xmlobj){
let o = new AndroidPermissionSdk23();
for(let i in xmlobj){
if(i.startsWith('android:')){
o[i.substr(8)] = xmlobj[i];
}else{
o[i] = xmlobj[i];
}
}
return o;
}
}
class AndroidGlTexture
{
constructor(){
this.name = null;
}
static fromXml(xmlobj){
let o = new AndroidGlTexture();
o.name = xmlobj['android:name'];
return o;
}
}
class AndroidFeature
{
constructor(){
this.name = null;
this.require = null;
this.glEsVersion = null;
}
static fromXml(xmlobj){
let p = new AndroidFeature();
for(let i in xmlobj){
if(i.startsWith('android:')){
p[i.substr(8)] = xmlobj[i];
}else{
p[i] = xmlobj[i];
}
}
return p;
}
}
class AndroidActivityAlias
{
constructor(config=null){
this.enabled=null;
this.exported=null;
this.icon=null;
this.label=null;
this.name=null;
this.permission=null;
this.targetActivity=null;
if(config != null){
for(let i in config)
if(this[i] !== undefined)
this[i] = config[i];
}
}
toXmlObject(){
let o = {$:{}};
for(let i in this){
o.$["android:"+i] = this[i];
}
return o;
}
static fromXml(xmlobj){
let act = new AndroidActivityAlias();
for(let i in xmlobj.$){
if(i.indexOf("android:")>-1)
act[i.substr(8)] = xmlobj.$[i];
else
act[i] = xmlobj.$[i];
}
return act;
}
}
class AndroidInstrumentation
{
static MODEL = {
functionalTest:["true" , "false"],
handleProfiling:["true" , "false"],
icon:"drawable resource",
label:"string resource",
name:"string",
targetPackage:"string",
targetProcesses:"string"
}
constructor(config=null){
this.functionalTest=null;
this.handleProfiling=null;
this.icon=null;
this.label=null;
this.name=null;
this.targetPackage=null;
this.targetProcesses=null;
}
static fromXml(xmlobj){
let p = new AndroidInstrumentation();
for(let i in xmlobj){
if(i.startsWith('android:')){
p[i.substr(8)] = xmlobj[i];
}else{
p[i] = xmlobj[i];
}
}
return p;
}
}
class AndroidSupportedScreen
{
static MODEL = {
resizeable:["true" | "false"],
smallScreens:["true" | "false"],
normalScreens:["true" | "false"],
largeScreens:["true" | "false"],
xlargeScreens:["true" | "false"],
anyDensity:["true" | "false"],
requiresSmallestWidthDp:"integer",
compatibleWidthLimitDp:"integer",
largestWidthLimitDp:"integer"
}
constructor(){
this.resizeable=null;
this.smallScreens=null;
this.normalScreens=null;
this.largeScreens=null;
this.xlargeScreens=null;
this.anyDensity=null;
this.requiresSmallestWidthDp=null;
this.compatibleWidthLimitDp=null;
this.largestWidthLimitDp=null;
}
static fromXml(xmlobj){
let p = new AndroidSupportedScreen();
for(let i in xmlobj){
if(i.startsWith('android:')){
p[i.substr(8)] = xmlobj[i];
}else{
p[i] = xmlobj[i];
}
}
return p;
}
}
class AndroidScreen
{
constructor(config=null){
this.screenSize = null;
this.screenDensity = null;
}
static fromXml(xmlobj){
let p = new AndroidScreen();
for(let i in xmlobj){
if(i.startsWith('android:')){
p[i.substr(8)] = xmlobj[i];
}else{
p[i] = xmlobj[i];
}
}
return p;
}
}
class AndroidConfiguration
{
static MODEL = {
reqFiveWayNav:["true" | "false"],
reqHardKeyboard:["true" | "false"],
reqKeyboardType:["undefined" | "nokeys" | "qwerty" | "twelvekey"],
reqNavigation:["undefined" | "nonav" | "dpad" | "trackball" | "wheel"],
reqTouchScreen:["undefined" | "notouch" | "stylus" | "finger"]
}
constructor(){
this.reqFiveWayNav=null;
this.reqHardKeyboard=null;
this.reqKeyboardType=null;
this.reqNavigation=null;
this.reqTouchScreen=null;
}
static fromXml(xmlobj){
let p = new AndroidConfiguration();
for(let i in xmlobj){
if(i.startsWith('android:')){
p[i.substr(8)] = xmlobj[i];
}else{
p[i] = xmlobj[i];
}
}
return p;
}
}
class ProtectionLevel
{
static NORMAL = new ProtectionLevel({ name:"normal" });
static SIGNATURE = new ProtectionLevel({ name:"signature" });
static SPECIAL = new ProtectionLevel({ name:"special" });
static DANGEROUS = new ProtectionLevel({ name:"dangerous" });
static PRIVILEGED = new ProtectionLevel({ name:"privileged" });
static DEVELOPMENT = new ProtectionLevel({ name:"development" });
constructor(config=null){
this.name = null;
if(config != null){
for(let i in config){
this[i] = config[i];
}
}
}
}
class Permission
{
constructor(config=null){
this.description = null;
this.label = null;
this.name = null;
this.permissionGroup = null;
this.protectionLevel = null;
this.apiVersion = 1;
this.controls = null;
this.query = null;
this.__custom = false;
this.__tag = [];
this.__raw = null;
if(config != null){
for(let i in config){
this[i] = config[i];
}
}
}
addTag(tag){
if(this.__tag.indexOf(tag)==-1)
this.__tag.push(tag);
}
getTags(){
return this.__tag;
}
isCustom(){
return this.__custom===true;
}
setCustom(bool){
this.__custom = bool;
}
update(otherPerm,override=false){
for(let i in otherPerm){
if(override || (this[i]===null)){
this[i] = otherPerm[i];
}
}
}
static fromXml(xmlobj){
let p = new Permission();
p.__raw = xmlobj;
for(let i in xmlobj){
if(i.startsWith('android:')){
p[i.substr(8)] = xmlobj[i];
}else{
p[i] = xmlobj[i];
}
}
return p;
}
toJsonObject(){
let o = new Object();
o.name = this.name;
o.label = this.label;
o.description = this.description;
o.apiVersion = this.apiVersion;
o.controls = this.controls;
o.query = this.query;
if(this.permissionGroup != null)
o.permissionGroup = this.permissionGroup.name;
else
o.permissionGroup = null;
if(this.protectionLevel != null){
if(this.protectionLevel instanceof Array){
o.protectionLevel = [];
for(let i=0; i<o.protectionLevel.length; i++){
o.protectionLevel.push(this.protectionLevel[i].name);
}
}else
o.protectionLevel = this.protectionLevel.name;
}else
o.protectionLevel = null;
return o;
}
}
class PermissionGroup
{
constructor(config=null){
this.description = null;
this.label = null;
this.name = null;
this.children = [];
// auto config
if(config != null){
for(let i in config)
if(this[i] !== undefined)
this[i] = config[i];
}
for(let i=0; i<this.children.length; i++){
if(this.children[i].permissionGroup === null){
this.children[i].permissionGroup = this;
}
}
}
static fromXml(xmlobj){
let p = new PermissionGroup();
for(let i in xmlobj){
if(i.startsWith('android:'))
p[i.substr(8)] = xmlobj[i];
else
p[i] = xmlobj[i];
}
return p;
}
}
class PermissionTree
{
constructor(config=null){
this.icon = null;
this.label = null;
this.name = null;
// auto config
if(config != null){
for(let i in config)
if(this[i] !== undefined)
this[i] = config[i];
}
}
static fromXml(xmlobj){
let p = new PermissionTree();
for(let i in xmlobj){
if(i.startsWith('android:'))
p[i.substr(8)] = xmlobj[i];
else
p[i] = xmlobj[i];
}
return p;
}
}
/**
* To represent an activity declared into the Android manifest
*
*/
class AndroidActivity
{
static MODEL = {
allowEmbedded:["true" , "false"],
allowTaskReparenting:["true" , "false"],
alwaysRetainTaskState:["true" , "false"],
autoRemoveFromRecents:["true" , "false"],
banner:"drawable resource",
clearTaskOnLaunch:["true" , "false"],
colorMode:[ "hdr" , "wideColorGamut"],
configChanges:["mcc", "mnc", "locale",
"touchscreen", "keyboard", "keyboardHidden",
"navigation", "screenLayout", "fontScale",
"uiMode", "orientation", "density",
"screenSize", "smallestScreenSize"],
directBootAware:["true" , "false"],
documentLaunchMode:["intoExisting" , "always" ,
"none" , "never"],
enabled:["true" , "false"],
excludeFromRecents:["true" , "false"],
exported:["true" , "false"],
finishOnTaskLaunch:["true" , "false"],
hardwareAccelerated:["true" , "false"],
icon:"drawable resource",
immersive:["true" , "false"],
label:"string resource",
launchMode:["standard" , "singleTop" ,
"singleTask" , "singleInstance"],
lockTaskMode:["normal" , "never" ,
"if_whitelisted" , "always"],
maxRecents:"integer",
maxAspectRatio:"float",
multiprocess:["true" , "false"],
name:"string",
noHistory:["true" , "false"],
parentActivityName:"string",
persistableMode:["persistRootOnly" ,
"persistAcrossReboots" , "persistNever"],
permission:"string",
process:"string",
relinquishTaskIdentity:["true" , "false"],
resizeableActivity:["true" , "false"],
screenOrientation:["unspecified" , "behind" ,
"landscape" , "portrait" ,
"reverseLandscape" , "reversePortrait" ,
"sensorLandscape" , "sensorPortrait" ,
"userLandscape" , "userPortrait" ,
"sensor" , "fullSensor" , "nosensor" ,
"user" , "fullUser" , "locked"],
showForAllUsers:["true" , "false"],
stateNotNeeded:["true" , "false"],
supportsPictureInPicture:["true" , "false"],
taskAffinity:"string",
theme:"resource or theme",
uiOptions:["none" , "splitActionBarWhenNarrow"],
windowSoftInputMode:["stateUnspecified",
"stateUnchanged", "stateHidden",
"stateAlwaysHidden", "stateVisible",
"stateAlwaysVisible", "adjustUnspecified",
"adjustResize", "adjustPan"]
}
static androidPrefixed = [];
constructor(config=null){
// the manifest data are stored here
this.attr = {};
this.label = null;
this.name = null;
this.intentFilters = [];
this.metadata = null;
this.__id = null;
this.__impl = null;
this.__tag = [];
this.__ppts = {};
// auto config
if(config != null){
for(let i in config)
if(this[i] !== undefined)
this[i] = config[i];
if(this.name != null)
this.generateUID();
}
}
generateUID(){
if(this.name == null) throw new Error("[ACTIVITY] Unable to generate UID");
this.__id = _md5_(this.name);
}
getUID(){
if(this.__id == null){
Logger.debug("Activity UID is null : generating UID");
this.generateUID();
}
return this.__id;
}
setImplementedBy(cls){
this.__impl = cls;
}
getImplementedBy(){
return this.__impl;
}
setActivityClass(x){
this.ref = x;
}
getActivityClass(){
return this.ref;
}
setAttributes(attr){
let n="";
for(let i in attr){
if(i.startsWith(ANDROID_PREFIX)){
n = i.substr(ANDROID_PREFIX_LEN);
if(AndroidActivity.androidPrefixed.indexOf(n)==-1)
AndroidActivity.androidPrefixed.push(n);
this.attr[n] = attr[i];
}else{
this.attr[i] = attr[i];
}
}
}
getAttributes(){
return this.attr;
}
getAttribute(name){
return this.attr[name];
}
addIntentFilters(filter){
filter.generateUID(this);
this.intentFilters.push(filter);
}
getIntentFilters(){
return this.intentFilters;
}
countIntentFilter(){
return this.intentFilters.length;
}
getIntentFilterByUid(id){
for(let i=0; i<this.intentFilters.length; i++){
if(this.intentFilters[i].getUid()===id)
return this.intentFilters[i];
}
return null;
}
getLabel(){
return this.label
}
getName(){
return this.name;
}
addTag(tag){
if(this.__tag.indexOf(tag)==-1)
this.__tag.push(tag);
}
getTags(){
return this.__tag;
}
addNodeProperty(name, value){
this.__ppts[name] = value
}
getNodeProperty(name){
return this.__ppts[name];
}
static fromXml(xmlobj){
let act = new AndroidActivity();
for(let j in xmlobj){
switch(j){
case '$':
act.setAttributes(xmlobj.$);
act.label = act.attr.label;
act.name = act.attr.name;
try{
act.generateUID();
}catch(e){
Logger.error("[ACTIVITY] Manifest parsing error : an service has not name");
}
break;
case 'intent-filter':
for(let i=0; i<xmlobj[j].length; i++){
act.addIntentFilters(
IntentFilter.fromXml(xmlobj[j][i])
);
}
break;
}
}
return act;
}
/**
* To serialize to XML
* @returns {String} The activity data ready to be writen into an XML file
* @function
*/
toXmlObject(){
let o = {}
o.$ = {};
for(let i in this.attr){
if(AndroidActivity.androidPrefixed.indexOf(i)>-1)
o.$[ANDROID_PREFIX+i] = this.attr[i];
else
o.$[i] = this.attr[i];
}
o["intent-filter"] = [];
for(let i=0; i<this.intentFilters.length; i++){
o["intent-filter"].push(this.intentFilters[i].toXml());
}
return o;
}
/**
* To serialize to JSON
* @returns {String} The activity data seriualized
* @function
*/
toJsonObject(){
let o = new Object();
o.__id = this.__id;
o.label = this.label;
o.name = this.name;
o.attr = this.attr;
o.intentFilters = [];
this.intentFilters.map(x => o.intentFilters.push(x.toJsonObject()));
if(this.__impl!=null){
o.__impl = this.__impl.signature();
}
if((this.__tag instanceof Array) && this.__tag.length>0){
o.__tag = this.__tag;
}
o.__ppts = this.__ppts;
return o;
}
}
class AndroidService
{
constructor(config=null){
// the manifest data are stored here
this.attr = {};
this.label = null;
this.name = null;
this.intentFilters = [];
this.metadata = null;
this.__id = null;
this.__impl = null;
this.__tag =[];
this.__ppts = {};
// auto config
if(config != null){
for(let i in config)
if(this[i] !== undefined)
this[i] = config[i];
if(this.name != null)
this.generateUID();
}
}
generateUID(){
if(this.name == null) throw new Error("[SERVICE] Unable to generate UID");
this.__id = _md5_(this.name);
}
getUID(){
return this.__id;
}
addTag(tag){
if(this.__tag.indexOf(tag)==-1)
this.__tag.push(tag);
}
getTags(){
return this.__tag;
}
setImplementedBy(cls){
this.__impl = cls;
}
getImplementedBy(){
return this.__impl;
}
setAttributes(attr){
for(let i in attr){
if(i.startsWith('android:')){
this.attr[i.substr(8)] = attr[i];
}else{
this.attr[i] = attr[i];
}
}
}
addIntentFilters(filter){
filter.generateUID(this);
this.intentFilters.push(filter);
}
countIntentFilter(){
return this.intentFilters.length;
}
getIntentFilterByUid(id){
for(let i=0; i<this.intentFilters.length; i++){
if(this.intentFilters[i].getUid()===id)
return this.intentFilters[i];
}
return null;
}
getIntentFilters(){
return this.intentFilters;
}
getAttributes(){
return this.attr;
}
getLabel(){
return this.label
}
getName(){
return this.name;
}
addNodeProperty(name, value){
this.__ppts[name] = value
}
getNodeProperty(name){
return this.__ppts[name];
}
isExported(){
return (this.attr.exported != null) && (this.attr.exported === true);
}
static fromXml(xmlobj){
let act = new AndroidService();
for(let j in xmlobj){
switch(j){
case '$':
act.setAttributes(xmlobj.$);
act.label = act.attr.label;
act.name = act.attr.name;
try{
act.generateUID();
}catch(e){
Logger.error("[SERVICE] Manifest parsing error : an service has not name");
}
break;
case 'intent-filter':
for(let i=0; i<xmlobj[j].length; i++){
act.addIntentFilters(
IntentFilter.fromXml(xmlobj[j][i])
);
}
break;
}
}
return act;
}
toJsonObject(){
let o = new Object();
o.__id = this.__id;
o.label = this.label;
o.name = this.name;
o.attr = this.attr;
o.intentFilters = [];
this.intentFilters.map(x => o.intentFilters.push(x.toJsonObject()));
if(this.__impl!=null){
// o.__impl = this.__impl.toJsonObject();
o.__impl = this.__impl.signature();
}
if((this.__tag instanceof Array) && this.__tag.length>0){
o.__tag = this.__tag;
}
o.__ppts = this.__ppts;
return o;
}
}
class AndroidReceiver
{
constructor(config=null){
// the manifest data are stored here
this.attr = {};
this.label = null;
this.name = null;
this.intentFilters = [];
this.metadata = null;
this.__id = null;
this.__impl = null;
this.__tag = [];
this.__ppts = {};
// auto config
if(config != null){
for(let i in config)
if(this[i] !== undefined)
this[i] = config[i];
if(this.name != null)
this.generateUID();
}
}
generateUID(){
if(this.name == null) throw new Error("[RECEIVER] Unable to generate UID");
this.__id = _md5_(this.name);
}
getUID(){
return this.__id;
}
addTag(tag){
if(this.__tag.indexOf(tag)==-1)
this.__tag.push(tag);
}
getTags(){
return this.__tag;
}
setImplementedBy(cls){
this.__impl = cls;
}
getImplementedBy(){
return this.__impl;
}
setAttributes(attr){
for(let i in attr){
if(i.startsWith('android:')){
this.attr[i.substr(8)] = attr[i];
}else{
this.attr[i] = attr[i];
}
}
}
addIntentFilters(filter){
filter.generateUID(this);
this.intentFilters.push(filter);
}
countIntentFilter(){
return this.intentFilters.length;
}
getIntentFilterByUid(id){
for(let i=0; i<this.intentFilters.length; i++){
if(this.intentFilters[i].getUid()===id)
return this.intentFilters[i];
}
return null;
}
getIntentFilters(){
return this.intentFilters;
}
getAttributes(){
return this.attr;
}
getLabel(){
return this.label
}
getName(){
return this.name;
}
addNodeProperty(name, value){
this.__ppts[name] = value
}
getNodeProperty(name){
return this.__ppts[name];
}
isExported(){
return (this.attr.exported != null) && (this.attr.exported === true);
}
static fromXml(xmlobj){
let act = new AndroidReceiver();
for(let j in xmlobj){
switch(j){
case '$':
act.setAttributes(xmlobj.$);
act.label = act.attr.label;
act.name = act.attr.name;
try{
act.generateUID();
}catch(e){
Logger.error("[RECEIVER] Manifest parsing error : an service has not name");
}
break;
case 'intent-filter':
for(let i=0; i<xmlobj[j].length; i++){
act.addIntentFilters(
IntentFilter.fromXml(xmlobj[j][i])
);
}
break;
}
}
return act;
}
toJsonObject(){
let o = new Object();
o.__id = this.__id;
o.label = this.label;
o.name = this.name;
o.attr = this.attr;
o.intentFilters = [];
this.intentFilters.map(x => o.intentFilters.push(x.toJsonObject()));
if(this.__impl!=null){
// o.__impl = this.__impl.toJsonObject();
o.__impl = this.__impl.signature();
}
if((this.__tag instanceof Array) && this.__tag.length>0){
o.__tag = this.__tag;
}
o.__ppts = this.__ppts;
return o;
}
}
class AndroidProvider
{
constructor(config=null){
// the manifest data are stored here
this.attr = {};
this.label = null;
this.name = null;
this.intentFilters = [];
this.metadata = null;
this.__id = null;
this.__impl = null;
this.__tag = [];
this.__ppts = {};
// auto config
if(config != null){
for(let i in config)
if(this[i] !== undefined)
this[i] = config[i];
if(this.name != null)
this.generateUID();
}
}
generateUID(){
if(this.name == null) throw new Error("[PROVIDER] Unable to generate UID");
this.__id = _md5_(this.name);
}
getUID(){
return this.__id;
}
addTag(tag){
if(this.__tag.indexOf(tag)==-1)
this.__tag.push(tag);
}
getTags(){
return this.__tag;
}
setImplementedBy(cls){
this.__impl = cls;
}
getImplementedBy(){
return this.__impl;
}
setAttributes(attr){
for(let i in attr){
if(i.startsWith('android:')){
this.attr[i.substr(8)] = attr[i];
}else{
this.attr[i] = attr[i];
}
}
}
addIntentFilters(filter){
filter.generateUID(this);
this.intentFilters.push(filter);
}
countIntentFilter(){
return this.intentFilters.length;
}
getIntentFilterByUid(id){
for(let i=0; i<this.intentFilters.length; i++){
if(this.intentFilters[i].getUid()===id)
return this.intentFilters[i];
}
return null;
}
getIntentFilters(){
return this.intentFilters;
}
getAttributes(){
return this.attr;
}
getLabel(){
return this.label
}
getName(){
return this.name;
}
addNodeProperty(name, value){
this.__ppts[name] = value
}
getNodeProperty(name){
return this.__ppts[name];
}
isExported(){
return (this.attr.exported != null) && (this.attr.exported === true);
}
static fromXml(xmlobj){
let act = new AndroidProvider();
for(let j in xmlobj){
switch(j){
case '$':
act.setAttributes(xmlobj.$);
act.label = act.attr.label;
act.name = act.attr.name;
try{
act.generateUID();
}catch(e){
Logger.error("[PROVIDER] Manifest parsing error : an service has not name");
}
break;
case 'intent-filter':
for(let i=0; i<xmlobj[j].length; i++){
act.addIntentFilters(
IntentFilter.fromXml(xmlobj[j][i])
);
}
break;
}
}
return act;
}
toJsonObject(){
let o = new Object();
o.__id = this.__id;
o.label = this.label;
o.name = this.name;
o.attr = this.attr;
o.intentFilters = [];
this.intentFilters.map(x => o.intentFilters.push(x.toJsonObject()));
if(this.__impl!=null){
o.__impl = this.__impl.signature();
// o.__impl = this.__impl.toJsonObject();
}
if((this.__tag instanceof Array) && this.__tag.length>0){
o.__tag = this.__tag;
}
o.__ppts = this.__ppts;
return o;
}
}
class AndroidApplication
{
static MODEL = {
allowTaskReparenting:["true" | "false"],
allowBackup:["true" | "false"],
allowClearUserData:["true" | "false"],
backupAgent:"string",
backupInForeground:["true" | "false"],
banner:"drawable resource",
debuggable:["true" | "false"],
description:"string resource",
directBootAware:["true" | "false"],
enabled:["true" | "false"],
extractNativeLibs:["true" | "false"],
fullBackupContent:"string",
fullBackupOnly:["true" | "false"],
hasCode:["true" | "false"],
hardwareAccelerated:["true" | "false"],
icon:"drawable resource",
isGame:["true" | "false"],
killAfterRestore:["true" | "false"],
largeHeap:["true" | "false"],
label:"string resource",
logo:"drawable resource",
manageSpaceActivity:"string",
name:"string",
networkSecurityConfig:"xml resource",
permission:"string",
persistent:["true" | "false"],
process:"string",
restoreAnyVersion:["true" | "false"],
requiredAccountType:"string",
resizeableActivity:["true" | "false"],
restrictedAccountType:"string",
supportsRtl:["true" | "false"],
taskAffinity:"string",
testOnly:["true" | "false"],
theme:"resource or theme",
uiOptions:["none" | "splitActionBarWhenNarrow"],
usesCleartextTraffic:["true" | "false"],
vmSafeMode:["true" | "false"]
}
constructor(config=null){
this.attr = {};
this.activities = [];
this.activityAliases = [];
this.launcherActivities = [];
this.services = [];
this.receivers = [];
this.providers = [];
this.usesLibraries = [];
this.metaData = [];
if(config!=null)
for(let i in config)
if(this[i] !== undefined)
this[i] = config[i];
}
static fromXml(xmlobj){
let app = new AndroidApplication();
for(let i in xmlobj.$){
if(i.startsWith('android:')){
app.attr[i.substr(8)] = xmlobj.$[i];
}else{
app.attr[i] = xmlobj.$[i];
}
}
for(let j in xmlobj){
switch(j){
case 'activity':
for(let i=0; i<xmlobj.activity.length; i++){
app.activities.push(AndroidActivity.fromXml(xmlobj.activity[i]));
}
break;
case 'service':
for(let i=0; i<xmlobj.service.length; i++){
app.services.push(AndroidService.fromXml(xmlobj.service[i]));
}
break;
case 'receiver':
for(let i=0; i<xmlobj.receiver.length; i++){
app.receivers.push(AndroidReceiver.fromXml(xmlobj.receiver[i]));
}
break;
case 'provider':
for(let i=0; i<xmlobj.provider.length; i++){
app.providers.push(AndroidProvider.fromXml(xmlobj.provider[i]));
}
break;
case 'meta-data':
for(let i=0; i<xmlobj['meta-data'].length; i++){
app.metaData.push(xmlobj['meta-data'][i].$);
}
break;
case 'uses-library':
for(let i=0; i<xmlobj['uses-library'].length; i++){
app.usesLibraries.push(xmlobj['uses-library'][i].$);
}
break;
}
}
return app;
}
}
class AndroidManifest
{
constructor(ctx=null){
this.attributes = {};
this.usesPermissions = [];
this.permissions = [];
this.permissionTrees = [];
this.permissionGroups = [];
this.instrumentation = null;
this.usesPermissionsSdk23 = null;
this.usesSdk = {
'android:minSdkVersion': null,
'android:targetSdkVersion': null,
};
this.usesConfiguration = null;
this.usesFeatures = [];
this.supportsScreens = null;
this.compatibleScreens = [];
this.supportsGlTextures = [];
this.application = null;
this.__context = ctx;
this.__additionalContent = {};
}
static fromXml(config, context){
let self = new AndroidManifest();
// init manifest attributes
for(let i in config){
switch(i){
case '$':
self.setAttributes(config['$']);
break;
case 'uses-sdk':
config['uses-sdk'].map(function(k){
self.usesSdk = k.$;
});
break;
case 'uses-permission':
config['uses-permission'].map(function(k){
self.usesPermissions.push(Permission.fromXml(k.$));
});
break;
case 'permission':
config['permission'].map(function(k){
self.permissions.push(Permission.fromXml(k.$));
});
break;
case 'permission-group':
config['permission-group'].map(function(k){
self.permissionGroups.push(PermissionGroup.fromXml(k.$));
});
break;
case 'permission-tree':
config['permission-tree'].map(function(k){
self.permissionTrees.push(PermissionTree.fromXml(k.$));
});
break;
case 'uses-feature':
config['uses-feature'].map(function(k){
self.usesFeatures.push(AndroidFeature.fromXml(k.$));
});
break;
case 'supports-gl-texture':
config['supports-gl-texture'].map(function(k){
self.supportsGlTextures.push(AndroidGlTexture.fromXml(k.$));
});
break;
case 'compatible-screens':
config['compatible-screens'].map(function(k){
self.compatibleScreens.push(AndroidScreen.fromXml(k.$));
});
break;
case 'supports-screens':
if(self.supportsScreens===null) self.supportsScreens = [];
config['supports-screens'].map(function(k){
self.supportsScreens.push(AndroidSupportedScreen.fromXml(k.$));
});
break;
case 'uses-configuration':
if(self.usesConfiguration===null) self.usesConfiguration = [];
config['uses-configuration'].map(function(k){
self.usesConfiguration.push(AndroidConfiguration.fromXml(k.$));
});
break;
case 'uses-permission-sdk-23':
if(self.usesPermissionsSdk23===null) self.usesPermissionsSdk23 = [];
config['uses-permission-sdk-23'].map(function(k){
self.usesPermissionsSdk23.push(AndroidPermissionSdk23.fromXml(k.$));
});
break;
case 'instrumentation':
if(self.instrumentation===null) self.instrumentation = [];
config['instrumentation'].map(function(k){
self.instrumentation.push(AndroidInstrumentation.fromXml(k.$));
});
break;
case 'application':
if(config[i] instanceof AndroidApplication){
self.application = config[i];
}else{
self.application = AndroidApplication.fromXml(config[i][0]);
context.trigger({
name: "app.application.new",
data: self.application
})
}
break;
default:
self.__additionalContent[i] = config[i];
break;
}
}
//console.log(self.__additionalContent);
return self;
}
toXml(){
let o = new Object();
o.$ = {};
for(let i in this.attributes){
o.$[i] = this.attributes[i];
}
if(this.usesPermissions.length > 0){
o['uses-permission'] = [];
this.usesPermissions.map(perm => {
o['uses-permission'].push(perm.toXml());
});
}
if(this.permissions.length > 0){
o['permission'] = [];
this.permissions.map(perm => {
o['permission'].push(perm.toXml());
});
}
if(this.permissionGroups.length > 0){
o['permission-group'] = [];
this.permissionGroups.map(perm => {
o['permission-group'].push(perm.toXml());
});
}
if(this.permissionTrees.length > 0){
o['permission-tree'] = [];
this.permissionTrees.map(perm => {
o['permission-tree'].push(perm.toXml());
});
}
if(this.instrumentation != null && this.instrumentation.length > 0){
o['instrumentation'] = [];
this.instrumentation.map(perm => {
o['instrumentation'].push(perm.toXml());
});
}
if(this.usesPermissionsSdk23 != null && this.usesPermissionsSdk23.length > 0){
o['uses-permission-sdk-23'] = [];
this.usesPermissionsSdk23.map(perm => {
o['uses-permission-sdk-23'].push(perm.toXml());
});
}
if(this.usesConfiguration != null && this.usesConfiguration.length > 0){
o['uses-configuration'] = [];
this.usesConfiguration.map(perm => {
o['uses-configuration'].push(perm.toXml());
});
}
if(this.usesFeatures != null && this.usesFeatures.length > 0){
o['uses-feature'] = [];
this.usesFeatures.map(perm => {
o['uses-feature'].push(perm.toXml());
});
}
if(this.usesSdk != null && this.usesSdk.length > 0){
o['uses-sdk'] = [];
o['uses-sdk'].push(this.usesSdk);
}
if(this.supportsScreens != null && this.supportsScreens.length > 0){
o['supports-screens'] = [];
this.supportsScreens.map(perm => {
o['supports-screens'].push(perm.toXml());
});
}
if(this.compatibleScreens != null && this.compatibleScreens.length > 0){
o['compatible-screens'] = [];
this.compatibleScreens.map(perm => {
o['compatible-screens'].push(perm.toXml());
});
}
if(this.supportsGlTextures != null && this.supportsGlTextures.length > 0){
o['supports-gl-texture'] = [];
this.supportsGlTextures.map(perm => {
o['supports-gl-texture'].push(perm.toXml());
});
}
if(this.usesFeatures != null && this.usesFeatures.length > 0){
o['uses-feature'] = [];
this.usesFeatures.map(perm => {
o['uses-feature'].push(perm.toXml());
});
}
o.application = this.application.toXml();
if(Object.keys(this.__additionalContent).length > 0){
for(let i in this.__additionalContent){
o[i] = this.__additionalContent[i];
}
}
return o;
}
setAttributes(attrs){
this.attributes = attrs;
}
getAttrVersionCode(){
return this.attributes['android:versionCode'];
}
getAttrVersionName(){
return this.attributes['android:versionName'];
}
getAttrPackage(){
return this.attributes['package'];
}
getAttrPlatformBuildVersionCode(){
return this.attributes['platformBuildVersionCode'];
}
getAttrPlatformBuildVersionName(){
return this.attributes['platformBuildVersionName'];
}
getAttrXmlNS(){
return this.attributes['xmlns:android'];
}
getMinSdkVersion(){
return this.usesSdk['android:minSdkVersion'];
}
getTargetSdkVersion(){
return this.usesSdk['android:targetSdkVersion'];
}
/**
* To get the Application description as declared into the manifest
* @returns {AndroidApplication} The manifest's description of the application
*/
getApplication(){
return this.application;
}
/**
* To get the permissions of the applciaton as declared into the manifest
*
*/
getPermissions(){
return this.permissions;
}
/**
* To check is the application require the given permission
* @param {AndroidPermission | String} perm The permission to search
* @returns {Boolean} Return TRUE if the given permission is required, else FALSE
*/
requirePermission(perm){
let res = false;
if(perm instanceof Permission){
this.usesPermissions.map(function(p){
if(p.getName()===perm.getName())
res = true;
})
}else{
this.usesPermissions.map(function(p){
if(p.getName()===perm)
res = true;
})
}
return res;
}
}
module.exports = {
Activity: AndroidActivity,
Receiver: AndroidReceiver,
Service: AndroidService,
Provider: AndroidProvider,
Application: AndroidApplication,
Manifest: AndroidManifest,
Feature: AndroidFeature,
Permission: Permission,
PermissionGroup: PermissionGroup,
ProtectionLevel: ProtectionLevel,
IntentFilter: IntentFilter,
IntentDataCriteria: IntentDataCriteria,
IntentActionCriteria: IntentActionCriteria,
IntentCategoryCriteria: IntentCategoryCriteria,
};