Fairoj : Clix changes and Master Stored in Offline
3
.gitignore
vendored
@ -8,6 +8,7 @@
|
|||||||
/node_modules
|
/node_modules
|
||||||
/platforms
|
/platforms
|
||||||
/resources
|
/resources
|
||||||
|
/plugins
|
||||||
/www
|
/www
|
||||||
|
|
||||||
# IDEs and editors
|
# IDEs and editors
|
||||||
@ -41,4 +42,4 @@ testem.log
|
|||||||
|
|
||||||
#System Files
|
#System Files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|||||||
0
.sourcemaps/0.js.map
Normal file → Executable file
2
.sourcemaps/1.js.map
Normal file → Executable file
0
.sourcemaps/2.js.map
Normal file → Executable file
0
.sourcemaps/3.js.map
Normal file → Executable file
2
.sourcemaps/main.js.map
Normal file → Executable file
0
.vscode/settings.json
vendored
Normal file → Executable file
@ -1,5 +1,5 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<widget id="com.sineedge.pdgenie" version="0.0.12" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
<widget id="com.sineedge.pdgenie" version="0.0.13" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||||
<name>PD Genie Officer </name>
|
<name>PD Genie Officer </name>
|
||||||
<description>info@pdgenie.com</description>
|
<description>info@pdgenie.com</description>
|
||||||
<author email="info@pdgenie.com" href="https://pdgenie.com">PD Genie</author>
|
<author email="info@pdgenie.com" href="https://pdgenie.com">PD Genie</author>
|
||||||
@ -101,4 +101,5 @@
|
|||||||
<variable name="FCM_VERSION" value="11.6.2" />
|
<variable name="FCM_VERSION" value="11.6.2" />
|
||||||
</plugin>
|
</plugin>
|
||||||
<engine name="browser" spec="5.0.4" />
|
<engine name="browser" spec="5.0.4" />
|
||||||
|
<engine name="android" spec="8.0.0" />
|
||||||
</widget>
|
</widget>
|
||||||
|
|||||||
0
config/webpack.config.js
Normal file → Executable file
0
google-services.json
Normal file → Executable file
3300
package-lock.json
generated
@ -13,7 +13,7 @@
|
|||||||
"serve": "ionic build",
|
"serve": "ionic build",
|
||||||
"start": "npm run serve",
|
"start": "npm run serve",
|
||||||
"prod_build": "ionic cordova build android --aot --minifyjs --minifycss --max-old-space-size=4096",
|
"prod_build": "ionic cordova build android --aot --minifyjs --minifycss --max-old-space-size=4096",
|
||||||
"ionic:build": "node --max-old-space-size=2046 ./node_modules/@ionic/app-scripts/bin/ionic-app-scripts.js build"
|
"ionic:build": "node --max-old-space-size=4096 ./node_modules/@ionic/app-scripts/bin/ionic-app-scripts.js build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^5.1.1",
|
"@angular/animations": "^5.1.1",
|
||||||
@ -80,9 +80,9 @@
|
|||||||
"zone.js": "0.8.18"
|
"zone.js": "0.8.18"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@ionic/app-scripts": "3.1.5",
|
"@ionic/app-scripts": "^3.2.4",
|
||||||
"typescript": "2.4.2",
|
"gulp-sass": "^3.1.0",
|
||||||
"gulp-sass": "^3.1.0"
|
"typescript": "2.4.2"
|
||||||
},
|
},
|
||||||
"description": "An Ionic project",
|
"description": "An Ionic project",
|
||||||
"config": {
|
"config": {
|
||||||
|
|||||||
21
platforms/android/.gitignore
vendored
@ -1,21 +0,0 @@
|
|||||||
# Non-project-specific build files:
|
|
||||||
build.xml
|
|
||||||
local.properties
|
|
||||||
/gradlew
|
|
||||||
/gradlew.bat
|
|
||||||
/gradle
|
|
||||||
# Ant builds
|
|
||||||
ant-build
|
|
||||||
ant-gen
|
|
||||||
# Eclipse builds
|
|
||||||
gen
|
|
||||||
out
|
|
||||||
# Gradle build artifacts
|
|
||||||
.gradle
|
|
||||||
.gradletasknamecache
|
|
||||||
/build
|
|
||||||
/CordovaLib/build
|
|
||||||
/app/build
|
|
||||||
gradle-app.setting
|
|
||||||
# Android Studio
|
|
||||||
.idea
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
#Wed Jul 24 12:54:31 IST 2019
|
|
||||||
gradle.version=4.10.3
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
-->
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="org.apache.cordova" android:versionName="1.0" android:versionCode="1">
|
|
||||||
<uses-sdk android:minSdkVersion="19" />
|
|
||||||
</manifest>
|
|
||||||
@ -1,136 +0,0 @@
|
|||||||
/* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ext {
|
|
||||||
apply from: 'cordova.gradle'
|
|
||||||
cdvCompileSdkVersion = privateHelpers.getProjectTarget()
|
|
||||||
cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
|
|
||||||
}
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
// The gradle plugin and the maven plugin have to be updated after each version of Android
|
|
||||||
// studio comes out
|
|
||||||
classpath 'com.android.tools.build:gradle:3.3.0'
|
|
||||||
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
|
|
||||||
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply plugin: 'com.android.library'
|
|
||||||
apply plugin: 'com.github.dcendents.android-maven'
|
|
||||||
apply plugin: 'com.jfrog.bintray'
|
|
||||||
|
|
||||||
group = 'org.apache.cordova'
|
|
||||||
version = '8.0.0'
|
|
||||||
|
|
||||||
android {
|
|
||||||
compileSdkVersion cdvCompileSdkVersion
|
|
||||||
buildToolsVersion cdvBuildToolsVersion
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
manifest.srcFile 'AndroidManifest.xml'
|
|
||||||
java.srcDirs = ['src']
|
|
||||||
resources.srcDirs = ['src']
|
|
||||||
aidl.srcDirs = ['src']
|
|
||||||
renderscript.srcDirs = ['src']
|
|
||||||
res.srcDirs = ['res']
|
|
||||||
assets.srcDirs = ['assets']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
packagingOptions {
|
|
||||||
exclude 'META-INF/LICENSE'
|
|
||||||
exclude 'META-INF/LICENSE.txt'
|
|
||||||
exclude 'META-INF/DEPENDENCIES'
|
|
||||||
exclude 'META-INF/NOTICE'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
install {
|
|
||||||
repositories.mavenInstaller {
|
|
||||||
pom {
|
|
||||||
project {
|
|
||||||
packaging 'aar'
|
|
||||||
name 'Cordova'
|
|
||||||
url 'https://cordova.apache.org'
|
|
||||||
licenses {
|
|
||||||
license {
|
|
||||||
name 'The Apache Software License, Version 2.0'
|
|
||||||
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
developers {
|
|
||||||
developer {
|
|
||||||
id 'stevengill'
|
|
||||||
name 'Steve Gill'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scm {
|
|
||||||
connection 'scm:git:https://github.com/apache/cordova-android.git'
|
|
||||||
developerConnection 'scm:git:git@github.com:apache/cordova-android.git'
|
|
||||||
url 'https://github.com/apache/cordova-android'
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task sourcesJar(type: Jar) {
|
|
||||||
from android.sourceSets.main.java.srcDirs
|
|
||||||
classifier = 'sources'
|
|
||||||
}
|
|
||||||
|
|
||||||
artifacts {
|
|
||||||
archives sourcesJar
|
|
||||||
}
|
|
||||||
|
|
||||||
bintray {
|
|
||||||
user = System.getenv('BINTRAY_USER')
|
|
||||||
key = System.getenv('BINTRAY_KEY')
|
|
||||||
configurations = ['archives']
|
|
||||||
pkg {
|
|
||||||
repo = 'maven'
|
|
||||||
name = 'cordova-android'
|
|
||||||
userOrg = 'cordova'
|
|
||||||
licenses = ['Apache-2.0']
|
|
||||||
vcsUrl = 'https://github.com/apache/cordova-android'
|
|
||||||
websiteUrl = 'https://cordova.apache.org'
|
|
||||||
issueTrackerUrl = 'https://github.com/apache/cordova-android/issues'
|
|
||||||
publicDownloadNumbers = true
|
|
||||||
licenses = ['Apache-2.0']
|
|
||||||
labels = ['android', 'cordova', 'phonegap']
|
|
||||||
version {
|
|
||||||
name = '8.0.0'
|
|
||||||
released = new Date()
|
|
||||||
vcsTag = '8.0.0'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* Automatically generated file. DO NOT MODIFY
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
public final class BuildConfig {
|
|
||||||
public static final boolean DEBUG = Boolean.parseBoolean("true");
|
|
||||||
public static final String APPLICATION_ID = "org.apache.cordova";
|
|
||||||
public static final String BUILD_TYPE = "debug";
|
|
||||||
public static final String FLAVOR = "";
|
|
||||||
public static final int VERSION_CODE = 1;
|
|
||||||
public static final String VERSION_NAME = "1.0";
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\src\main\jniLibs"/></dataSet><dataSet config="debug" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\src\debug\jniLibs"/></dataSet></merger>
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\src\main\shaders"/></dataSet><dataSet config="debug" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\src\debug\shaders"/></dataSet></merger>
|
|
||||||
@ -1 +0,0 @@
|
|||||||
#Wed Jul 24 12:54:53 IST 2019
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<merger version="3"><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\res"/><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\build\generated\res\rs\debug"/><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\build\generated\res\resValues\debug"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main" generated-set="main$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\res"/><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\build\generated\res\rs\debug"/><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\build\generated\res\resValues\debug"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="debug$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\src\debug\res"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="debug" generated-set="debug$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="S:\pd_office\pd_officer_change\platforms\android\CordovaLib\src\debug\res"/></dataSet><mergedItems/></merger>
|
|
||||||
@ -1 +0,0 @@
|
|||||||
org.apache.cordova
|
|
||||||
@ -1 +0,0 @@
|
|||||||
[{"name":"resources","index":0,"scopes":["PROJECT"],"types":["NATIVE_LIBS"],"format":"DIRECTORY","present":false}]
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
-- Merging decision tree log ---
|
|
||||||
manifest
|
|
||||||
ADDED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:20:1-23:12
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:20:1-23:12
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:20:1-23:12
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:20:1-23:12
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:20:1-23:12
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:20:1-23:12
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:20:1-23:12
|
|
||||||
package
|
|
||||||
ADDED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:21:7-35
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml
|
|
||||||
android:versionName
|
|
||||||
ADDED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:21:36-61
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml
|
|
||||||
xmlns:android
|
|
||||||
ADDED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:20:11-69
|
|
||||||
android:versionCode
|
|
||||||
ADDED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:21:62-85
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml
|
|
||||||
INJECTED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml
|
|
||||||
uses-sdk
|
|
||||||
ADDED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:22:5-44
|
|
||||||
android:minSdkVersion
|
|
||||||
ADDED from S:\pd_office\pd_officer_change\platforms\android\CordovaLib\AndroidManifest.xml:22:15-41
|
|
||||||
@ -1,205 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import java.util.regex.Pattern
|
|
||||||
import groovy.swing.SwingBuilder
|
|
||||||
|
|
||||||
String doEnsureValueExists(filePath, props, key) {
|
|
||||||
if (props.get(key) == null) {
|
|
||||||
throw new GradleException(filePath + ': Missing key required "' + key + '"')
|
|
||||||
}
|
|
||||||
return props.get(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
String doGetProjectTarget() {
|
|
||||||
def props = new Properties()
|
|
||||||
def propertiesFile = 'project.properties';
|
|
||||||
if(!(file(propertiesFile).exists())) {
|
|
||||||
propertiesFile = '../project.properties';
|
|
||||||
}
|
|
||||||
file(propertiesFile).withReader { reader ->
|
|
||||||
props.load(reader)
|
|
||||||
}
|
|
||||||
return doEnsureValueExists('project.properties', props, 'target')
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] getAvailableBuildTools() {
|
|
||||||
def buildToolsDir = new File(getAndroidSdkDir(), "build-tools")
|
|
||||||
buildToolsDir.list()
|
|
||||||
.findAll { it ==~ /[0-9.]+/ }
|
|
||||||
.sort { a, b -> compareVersions(b, a) }
|
|
||||||
}
|
|
||||||
|
|
||||||
String doFindLatestInstalledBuildTools(String minBuildToolsVersion) {
|
|
||||||
def availableBuildToolsVersions
|
|
||||||
try {
|
|
||||||
availableBuildToolsVersions = getAvailableBuildTools()
|
|
||||||
} catch (e) {
|
|
||||||
println "An exception occurred while trying to find the Android build tools."
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
if (availableBuildToolsVersions.length > 0) {
|
|
||||||
def highestBuildToolsVersion = availableBuildToolsVersions[0]
|
|
||||||
if (compareVersions(highestBuildToolsVersion, minBuildToolsVersion) < 0) {
|
|
||||||
throw new RuntimeException(
|
|
||||||
"No usable Android build tools found. Highest installed version is " +
|
|
||||||
highestBuildToolsVersion + "; minimum version required is " +
|
|
||||||
minBuildToolsVersion + ".")
|
|
||||||
}
|
|
||||||
highestBuildToolsVersion
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException(
|
|
||||||
"No installed build tools found. Install the Android build tools version " +
|
|
||||||
minBuildToolsVersion + " or higher.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the first non-zero result of subtracting version list elements
|
|
||||||
// pairwise. If they are all identical, return the difference in length of
|
|
||||||
// the two lists.
|
|
||||||
int compareVersionList(Collection aParts, Collection bParts) {
|
|
||||||
def pairs = ([aParts, bParts]).transpose()
|
|
||||||
pairs.findResult(aParts.size()-bParts.size()) {it[0] - it[1] != 0 ? it[0] - it[1] : null}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare two version strings, such as "19.0.0" and "18.1.1.0". If all matched
|
|
||||||
// elements are identical, the longer version is the largest by this method.
|
|
||||||
// Examples:
|
|
||||||
// "19.0.0" > "19"
|
|
||||||
// "19.0.1" > "19.0.0"
|
|
||||||
// "19.1.0" > "19.0.1"
|
|
||||||
// "19" > "18.999.999"
|
|
||||||
int compareVersions(String a, String b) {
|
|
||||||
def aParts = a.tokenize('.').collect {it.toInteger()}
|
|
||||||
def bParts = b.tokenize('.').collect {it.toInteger()}
|
|
||||||
compareVersionList(aParts, bParts)
|
|
||||||
}
|
|
||||||
|
|
||||||
String getAndroidSdkDir() {
|
|
||||||
def rootDir = project.rootDir
|
|
||||||
def androidSdkDir = null
|
|
||||||
String envVar = System.getenv("ANDROID_HOME")
|
|
||||||
def localProperties = new File(rootDir, 'local.properties')
|
|
||||||
String systemProperty = System.getProperty("android.home")
|
|
||||||
if (envVar != null) {
|
|
||||||
androidSdkDir = envVar
|
|
||||||
} else if (localProperties.exists()) {
|
|
||||||
Properties properties = new Properties()
|
|
||||||
localProperties.withInputStream { instr ->
|
|
||||||
properties.load(instr)
|
|
||||||
}
|
|
||||||
def sdkDirProp = properties.getProperty('sdk.dir')
|
|
||||||
if (sdkDirProp != null) {
|
|
||||||
androidSdkDir = sdkDirProp
|
|
||||||
} else {
|
|
||||||
sdkDirProp = properties.getProperty('android.dir')
|
|
||||||
if (sdkDirProp != null) {
|
|
||||||
androidSdkDir = (new File(rootDir, sdkDirProp)).getAbsolutePath()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (androidSdkDir == null && systemProperty != null) {
|
|
||||||
androidSdkDir = systemProperty
|
|
||||||
}
|
|
||||||
if (androidSdkDir == null) {
|
|
||||||
throw new RuntimeException(
|
|
||||||
"Unable to determine Android SDK directory.")
|
|
||||||
}
|
|
||||||
androidSdkDir
|
|
||||||
}
|
|
||||||
|
|
||||||
def doExtractIntFromManifest(name) {
|
|
||||||
def manifestFile = file(android.sourceSets.main.manifest.srcFile)
|
|
||||||
def pattern = Pattern.compile(name + "=\"(\\d+)\"")
|
|
||||||
def matcher = pattern.matcher(manifestFile.getText())
|
|
||||||
matcher.find()
|
|
||||||
return new BigInteger(matcher.group(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
def doExtractStringFromManifest(name) {
|
|
||||||
def manifestFile = file(android.sourceSets.main.manifest.srcFile)
|
|
||||||
def pattern = Pattern.compile(name + "=\"(\\S+)\"")
|
|
||||||
def matcher = pattern.matcher(manifestFile.getText())
|
|
||||||
matcher.find()
|
|
||||||
return matcher.group(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
def doPromptForPassword(msg) {
|
|
||||||
if (System.console() == null) {
|
|
||||||
def ret = null
|
|
||||||
new SwingBuilder().edt {
|
|
||||||
dialog(modal: true, title: 'Enter password', alwaysOnTop: true, resizable: false, locationRelativeTo: null, pack: true, show: true) {
|
|
||||||
vbox {
|
|
||||||
label(text: msg)
|
|
||||||
def input = passwordField()
|
|
||||||
button(defaultButton: true, text: 'OK', actionPerformed: {
|
|
||||||
ret = input.password;
|
|
||||||
dispose();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!ret) {
|
|
||||||
throw new GradleException('User canceled build')
|
|
||||||
}
|
|
||||||
return new String(ret)
|
|
||||||
} else {
|
|
||||||
return System.console().readPassword('\n' + msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def doGetConfigXml() {
|
|
||||||
def xml = file("src/main/res/xml/config.xml").getText()
|
|
||||||
// Disable namespace awareness since Cordova doesn't use them properly
|
|
||||||
return new XmlParser(false, false).parseText(xml)
|
|
||||||
}
|
|
||||||
|
|
||||||
def doGetConfigPreference(name, defaultValue) {
|
|
||||||
name = name.toLowerCase()
|
|
||||||
def root = doGetConfigXml()
|
|
||||||
|
|
||||||
def ret = defaultValue
|
|
||||||
root.preference.each { it ->
|
|
||||||
def attrName = it.attribute("name")
|
|
||||||
if (attrName && attrName.toLowerCase() == name) {
|
|
||||||
ret = it.attribute("value")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// Properties exported here are visible to all plugins.
|
|
||||||
ext {
|
|
||||||
// These helpers are shared, but are not guaranteed to be stable / unchanged.
|
|
||||||
privateHelpers = {}
|
|
||||||
privateHelpers.getProjectTarget = { doGetProjectTarget() }
|
|
||||||
privateHelpers.findLatestInstalledBuildTools = { doFindLatestInstalledBuildTools('19.1.0') }
|
|
||||||
privateHelpers.extractIntFromManifest = { name -> doExtractIntFromManifest(name) }
|
|
||||||
privateHelpers.extractStringFromManifest = { name -> doExtractStringFromManifest(name) }
|
|
||||||
privateHelpers.promptForPassword = { msg -> doPromptForPassword(msg) }
|
|
||||||
privateHelpers.ensureValueExists = { filePath, props, key -> doEnsureValueExists(filePath, props, key) }
|
|
||||||
|
|
||||||
// These helpers can be used by plugins / projects and will not change.
|
|
||||||
cdvHelpers = {}
|
|
||||||
// Returns a XmlParser for the config.xml. Added in 4.1.0.
|
|
||||||
cdvHelpers.getConfigXml = { doGetConfigXml() }
|
|
||||||
// Returns the value for the desired <preference>. Added in 4.1.0.
|
|
||||||
cdvHelpers.getConfigPreference = { name, defaultValue -> doGetConfigPreference(name, defaultValue) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
# This file was originally created by the Android Tools, but is now
|
|
||||||
# used by cordova-android to manage the project configuration.
|
|
||||||
|
|
||||||
# Indicates whether an apk should be generated for each density.
|
|
||||||
split.density=false
|
|
||||||
|
|
||||||
# Project target.
|
|
||||||
target=android-28
|
|
||||||
apk-configurations=
|
|
||||||
renderscript.opt.level=O0
|
|
||||||
android.library=true
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Class AuthenticationToken defines the userName and password to be used for authenticating a web resource
|
|
||||||
*/
|
|
||||||
public class AuthenticationToken {
|
|
||||||
private String userName;
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the user name.
|
|
||||||
*
|
|
||||||
* @return the user name
|
|
||||||
*/
|
|
||||||
public String getUserName() {
|
|
||||||
return userName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the user name.
|
|
||||||
*
|
|
||||||
* @param userName
|
|
||||||
* the new user name
|
|
||||||
*/
|
|
||||||
public void setUserName(String userName) {
|
|
||||||
this.userName = userName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the password.
|
|
||||||
*
|
|
||||||
* @return the password
|
|
||||||
*/
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the password.
|
|
||||||
*
|
|
||||||
* @param password
|
|
||||||
* the new password
|
|
||||||
*/
|
|
||||||
public void setPassword(String password) {
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a utility class that allows us to get the BuildConfig variable, which is required
|
|
||||||
* for the use of different providers. This is not guaranteed to work, and it's better for this
|
|
||||||
* to be set in the build step in config.xml
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
|
|
||||||
|
|
||||||
public class BuildHelper {
|
|
||||||
|
|
||||||
|
|
||||||
private static String TAG="BuildHelper";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This needs to be implemented if you wish to use the Camera Plugin or other plugins
|
|
||||||
* that read the Build Configuration.
|
|
||||||
*
|
|
||||||
* Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to
|
|
||||||
* StackOverflow. This is annoying as hell! However, this method does not work with
|
|
||||||
* ProGuard, and you should use the config.xml to define the application_id
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static Object getBuildConfigValue(Context ctx, String key)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Class<?> clazz = Class.forName(ctx.getPackageName() + ".BuildConfig");
|
|
||||||
Field field = clazz.getField(key);
|
|
||||||
return field.get(null);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
LOG.d(TAG, "Unable to get the BuildConfig, is this built with ANT?");
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (NoSuchFieldException e) {
|
|
||||||
LOG.d(TAG, key + " is not a valid field. Check your build.gradle");
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
LOG.d(TAG, "Illegal Access Exception: Let's print a stack trace.");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
|
|
||||||
import org.apache.cordova.CordovaWebView;
|
|
||||||
import org.apache.cordova.PluginResult;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
public class CallbackContext {
|
|
||||||
private static final String LOG_TAG = "CordovaPlugin";
|
|
||||||
|
|
||||||
private String callbackId;
|
|
||||||
private CordovaWebView webView;
|
|
||||||
protected boolean finished;
|
|
||||||
private int changingThreads;
|
|
||||||
|
|
||||||
public CallbackContext(String callbackId, CordovaWebView webView) {
|
|
||||||
this.callbackId = callbackId;
|
|
||||||
this.webView = webView;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFinished() {
|
|
||||||
return finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isChangingThreads() {
|
|
||||||
return changingThreads > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCallbackId() {
|
|
||||||
return callbackId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendPluginResult(PluginResult pluginResult) {
|
|
||||||
synchronized (this) {
|
|
||||||
if (finished) {
|
|
||||||
LOG.w(LOG_TAG, "Attempted to send a second callback for ID: " + callbackId + "\nResult was: " + pluginResult.getMessage());
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
finished = !pluginResult.getKeepCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
webView.sendPluginResult(pluginResult, callbackId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for success callbacks that just returns the Status.OK by default
|
|
||||||
*
|
|
||||||
* @param message The message to add to the success result.
|
|
||||||
*/
|
|
||||||
public void success(JSONObject message) {
|
|
||||||
sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for success callbacks that just returns the Status.OK by default
|
|
||||||
*
|
|
||||||
* @param message The message to add to the success result.
|
|
||||||
*/
|
|
||||||
public void success(String message) {
|
|
||||||
sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for success callbacks that just returns the Status.OK by default
|
|
||||||
*
|
|
||||||
* @param message The message to add to the success result.
|
|
||||||
*/
|
|
||||||
public void success(JSONArray message) {
|
|
||||||
sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for success callbacks that just returns the Status.OK by default
|
|
||||||
*
|
|
||||||
* @param message The message to add to the success result.
|
|
||||||
*/
|
|
||||||
public void success(byte[] message) {
|
|
||||||
sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for success callbacks that just returns the Status.OK by default
|
|
||||||
*
|
|
||||||
* @param message The message to add to the success result.
|
|
||||||
*/
|
|
||||||
public void success(int message) {
|
|
||||||
sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for success callbacks that just returns the Status.OK by default
|
|
||||||
*/
|
|
||||||
public void success() {
|
|
||||||
sendPluginResult(new PluginResult(PluginResult.Status.OK));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for error callbacks that just returns the Status.ERROR by default
|
|
||||||
*
|
|
||||||
* @param message The message to add to the error result.
|
|
||||||
*/
|
|
||||||
public void error(JSONObject message) {
|
|
||||||
sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for error callbacks that just returns the Status.ERROR by default
|
|
||||||
*
|
|
||||||
* @param message The message to add to the error result.
|
|
||||||
*/
|
|
||||||
public void error(String message) {
|
|
||||||
sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for error callbacks that just returns the Status.ERROR by default
|
|
||||||
*
|
|
||||||
* @param message The message to add to the error result.
|
|
||||||
*/
|
|
||||||
public void error(int message) {
|
|
||||||
sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import android.util.Pair;
|
|
||||||
import android.util.SparseArray;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a collection that maps unique request codes to CordovaPlugins and Integers.
|
|
||||||
* Used to ensure that when plugins make requests for runtime permissions, those requests do not
|
|
||||||
* collide with requests from other plugins that use the same request code value.
|
|
||||||
*/
|
|
||||||
public class CallbackMap {
|
|
||||||
private int currentCallbackId = 0;
|
|
||||||
private SparseArray<Pair<CordovaPlugin, Integer>> callbacks;
|
|
||||||
|
|
||||||
public CallbackMap() {
|
|
||||||
this.callbacks = new SparseArray<Pair<CordovaPlugin, Integer>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores a CordovaPlugin and request code and returns a new unique request code to use
|
|
||||||
* in a permission request.
|
|
||||||
*
|
|
||||||
* @param receiver The plugin that is making the request
|
|
||||||
* @param requestCode The original request code used by the plugin
|
|
||||||
* @return A unique request code that can be used to retrieve this callback
|
|
||||||
* with getAndRemoveCallback()
|
|
||||||
*/
|
|
||||||
public synchronized int registerCallback(CordovaPlugin receiver, int requestCode) {
|
|
||||||
int mappedId = this.currentCallbackId++;
|
|
||||||
callbacks.put(mappedId, new Pair<CordovaPlugin, Integer>(receiver, requestCode));
|
|
||||||
return mappedId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves and removes a callback stored in the map using the mapped request code
|
|
||||||
* obtained from registerCallback()
|
|
||||||
*
|
|
||||||
* @param mappedId The request code obtained from registerCallback()
|
|
||||||
* @return The CordovaPlugin and orignal request code that correspond to the
|
|
||||||
* given mappedCode
|
|
||||||
*/
|
|
||||||
public synchronized Pair<CordovaPlugin, Integer> getAndRemoveCallback(int mappedId) {
|
|
||||||
Pair<CordovaPlugin, Integer> callback = callbacks.get(mappedId);
|
|
||||||
callbacks.remove(mappedId);
|
|
||||||
return callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
|
|
||||||
@Deprecated // Use Whitelist, CordovaPrefences, etc. directly.
|
|
||||||
public class Config {
|
|
||||||
private static final String TAG = "Config";
|
|
||||||
|
|
||||||
static ConfigXmlParser parser;
|
|
||||||
|
|
||||||
private Config() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void init(Activity action) {
|
|
||||||
parser = new ConfigXmlParser();
|
|
||||||
parser.parse(action);
|
|
||||||
//TODO: Add feature to bring this back. Some preferences should be overridden by intents, but not all
|
|
||||||
parser.getPreferences().setPreferencesBundle(action.getIntent().getExtras());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intended to be used for testing only; creates an empty configuration.
|
|
||||||
public static void init() {
|
|
||||||
if (parser == null) {
|
|
||||||
parser = new ConfigXmlParser();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getStartUrl() {
|
|
||||||
if (parser == null) {
|
|
||||||
return "file:///android_asset/www/index.html";
|
|
||||||
}
|
|
||||||
return parser.getLaunchUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getErrorUrl() {
|
|
||||||
return parser.getPreferences().getString("errorurl", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<PluginEntry> getPluginEntries() {
|
|
||||||
return parser.getPluginEntries();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CordovaPreferences getPreferences() {
|
|
||||||
return parser.getPreferences();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isInitialized() {
|
|
||||||
return parser != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
public class ConfigXmlParser {
|
|
||||||
private static String TAG = "ConfigXmlParser";
|
|
||||||
|
|
||||||
private String launchUrl = "file:///android_asset/www/index.html";
|
|
||||||
private CordovaPreferences prefs = new CordovaPreferences();
|
|
||||||
private ArrayList<PluginEntry> pluginEntries = new ArrayList<PluginEntry>(20);
|
|
||||||
|
|
||||||
public CordovaPreferences getPreferences() {
|
|
||||||
return prefs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<PluginEntry> getPluginEntries() {
|
|
||||||
return pluginEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLaunchUrl() {
|
|
||||||
return launchUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void parse(Context action) {
|
|
||||||
// First checking the class namespace for config.xml
|
|
||||||
int id = action.getResources().getIdentifier("config", "xml", action.getClass().getPackage().getName());
|
|
||||||
if (id == 0) {
|
|
||||||
// If we couldn't find config.xml there, we'll look in the namespace from AndroidManifest.xml
|
|
||||||
id = action.getResources().getIdentifier("config", "xml", action.getPackageName());
|
|
||||||
if (id == 0) {
|
|
||||||
LOG.e(TAG, "res/xml/config.xml is missing!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parse(action.getResources().getXml(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean insideFeature = false;
|
|
||||||
String service = "", pluginClass = "", paramType = "";
|
|
||||||
boolean onload = false;
|
|
||||||
|
|
||||||
public void parse(XmlPullParser xml) {
|
|
||||||
int eventType = -1;
|
|
||||||
|
|
||||||
while (eventType != XmlPullParser.END_DOCUMENT) {
|
|
||||||
if (eventType == XmlPullParser.START_TAG) {
|
|
||||||
handleStartTag(xml);
|
|
||||||
}
|
|
||||||
else if (eventType == XmlPullParser.END_TAG)
|
|
||||||
{
|
|
||||||
handleEndTag(xml);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
eventType = xml.next();
|
|
||||||
} catch (XmlPullParserException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleStartTag(XmlPullParser xml) {
|
|
||||||
String strNode = xml.getName();
|
|
||||||
if (strNode.equals("feature")) {
|
|
||||||
//Check for supported feature sets aka. plugins (Accelerometer, Geolocation, etc)
|
|
||||||
//Set the bit for reading params
|
|
||||||
insideFeature = true;
|
|
||||||
service = xml.getAttributeValue(null, "name");
|
|
||||||
}
|
|
||||||
else if (insideFeature && strNode.equals("param")) {
|
|
||||||
paramType = xml.getAttributeValue(null, "name");
|
|
||||||
if (paramType.equals("service")) // check if it is using the older service param
|
|
||||||
service = xml.getAttributeValue(null, "value");
|
|
||||||
else if (paramType.equals("package") || paramType.equals("android-package"))
|
|
||||||
pluginClass = xml.getAttributeValue(null,"value");
|
|
||||||
else if (paramType.equals("onload"))
|
|
||||||
onload = "true".equals(xml.getAttributeValue(null, "value"));
|
|
||||||
}
|
|
||||||
else if (strNode.equals("preference")) {
|
|
||||||
String name = xml.getAttributeValue(null, "name").toLowerCase(Locale.ENGLISH);
|
|
||||||
String value = xml.getAttributeValue(null, "value");
|
|
||||||
prefs.set(name, value);
|
|
||||||
}
|
|
||||||
else if (strNode.equals("content")) {
|
|
||||||
String src = xml.getAttributeValue(null, "src");
|
|
||||||
if (src != null) {
|
|
||||||
setStartUrl(src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleEndTag(XmlPullParser xml) {
|
|
||||||
String strNode = xml.getName();
|
|
||||||
if (strNode.equals("feature")) {
|
|
||||||
pluginEntries.add(new PluginEntry(service, pluginClass, onload));
|
|
||||||
|
|
||||||
service = "";
|
|
||||||
pluginClass = "";
|
|
||||||
insideFeature = false;
|
|
||||||
onload = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setStartUrl(String src) {
|
|
||||||
Pattern schemeRegex = Pattern.compile("^[a-z-]+://");
|
|
||||||
Matcher matcher = schemeRegex.matcher(src);
|
|
||||||
if (matcher.find()) {
|
|
||||||
launchUrl = src;
|
|
||||||
} else {
|
|
||||||
if (src.charAt(0) == '/') {
|
|
||||||
src = src.substring(1);
|
|
||||||
}
|
|
||||||
launchUrl = "file:///android_asset/www/" + src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,519 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.media.AudioManager;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.webkit.WebViewClient;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is the main Android activity that represents the Cordova
|
|
||||||
* application. It should be extended by the user to load the specific
|
|
||||||
* html file that contains the application.
|
|
||||||
*
|
|
||||||
* As an example:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* package org.apache.cordova.examples;
|
|
||||||
*
|
|
||||||
* import android.os.Bundle;
|
|
||||||
* import org.apache.cordova.*;
|
|
||||||
*
|
|
||||||
* public class Example extends CordovaActivity {
|
|
||||||
* @Override
|
|
||||||
* public void onCreate(Bundle savedInstanceState) {
|
|
||||||
* super.onCreate(savedInstanceState);
|
|
||||||
* super.init();
|
|
||||||
* // Load your application
|
|
||||||
* loadUrl(launchUrl);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* Cordova xml configuration: Cordova uses a configuration file at
|
|
||||||
* res/xml/config.xml to specify its settings. See "The config.xml File"
|
|
||||||
* guide in cordova-docs at http://cordova.apache.org/docs for the documentation
|
|
||||||
* for the configuration. The use of the set*Property() methods is
|
|
||||||
* deprecated in favor of the config.xml file.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class CordovaActivity extends Activity {
|
|
||||||
public static String TAG = "CordovaActivity";
|
|
||||||
|
|
||||||
// The webview for our app
|
|
||||||
protected CordovaWebView appView;
|
|
||||||
|
|
||||||
private static int ACTIVITY_STARTING = 0;
|
|
||||||
private static int ACTIVITY_RUNNING = 1;
|
|
||||||
private static int ACTIVITY_EXITING = 2;
|
|
||||||
|
|
||||||
// Keep app running when pause is received. (default = true)
|
|
||||||
// If true, then the JavaScript and native code continue to run in the background
|
|
||||||
// when another application (activity) is started.
|
|
||||||
protected boolean keepRunning = true;
|
|
||||||
|
|
||||||
// Flag to keep immersive mode if set to fullscreen
|
|
||||||
protected boolean immersiveMode;
|
|
||||||
|
|
||||||
// Read from config.xml:
|
|
||||||
protected CordovaPreferences preferences;
|
|
||||||
protected String launchUrl;
|
|
||||||
protected ArrayList<PluginEntry> pluginEntries;
|
|
||||||
protected CordovaInterfaceImpl cordovaInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity is first created.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
// need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception
|
|
||||||
loadConfig();
|
|
||||||
|
|
||||||
String logLevel = preferences.getString("loglevel", "ERROR");
|
|
||||||
LOG.setLogLevel(logLevel);
|
|
||||||
|
|
||||||
LOG.i(TAG, "Apache Cordova native platform version " + CordovaWebView.CORDOVA_VERSION + " is starting");
|
|
||||||
LOG.d(TAG, "CordovaActivity.onCreate()");
|
|
||||||
|
|
||||||
if (!preferences.getBoolean("ShowTitle", false)) {
|
|
||||||
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preferences.getBoolean("SetFullscreen", false)) {
|
|
||||||
LOG.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version.");
|
|
||||||
preferences.set("Fullscreen", true);
|
|
||||||
}
|
|
||||||
if (preferences.getBoolean("Fullscreen", false)) {
|
|
||||||
// NOTE: use the FullscreenNotImmersive configuration key to set the activity in a REAL full screen
|
|
||||||
// (as was the case in previous cordova versions)
|
|
||||||
if (!preferences.getBoolean("FullscreenNotImmersive", false)) {
|
|
||||||
immersiveMode = true;
|
|
||||||
} else {
|
|
||||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
|
||||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
|
|
||||||
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
cordovaInterface = makeCordovaInterface();
|
|
||||||
if (savedInstanceState != null) {
|
|
||||||
cordovaInterface.restoreInstanceState(savedInstanceState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void init() {
|
|
||||||
appView = makeWebView();
|
|
||||||
createViews();
|
|
||||||
if (!appView.isInitialized()) {
|
|
||||||
appView.init(cordovaInterface, pluginEntries, preferences);
|
|
||||||
}
|
|
||||||
cordovaInterface.onCordovaInit(appView.getPluginManager());
|
|
||||||
|
|
||||||
// Wire the hardware volume controls to control media if desired.
|
|
||||||
String volumePref = preferences.getString("DefaultVolumeStream", "");
|
|
||||||
if ("media".equals(volumePref.toLowerCase(Locale.ENGLISH))) {
|
|
||||||
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
protected void loadConfig() {
|
|
||||||
ConfigXmlParser parser = new ConfigXmlParser();
|
|
||||||
parser.parse(this);
|
|
||||||
preferences = parser.getPreferences();
|
|
||||||
preferences.setPreferencesBundle(getIntent().getExtras());
|
|
||||||
launchUrl = parser.getLaunchUrl();
|
|
||||||
pluginEntries = parser.getPluginEntries();
|
|
||||||
Config.parser = parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Suppressing warnings in AndroidStudio
|
|
||||||
@SuppressWarnings({"deprecation", "ResourceType"})
|
|
||||||
protected void createViews() {
|
|
||||||
//Why are we setting a constant as the ID? This should be investigated
|
|
||||||
appView.getView().setId(100);
|
|
||||||
appView.getView().setLayoutParams(new FrameLayout.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
|
||||||
|
|
||||||
setContentView(appView.getView());
|
|
||||||
|
|
||||||
if (preferences.contains("BackgroundColor")) {
|
|
||||||
try {
|
|
||||||
int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK);
|
|
||||||
// Background of activity:
|
|
||||||
appView.getView().setBackgroundColor(backgroundColor);
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e){
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
appView.getView().requestFocusFromTouch();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct the default web view object.
|
|
||||||
* <p/>
|
|
||||||
* Override this to customize the webview that is used.
|
|
||||||
*/
|
|
||||||
protected CordovaWebView makeWebView() {
|
|
||||||
return new CordovaWebViewImpl(makeWebViewEngine());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected CordovaWebViewEngine makeWebViewEngine() {
|
|
||||||
return CordovaWebViewImpl.createEngine(this, preferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected CordovaInterfaceImpl makeCordovaInterface() {
|
|
||||||
return new CordovaInterfaceImpl(this) {
|
|
||||||
@Override
|
|
||||||
public Object onMessage(String id, Object data) {
|
|
||||||
// Plumb this to CordovaActivity.onMessage for backwards compatibility
|
|
||||||
return CordovaActivity.this.onMessage(id, data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the url into the webview.
|
|
||||||
*/
|
|
||||||
public void loadUrl(String url) {
|
|
||||||
if (appView == null) {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If keepRunning
|
|
||||||
this.keepRunning = preferences.getBoolean("KeepRunning", true);
|
|
||||||
|
|
||||||
appView.loadUrlIntoView(url, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the system is about to start resuming a previous activity.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
LOG.d(TAG, "Paused the activity.");
|
|
||||||
|
|
||||||
if (this.appView != null) {
|
|
||||||
// CB-9382 If there is an activity that started for result and main activity is waiting for callback
|
|
||||||
// result, we shoudn't stop WebView Javascript timers, as activity for result might be using them
|
|
||||||
boolean keepRunning = this.keepRunning || this.cordovaInterface.activityResultCallback != null;
|
|
||||||
this.appView.handlePause(keepRunning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity receives a new intent
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onNewIntent(Intent intent) {
|
|
||||||
super.onNewIntent(intent);
|
|
||||||
//Forward to plugins
|
|
||||||
if (this.appView != null)
|
|
||||||
this.appView.onNewIntent(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity will start interacting with the user.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
LOG.d(TAG, "Resumed the activity.");
|
|
||||||
|
|
||||||
if (this.appView == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Force window to have focus, so application always
|
|
||||||
// receive user input. Workaround for some devices (Samsung Galaxy Note 3 at least)
|
|
||||||
this.getWindow().getDecorView().requestFocus();
|
|
||||||
|
|
||||||
this.appView.handleResume(this.keepRunning);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity is no longer visible to the user.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onStop() {
|
|
||||||
super.onStop();
|
|
||||||
LOG.d(TAG, "Stopped the activity.");
|
|
||||||
|
|
||||||
if (this.appView == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.appView.handleStop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity is becoming visible to the user.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
LOG.d(TAG, "Started the activity.");
|
|
||||||
|
|
||||||
if (this.appView == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.appView.handleStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The final call you receive before your activity is destroyed.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
LOG.d(TAG, "CordovaActivity.onDestroy()");
|
|
||||||
super.onDestroy();
|
|
||||||
|
|
||||||
if (this.appView != null) {
|
|
||||||
appView.handleDestroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when view focus is changed
|
|
||||||
*/
|
|
||||||
@SuppressLint("InlinedApi")
|
|
||||||
@Override
|
|
||||||
public void onWindowFocusChanged(boolean hasFocus) {
|
|
||||||
super.onWindowFocusChanged(hasFocus);
|
|
||||||
if (hasFocus && immersiveMode) {
|
|
||||||
final int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
|
||||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
||||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
|
||||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
|
||||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
|
||||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
|
||||||
|
|
||||||
getWindow().getDecorView().setSystemUiVisibility(uiOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
|
||||||
@Override
|
|
||||||
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
|
|
||||||
// Capture requestCode here so that it is captured in the setActivityResultCallback() case.
|
|
||||||
cordovaInterface.setActivityResultRequestCode(requestCode);
|
|
||||||
super.startActivityForResult(intent, requestCode, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when an activity you launched exits, giving you the requestCode you started it with,
|
|
||||||
* the resultCode it returned, and any additional data from it.
|
|
||||||
*
|
|
||||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
|
||||||
* allowing you to identify who this result came from.
|
|
||||||
* @param resultCode The integer result code returned by the child activity through its setResult().
|
|
||||||
* @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
|
||||||
LOG.d(TAG, "Incoming Result. Request code = " + requestCode);
|
|
||||||
super.onActivityResult(requestCode, resultCode, intent);
|
|
||||||
cordovaInterface.onActivityResult(requestCode, resultCode, intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).
|
|
||||||
* The errorCode parameter corresponds to one of the ERROR_* constants.
|
|
||||||
*
|
|
||||||
* @param errorCode The error code corresponding to an ERROR_* value.
|
|
||||||
* @param description A String describing the error.
|
|
||||||
* @param failingUrl The url that failed to load.
|
|
||||||
*/
|
|
||||||
public void onReceivedError(final int errorCode, final String description, final String failingUrl) {
|
|
||||||
final CordovaActivity me = this;
|
|
||||||
|
|
||||||
// If errorUrl specified, then load it
|
|
||||||
final String errorUrl = preferences.getString("errorUrl", null);
|
|
||||||
if ((errorUrl != null) && (!failingUrl.equals(errorUrl)) && (appView != null)) {
|
|
||||||
// Load URL on UI thread
|
|
||||||
me.runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
me.appView.showWebPage(errorUrl, false, true, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// If not, then display error dialog
|
|
||||||
else {
|
|
||||||
final boolean exit = !(errorCode == WebViewClient.ERROR_HOST_LOOKUP);
|
|
||||||
me.runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
if (exit) {
|
|
||||||
me.appView.getView().setVisibility(View.GONE);
|
|
||||||
me.displayError("Application Error", description + " (" + failingUrl + ")", "OK", exit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display an error dialog and optionally exit application.
|
|
||||||
*/
|
|
||||||
public void displayError(final String title, final String message, final String button, final boolean exit) {
|
|
||||||
final CordovaActivity me = this;
|
|
||||||
me.runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
AlertDialog.Builder dlg = new AlertDialog.Builder(me);
|
|
||||||
dlg.setMessage(message);
|
|
||||||
dlg.setTitle(title);
|
|
||||||
dlg.setCancelable(false);
|
|
||||||
dlg.setPositiveButton(button,
|
|
||||||
new AlertDialog.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
dialog.dismiss();
|
|
||||||
if (exit) {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dlg.create();
|
|
||||||
dlg.show();
|
|
||||||
} catch (Exception e) {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hook in Cordova for menu plugins
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
if (appView != null) {
|
|
||||||
appView.getPluginManager().postMessage("onCreateOptionsMenu", menu);
|
|
||||||
}
|
|
||||||
return super.onCreateOptionsMenu(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
|
||||||
if (appView != null) {
|
|
||||||
appView.getPluginManager().postMessage("onPrepareOptionsMenu", menu);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
if (appView != null) {
|
|
||||||
appView.getPluginManager().postMessage("onOptionsItemSelected", item);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a message is sent to plugin.
|
|
||||||
*
|
|
||||||
* @param id The message id
|
|
||||||
* @param data The message data
|
|
||||||
* @return Object or null
|
|
||||||
*/
|
|
||||||
public Object onMessage(String id, Object data) {
|
|
||||||
if ("onReceivedError".equals(id)) {
|
|
||||||
JSONObject d = (JSONObject) data;
|
|
||||||
try {
|
|
||||||
this.onReceivedError(d.getInt("errorCode"), d.getString("description"), d.getString("url"));
|
|
||||||
} catch (JSONException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else if ("exit".equals(id)) {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
|
||||||
cordovaInterface.onSaveInstanceState(outState);
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the system when the device configuration changes while your activity is running.
|
|
||||||
*
|
|
||||||
* @param newConfig The new device configuration
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onConfigurationChanged(Configuration newConfig) {
|
|
||||||
super.onConfigurationChanged(newConfig);
|
|
||||||
if (this.appView == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PluginManager pm = this.appView.getPluginManager();
|
|
||||||
if (pm != null) {
|
|
||||||
pm.onConfigurationChanged(newConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the system when the user grants permissions
|
|
||||||
*
|
|
||||||
* @param requestCode
|
|
||||||
* @param permissions
|
|
||||||
* @param grantResults
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(int requestCode, String permissions[],
|
|
||||||
int[] grantResults) {
|
|
||||||
try
|
|
||||||
{
|
|
||||||
cordovaInterface.onRequestPermissionResult(requestCode, permissions, grantResults);
|
|
||||||
}
|
|
||||||
catch (JSONException e)
|
|
||||||
{
|
|
||||||
LOG.d(TAG, "JSONException: Parameters fed into the method are not valid");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import android.util.Base64;
|
|
||||||
|
|
||||||
public class CordovaArgs {
|
|
||||||
private JSONArray baseArgs;
|
|
||||||
|
|
||||||
public CordovaArgs(JSONArray args) {
|
|
||||||
this.baseArgs = args;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Pass through the basics to the base args.
|
|
||||||
public Object get(int index) throws JSONException {
|
|
||||||
return baseArgs.get(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getBoolean(int index) throws JSONException {
|
|
||||||
return baseArgs.getBoolean(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getDouble(int index) throws JSONException {
|
|
||||||
return baseArgs.getDouble(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getInt(int index) throws JSONException {
|
|
||||||
return baseArgs.getInt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JSONArray getJSONArray(int index) throws JSONException {
|
|
||||||
return baseArgs.getJSONArray(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JSONObject getJSONObject(int index) throws JSONException {
|
|
||||||
return baseArgs.getJSONObject(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLong(int index) throws JSONException {
|
|
||||||
return baseArgs.getLong(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getString(int index) throws JSONException {
|
|
||||||
return baseArgs.getString(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Object opt(int index) {
|
|
||||||
return baseArgs.opt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean optBoolean(int index) {
|
|
||||||
return baseArgs.optBoolean(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double optDouble(int index) {
|
|
||||||
return baseArgs.optDouble(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int optInt(int index) {
|
|
||||||
return baseArgs.optInt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JSONArray optJSONArray(int index) {
|
|
||||||
return baseArgs.optJSONArray(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JSONObject optJSONObject(int index) {
|
|
||||||
return baseArgs.optJSONObject(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long optLong(int index) {
|
|
||||||
return baseArgs.optLong(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String optString(int index) {
|
|
||||||
return baseArgs.optString(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNull(int index) {
|
|
||||||
return baseArgs.isNull(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// The interesting custom helpers.
|
|
||||||
public byte[] getArrayBuffer(int index) throws JSONException {
|
|
||||||
String encoded = baseArgs.getString(index);
|
|
||||||
return Base64.decode(encoded, Base64.DEFAULT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,187 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains APIs that the JS can call. All functions in here should also have
|
|
||||||
* an equivalent entry in CordovaChromeClient.java, and be added to
|
|
||||||
* cordova-js/lib/android/plugin/android/promptbasednativeapi.js
|
|
||||||
*/
|
|
||||||
public class CordovaBridge {
|
|
||||||
private static final String LOG_TAG = "CordovaBridge";
|
|
||||||
private PluginManager pluginManager;
|
|
||||||
private NativeToJsMessageQueue jsMessageQueue;
|
|
||||||
private volatile int expectedBridgeSecret = -1; // written by UI thread, read by JS thread.
|
|
||||||
|
|
||||||
public CordovaBridge(PluginManager pluginManager, NativeToJsMessageQueue jsMessageQueue) {
|
|
||||||
this.pluginManager = pluginManager;
|
|
||||||
this.jsMessageQueue = jsMessageQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String jsExec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
|
|
||||||
if (!verifySecret("exec()", bridgeSecret)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// If the arguments weren't received, send a message back to JS. It will switch bridge modes and try again. See CB-2666.
|
|
||||||
// We send a message meant specifically for this case. It starts with "@" so no other message can be encoded into the same string.
|
|
||||||
if (arguments == null) {
|
|
||||||
return "@Null arguments.";
|
|
||||||
}
|
|
||||||
|
|
||||||
jsMessageQueue.setPaused(true);
|
|
||||||
try {
|
|
||||||
// Tell the resourceApi what thread the JS is running on.
|
|
||||||
CordovaResourceApi.jsThread = Thread.currentThread();
|
|
||||||
|
|
||||||
pluginManager.exec(service, action, callbackId, arguments);
|
|
||||||
String ret = null;
|
|
||||||
if (!NativeToJsMessageQueue.DISABLE_EXEC_CHAINING) {
|
|
||||||
ret = jsMessageQueue.popAndEncode(false);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return "";
|
|
||||||
} finally {
|
|
||||||
jsMessageQueue.setPaused(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void jsSetNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
|
|
||||||
if (!verifySecret("setNativeToJsBridgeMode()", bridgeSecret)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
jsMessageQueue.setBridgeMode(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String jsRetrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
|
|
||||||
if (!verifySecret("retrieveJsMessages()", bridgeSecret)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return jsMessageQueue.popAndEncode(fromOnlineEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean verifySecret(String action, int bridgeSecret) throws IllegalAccessException {
|
|
||||||
if (!jsMessageQueue.isBridgeEnabled()) {
|
|
||||||
if (bridgeSecret == -1) {
|
|
||||||
LOG.d(LOG_TAG, action + " call made before bridge was enabled.");
|
|
||||||
} else {
|
|
||||||
LOG.d(LOG_TAG, "Ignoring " + action + " from previous page load.");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Bridge secret wrong and bridge not due to it being from the previous page.
|
|
||||||
if (expectedBridgeSecret < 0 || bridgeSecret != expectedBridgeSecret) {
|
|
||||||
LOG.e(LOG_TAG, "Bridge access attempt with wrong secret token, possibly from malicious code. Disabling exec() bridge!");
|
|
||||||
clearBridgeSecret();
|
|
||||||
throw new IllegalAccessException();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Called on page transitions */
|
|
||||||
void clearBridgeSecret() {
|
|
||||||
expectedBridgeSecret = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSecretEstablished() {
|
|
||||||
return expectedBridgeSecret != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Called by cordova.js to initialize the bridge. */
|
|
||||||
//On old Androids SecureRandom isn't really secure, this is the least of your problems if
|
|
||||||
//you're running Android 4.3 and below in 2017
|
|
||||||
@SuppressLint("TrulyRandom")
|
|
||||||
int generateBridgeSecret() {
|
|
||||||
SecureRandom randGen = new SecureRandom();
|
|
||||||
expectedBridgeSecret = randGen.nextInt(Integer.MAX_VALUE);
|
|
||||||
return expectedBridgeSecret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
jsMessageQueue.reset();
|
|
||||||
clearBridgeSecret();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String promptOnJsPrompt(String origin, String message, String defaultValue) {
|
|
||||||
if (defaultValue != null && defaultValue.length() > 3 && defaultValue.startsWith("gap:")) {
|
|
||||||
JSONArray array;
|
|
||||||
try {
|
|
||||||
array = new JSONArray(defaultValue.substring(4));
|
|
||||||
int bridgeSecret = array.getInt(0);
|
|
||||||
String service = array.getString(1);
|
|
||||||
String action = array.getString(2);
|
|
||||||
String callbackId = array.getString(3);
|
|
||||||
String r = jsExec(bridgeSecret, service, action, callbackId, message);
|
|
||||||
return r == null ? "" : r;
|
|
||||||
} catch (JSONException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
// Sets the native->JS bridge mode.
|
|
||||||
else if (defaultValue != null && defaultValue.startsWith("gap_bridge_mode:")) {
|
|
||||||
try {
|
|
||||||
int bridgeSecret = Integer.parseInt(defaultValue.substring(16));
|
|
||||||
jsSetNativeToJsBridgeMode(bridgeSecret, Integer.parseInt(message));
|
|
||||||
} catch (NumberFormatException e){
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
// Polling for JavaScript messages
|
|
||||||
else if (defaultValue != null && defaultValue.startsWith("gap_poll:")) {
|
|
||||||
int bridgeSecret = Integer.parseInt(defaultValue.substring(9));
|
|
||||||
try {
|
|
||||||
String r = jsRetrieveJsMessages(bridgeSecret, "1".equals(message));
|
|
||||||
return r == null ? "" : r;
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
else if (defaultValue != null && defaultValue.startsWith("gap_init:")) {
|
|
||||||
// Protect against random iframes being able to talk through the bridge.
|
|
||||||
// Trust only pages which the app would have been allowed to navigate to anyway.
|
|
||||||
if (pluginManager.shouldAllowBridgeAccess(origin)) {
|
|
||||||
// Enable the bridge
|
|
||||||
int bridgeMode = Integer.parseInt(defaultValue.substring(9));
|
|
||||||
jsMessageQueue.setBridgeMode(bridgeMode);
|
|
||||||
// Tell JS the bridge secret.
|
|
||||||
int secret = generateBridgeSecret();
|
|
||||||
return ""+secret;
|
|
||||||
} else {
|
|
||||||
LOG.e(LOG_TAG, "gap_init called from restricted origin: " + origin);
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,105 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.webkit.ClientCertRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of the ICordovaClientCertRequest for Android WebView.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class CordovaClientCertRequest implements ICordovaClientCertRequest {
|
|
||||||
|
|
||||||
private final ClientCertRequest request;
|
|
||||||
|
|
||||||
public CordovaClientCertRequest(ClientCertRequest request) {
|
|
||||||
this.request = request;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel this request
|
|
||||||
*/
|
|
||||||
@SuppressLint("NewApi")
|
|
||||||
public void cancel()
|
|
||||||
{
|
|
||||||
request.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the host name of the server requesting the certificate.
|
|
||||||
*/
|
|
||||||
@SuppressLint("NewApi")
|
|
||||||
public String getHost()
|
|
||||||
{
|
|
||||||
return request.getHost();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the acceptable types of asymmetric keys (can be null).
|
|
||||||
*/
|
|
||||||
@SuppressLint("NewApi")
|
|
||||||
public String[] getKeyTypes()
|
|
||||||
{
|
|
||||||
return request.getKeyTypes();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the port number of the server requesting the certificate.
|
|
||||||
*/
|
|
||||||
@SuppressLint("NewApi")
|
|
||||||
public int getPort()
|
|
||||||
{
|
|
||||||
return request.getPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the acceptable certificate issuers for the certificate matching the private key (can be null).
|
|
||||||
*/
|
|
||||||
@SuppressLint("NewApi")
|
|
||||||
public Principal[] getPrincipals()
|
|
||||||
{
|
|
||||||
return request.getPrincipals();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ignore the request for now. Do not remember user's choice.
|
|
||||||
*/
|
|
||||||
@SuppressLint("NewApi")
|
|
||||||
public void ignore()
|
|
||||||
{
|
|
||||||
request.ignore();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Proceed with the specified private key and client certificate chain. Remember the user's positive choice and use it for future requests.
|
|
||||||
*
|
|
||||||
* @param privateKey The privateKey
|
|
||||||
* @param chain The certificate chain
|
|
||||||
*/
|
|
||||||
@SuppressLint("NewApi")
|
|
||||||
public void proceed(PrivateKey privateKey, X509Certificate[] chain)
|
|
||||||
{
|
|
||||||
request.proceed(privateKey, chain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,152 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.widget.EditText;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class for WebViews to implement prompt(), alert(), confirm() dialogs.
|
|
||||||
*/
|
|
||||||
public class CordovaDialogsHelper {
|
|
||||||
private final Context context;
|
|
||||||
private AlertDialog lastHandledDialog;
|
|
||||||
|
|
||||||
public CordovaDialogsHelper(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showAlert(String message, final Result result) {
|
|
||||||
AlertDialog.Builder dlg = new AlertDialog.Builder(context);
|
|
||||||
dlg.setMessage(message);
|
|
||||||
dlg.setTitle("Alert");
|
|
||||||
//Don't let alerts break the back button
|
|
||||||
dlg.setCancelable(true);
|
|
||||||
dlg.setPositiveButton(android.R.string.ok,
|
|
||||||
new AlertDialog.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
result.gotResult(true, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dlg.setOnCancelListener(
|
|
||||||
new DialogInterface.OnCancelListener() {
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
|
||||||
result.gotResult(false, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
|
|
||||||
//DO NOTHING
|
|
||||||
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK)
|
|
||||||
{
|
|
||||||
result.gotResult(true, null);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
lastHandledDialog = dlg.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showConfirm(String message, final Result result) {
|
|
||||||
AlertDialog.Builder dlg = new AlertDialog.Builder(context);
|
|
||||||
dlg.setMessage(message);
|
|
||||||
dlg.setTitle("Confirm");
|
|
||||||
dlg.setCancelable(true);
|
|
||||||
dlg.setPositiveButton(android.R.string.ok,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
result.gotResult(true, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dlg.setNegativeButton(android.R.string.cancel,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
result.gotResult(false, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dlg.setOnCancelListener(
|
|
||||||
new DialogInterface.OnCancelListener() {
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
|
||||||
result.gotResult(false, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dlg.setOnKeyListener(new DialogInterface.OnKeyListener() {
|
|
||||||
//DO NOTHING
|
|
||||||
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK)
|
|
||||||
{
|
|
||||||
result.gotResult(false, null);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
lastHandledDialog = dlg.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the client to display a prompt dialog to the user.
|
|
||||||
* If the client returns true, WebView will assume that the client will
|
|
||||||
* handle the prompt dialog and call the appropriate JsPromptResult method.
|
|
||||||
*
|
|
||||||
* Since we are hacking prompts for our own purposes, we should not be using them for
|
|
||||||
* this purpose, perhaps we should hack console.log to do this instead!
|
|
||||||
*/
|
|
||||||
public void showPrompt(String message, String defaultValue, final Result result) {
|
|
||||||
// Returning false would also show a dialog, but the default one shows the origin (ugly).
|
|
||||||
AlertDialog.Builder dlg = new AlertDialog.Builder(context);
|
|
||||||
dlg.setMessage(message);
|
|
||||||
final EditText input = new EditText(context);
|
|
||||||
if (defaultValue != null) {
|
|
||||||
input.setText(defaultValue);
|
|
||||||
}
|
|
||||||
dlg.setView(input);
|
|
||||||
dlg.setCancelable(false);
|
|
||||||
dlg.setPositiveButton(android.R.string.ok,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
String userText = input.getText().toString();
|
|
||||||
result.gotResult(true, userText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dlg.setNegativeButton(android.R.string.cancel,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
result.gotResult(false, null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
lastHandledDialog = dlg.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroyLastDialog(){
|
|
||||||
if (lastHandledDialog != null){
|
|
||||||
lastHandledDialog.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface Result {
|
|
||||||
public void gotResult(boolean success, String value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import android.webkit.HttpAuthHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies interface for HTTP auth handler object which is used to handle auth requests and
|
|
||||||
* specifying user credentials.
|
|
||||||
*/
|
|
||||||
public class CordovaHttpAuthHandler implements ICordovaHttpAuthHandler {
|
|
||||||
|
|
||||||
private final HttpAuthHandler handler;
|
|
||||||
|
|
||||||
public CordovaHttpAuthHandler(HttpAuthHandler handler) {
|
|
||||||
this.handler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instructs the WebView to cancel the authentication request.
|
|
||||||
*/
|
|
||||||
public void cancel () {
|
|
||||||
this.handler.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instructs the WebView to proceed with the authentication with the given credentials.
|
|
||||||
*
|
|
||||||
* @param username
|
|
||||||
* @param password
|
|
||||||
*/
|
|
||||||
public void proceed (String username, String password) {
|
|
||||||
this.handler.proceed(username, password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,97 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
import org.apache.cordova.CordovaPlugin;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Activity interface that is implemented by CordovaActivity.
|
|
||||||
* It is used to isolate plugin development, and remove dependency on entire Cordova library.
|
|
||||||
*/
|
|
||||||
public interface CordovaInterface {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launch an activity for which you would like a result when it finished. When this activity exits,
|
|
||||||
* your onActivityResult() method will be called.
|
|
||||||
*
|
|
||||||
* @param command The command object
|
|
||||||
* @param intent The intent to start
|
|
||||||
* @param requestCode The request code that is passed to callback to identify the activity
|
|
||||||
*/
|
|
||||||
abstract public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the plugin to be called when a sub-activity exits.
|
|
||||||
*
|
|
||||||
* @param plugin The plugin on which onActivityResult is to be called
|
|
||||||
*/
|
|
||||||
abstract public void setActivityResultCallback(CordovaPlugin plugin);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Android activity.
|
|
||||||
*
|
|
||||||
* If a custom engine lives outside of the Activity's lifecycle the return value may be null.
|
|
||||||
*
|
|
||||||
* @return the Activity
|
|
||||||
*/
|
|
||||||
public abstract Activity getActivity();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Android context.
|
|
||||||
*
|
|
||||||
* @return the Context
|
|
||||||
*/
|
|
||||||
public Context getContext();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a message is sent to plugin.
|
|
||||||
*
|
|
||||||
* @param id The message id
|
|
||||||
* @param data The message data
|
|
||||||
* @return Object or null
|
|
||||||
*/
|
|
||||||
public Object onMessage(String id, Object data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a shared thread pool that can be used for background tasks.
|
|
||||||
*/
|
|
||||||
public ExecutorService getThreadPool();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a permission request to the activity for one permission.
|
|
||||||
*/
|
|
||||||
public void requestPermission(CordovaPlugin plugin, int requestCode, String permission);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a permission request to the activity for a group of permissions
|
|
||||||
*/
|
|
||||||
public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for a permission. Returns true if the permission is granted, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean hasPermission(String permission);
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,249 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Pair;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default implementation of CordovaInterface.
|
|
||||||
*/
|
|
||||||
public class CordovaInterfaceImpl implements CordovaInterface {
|
|
||||||
private static final String TAG = "CordovaInterfaceImpl";
|
|
||||||
protected Activity activity;
|
|
||||||
protected ExecutorService threadPool;
|
|
||||||
protected PluginManager pluginManager;
|
|
||||||
|
|
||||||
protected ActivityResultHolder savedResult;
|
|
||||||
protected CallbackMap permissionResultCallbacks;
|
|
||||||
protected CordovaPlugin activityResultCallback;
|
|
||||||
protected String initCallbackService;
|
|
||||||
protected int activityResultRequestCode;
|
|
||||||
protected boolean activityWasDestroyed = false;
|
|
||||||
protected Bundle savedPluginState;
|
|
||||||
|
|
||||||
public CordovaInterfaceImpl(Activity activity) {
|
|
||||||
this(activity, Executors.newCachedThreadPool());
|
|
||||||
}
|
|
||||||
|
|
||||||
public CordovaInterfaceImpl(Activity activity, ExecutorService threadPool) {
|
|
||||||
this.activity = activity;
|
|
||||||
this.threadPool = threadPool;
|
|
||||||
this.permissionResultCallbacks = new CallbackMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startActivityForResult(CordovaPlugin command, Intent intent, int requestCode) {
|
|
||||||
setActivityResultCallback(command);
|
|
||||||
try {
|
|
||||||
activity.startActivityForResult(intent, requestCode);
|
|
||||||
} catch (RuntimeException e) { // E.g.: ActivityNotFoundException
|
|
||||||
activityResultCallback = null;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setActivityResultCallback(CordovaPlugin plugin) {
|
|
||||||
// Cancel any previously pending activity.
|
|
||||||
if (activityResultCallback != null) {
|
|
||||||
activityResultCallback.onActivityResult(activityResultRequestCode, Activity.RESULT_CANCELED, null);
|
|
||||||
}
|
|
||||||
activityResultCallback = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Activity getActivity() {
|
|
||||||
return activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Context getContext() {
|
|
||||||
return activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object onMessage(String id, Object data) {
|
|
||||||
if ("exit".equals(id)) {
|
|
||||||
activity.finish();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ExecutorService getThreadPool() {
|
|
||||||
return threadPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispatches any pending onActivityResult callbacks and sends the resume event if the
|
|
||||||
* Activity was destroyed by the OS.
|
|
||||||
*/
|
|
||||||
public void onCordovaInit(PluginManager pluginManager) {
|
|
||||||
this.pluginManager = pluginManager;
|
|
||||||
if (savedResult != null) {
|
|
||||||
onActivityResult(savedResult.requestCode, savedResult.resultCode, savedResult.intent);
|
|
||||||
} else if(activityWasDestroyed) {
|
|
||||||
// If there was no Activity result, we still need to send out the resume event if the
|
|
||||||
// Activity was destroyed by the OS
|
|
||||||
activityWasDestroyed = false;
|
|
||||||
if(pluginManager != null)
|
|
||||||
{
|
|
||||||
CoreAndroid appPlugin = (CoreAndroid) pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME);
|
|
||||||
if(appPlugin != null) {
|
|
||||||
JSONObject obj = new JSONObject();
|
|
||||||
try {
|
|
||||||
obj.put("action", "resume");
|
|
||||||
} catch (JSONException e) {
|
|
||||||
LOG.e(TAG, "Failed to create event message", e);
|
|
||||||
}
|
|
||||||
appPlugin.sendResumeEvent(new PluginResult(PluginResult.Status.OK, obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Routes the result to the awaiting plugin. Returns false if no plugin was waiting.
|
|
||||||
*/
|
|
||||||
public boolean onActivityResult(int requestCode, int resultCode, Intent intent) {
|
|
||||||
CordovaPlugin callback = activityResultCallback;
|
|
||||||
if(callback == null && initCallbackService != null) {
|
|
||||||
// The application was restarted, but had defined an initial callback
|
|
||||||
// before being shut down.
|
|
||||||
savedResult = new ActivityResultHolder(requestCode, resultCode, intent);
|
|
||||||
if (pluginManager != null) {
|
|
||||||
callback = pluginManager.getPlugin(initCallbackService);
|
|
||||||
if(callback != null) {
|
|
||||||
callback.onRestoreStateForActivityResult(savedPluginState.getBundle(callback.getServiceName()),
|
|
||||||
new ResumeCallback(callback.getServiceName(), pluginManager));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
activityResultCallback = null;
|
|
||||||
|
|
||||||
if (callback != null) {
|
|
||||||
LOG.d(TAG, "Sending activity result to plugin");
|
|
||||||
initCallbackService = null;
|
|
||||||
savedResult = null;
|
|
||||||
callback.onActivityResult(requestCode, resultCode, intent);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
LOG.w(TAG, "Got an activity result, but no plugin was registered to receive it" + (savedResult != null ? " yet!" : "."));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call this from your startActivityForResult() overload. This is required to catch the case
|
|
||||||
* where plugins use Activity.startActivityForResult() + CordovaInterface.setActivityResultCallback()
|
|
||||||
* rather than CordovaInterface.startActivityForResult().
|
|
||||||
*/
|
|
||||||
public void setActivityResultRequestCode(int requestCode) {
|
|
||||||
activityResultRequestCode = requestCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves parameters for startActivityForResult().
|
|
||||||
*/
|
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
|
||||||
if (activityResultCallback != null) {
|
|
||||||
String serviceName = activityResultCallback.getServiceName();
|
|
||||||
outState.putString("callbackService", serviceName);
|
|
||||||
}
|
|
||||||
if(pluginManager != null){
|
|
||||||
outState.putBundle("plugin", pluginManager.onSaveInstanceState());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call this from onCreate() so that any saved startActivityForResult parameters will be restored.
|
|
||||||
*/
|
|
||||||
public void restoreInstanceState(Bundle savedInstanceState) {
|
|
||||||
initCallbackService = savedInstanceState.getString("callbackService");
|
|
||||||
savedPluginState = savedInstanceState.getBundle("plugin");
|
|
||||||
activityWasDestroyed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ActivityResultHolder {
|
|
||||||
private int requestCode;
|
|
||||||
private int resultCode;
|
|
||||||
private Intent intent;
|
|
||||||
|
|
||||||
public ActivityResultHolder(int requestCode, int resultCode, Intent intent) {
|
|
||||||
this.requestCode = requestCode;
|
|
||||||
this.resultCode = resultCode;
|
|
||||||
this.intent = intent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the system when the user grants permissions
|
|
||||||
*
|
|
||||||
* @param requestCode
|
|
||||||
* @param permissions
|
|
||||||
* @param grantResults
|
|
||||||
*/
|
|
||||||
public void onRequestPermissionResult(int requestCode, String[] permissions,
|
|
||||||
int[] grantResults) throws JSONException {
|
|
||||||
Pair<CordovaPlugin, Integer> callback = permissionResultCallbacks.getAndRemoveCallback(requestCode);
|
|
||||||
if(callback != null) {
|
|
||||||
callback.first.onRequestPermissionResult(callback.second, permissions, grantResults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestPermission(CordovaPlugin plugin, int requestCode, String permission) {
|
|
||||||
String[] permissions = new String [1];
|
|
||||||
permissions[0] = permission;
|
|
||||||
requestPermissions(plugin, requestCode, permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
|
||||||
public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions) {
|
|
||||||
int mappedRequestCode = permissionResultCallbacks.registerCallback(plugin, requestCode);
|
|
||||||
getActivity().requestPermissions(permissions, mappedRequestCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasPermission(String permission)
|
|
||||||
{
|
|
||||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
|
||||||
{
|
|
||||||
int result = activity.checkSelfPermission(permission);
|
|
||||||
return PackageManager.PERMISSION_GRANTED == result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,422 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import org.apache.cordova.CordovaArgs;
|
|
||||||
import org.apache.cordova.CordovaWebView;
|
|
||||||
import org.apache.cordova.CordovaInterface;
|
|
||||||
import org.apache.cordova.CallbackContext;
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Plugins must extend this class and override one of the execute methods.
|
|
||||||
*/
|
|
||||||
public class CordovaPlugin {
|
|
||||||
public CordovaWebView webView;
|
|
||||||
public CordovaInterface cordova;
|
|
||||||
protected CordovaPreferences preferences;
|
|
||||||
private String serviceName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call this after constructing to initialize the plugin.
|
|
||||||
* Final because we want to be able to change args without breaking plugins.
|
|
||||||
*/
|
|
||||||
public final void privateInitialize(String serviceName, CordovaInterface cordova, CordovaWebView webView, CordovaPreferences preferences) {
|
|
||||||
assert this.cordova == null;
|
|
||||||
this.serviceName = serviceName;
|
|
||||||
this.cordova = cordova;
|
|
||||||
this.webView = webView;
|
|
||||||
this.preferences = preferences;
|
|
||||||
initialize(cordova, webView);
|
|
||||||
pluginInitialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after plugin construction and fields have been initialized.
|
|
||||||
* Prefer to use pluginInitialize instead since there is no value in
|
|
||||||
* having parameters on the initialize() function.
|
|
||||||
*/
|
|
||||||
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after plugin construction and fields have been initialized.
|
|
||||||
*/
|
|
||||||
protected void pluginInitialize() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the plugin's service name (what you'd use when calling pluginManger.getPlugin())
|
|
||||||
*/
|
|
||||||
public String getServiceName() {
|
|
||||||
return serviceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the request.
|
|
||||||
*
|
|
||||||
* This method is called from the WebView thread. To do a non-trivial amount of work, use:
|
|
||||||
* cordova.getThreadPool().execute(runnable);
|
|
||||||
*
|
|
||||||
* To run on the UI thread, use:
|
|
||||||
* cordova.getActivity().runOnUiThread(runnable);
|
|
||||||
*
|
|
||||||
* @param action The action to execute.
|
|
||||||
* @param rawArgs The exec() arguments in JSON form.
|
|
||||||
* @param callbackContext The callback context used when calling back into JavaScript.
|
|
||||||
* @return Whether the action was valid.
|
|
||||||
*/
|
|
||||||
public boolean execute(String action, String rawArgs, CallbackContext callbackContext) throws JSONException {
|
|
||||||
JSONArray args = new JSONArray(rawArgs);
|
|
||||||
return execute(action, args, callbackContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the request.
|
|
||||||
*
|
|
||||||
* This method is called from the WebView thread. To do a non-trivial amount of work, use:
|
|
||||||
* cordova.getThreadPool().execute(runnable);
|
|
||||||
*
|
|
||||||
* To run on the UI thread, use:
|
|
||||||
* cordova.getActivity().runOnUiThread(runnable);
|
|
||||||
*
|
|
||||||
* @param action The action to execute.
|
|
||||||
* @param args The exec() arguments.
|
|
||||||
* @param callbackContext The callback context used when calling back into JavaScript.
|
|
||||||
* @return Whether the action was valid.
|
|
||||||
*/
|
|
||||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
|
||||||
CordovaArgs cordovaArgs = new CordovaArgs(args);
|
|
||||||
return execute(action, cordovaArgs, callbackContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the request.
|
|
||||||
*
|
|
||||||
* This method is called from the WebView thread. To do a non-trivial amount of work, use:
|
|
||||||
* cordova.getThreadPool().execute(runnable);
|
|
||||||
*
|
|
||||||
* To run on the UI thread, use:
|
|
||||||
* cordova.getActivity().runOnUiThread(runnable);
|
|
||||||
*
|
|
||||||
* @param action The action to execute.
|
|
||||||
* @param args The exec() arguments, wrapped with some Cordova helpers.
|
|
||||||
* @param callbackContext The callback context used when calling back into JavaScript.
|
|
||||||
* @return Whether the action was valid.
|
|
||||||
*/
|
|
||||||
public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the system is about to start resuming a previous activity.
|
|
||||||
*
|
|
||||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
|
||||||
*/
|
|
||||||
public void onPause(boolean multitasking) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity will start interacting with the user.
|
|
||||||
*
|
|
||||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
|
||||||
*/
|
|
||||||
public void onResume(boolean multitasking) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity is becoming visible to the user.
|
|
||||||
*/
|
|
||||||
public void onStart() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity is no longer visible to the user.
|
|
||||||
*/
|
|
||||||
public void onStop() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity receives a new intent.
|
|
||||||
*/
|
|
||||||
public void onNewIntent(Intent intent) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The final call you receive before your activity is destroyed.
|
|
||||||
*/
|
|
||||||
public void onDestroy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the Activity is being destroyed (e.g. if a plugin calls out to an external
|
|
||||||
* Activity and the OS kills the CordovaActivity in the background). The plugin should save its
|
|
||||||
* state in this method only if it is awaiting the result of an external Activity and needs
|
|
||||||
* to preserve some information so as to handle that result; onRestoreStateForActivityResult()
|
|
||||||
* will only be called if the plugin is the recipient of an Activity result
|
|
||||||
*
|
|
||||||
* @return Bundle containing the state of the plugin or null if state does not need to be saved
|
|
||||||
*/
|
|
||||||
public Bundle onSaveInstanceState() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a plugin is the recipient of an Activity result after the CordovaActivity has
|
|
||||||
* been destroyed. The Bundle will be the same as the one the plugin returned in
|
|
||||||
* onSaveInstanceState()
|
|
||||||
*
|
|
||||||
* @param state Bundle containing the state of the plugin
|
|
||||||
* @param callbackContext Replacement Context to return the plugin result to
|
|
||||||
*/
|
|
||||||
public void onRestoreStateForActivityResult(Bundle state, CallbackContext callbackContext) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a message is sent to plugin.
|
|
||||||
*
|
|
||||||
* @param id The message id
|
|
||||||
* @param data The message data
|
|
||||||
* @return Object to stop propagation or null
|
|
||||||
*/
|
|
||||||
public Object onMessage(String id, Object data) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when an activity you launched exits, giving you the requestCode you started it with,
|
|
||||||
* the resultCode it returned, and any additional data from it.
|
|
||||||
*
|
|
||||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
|
||||||
* allowing you to identify who this result came from.
|
|
||||||
* @param resultCode The integer result code returned by the child activity through its setResult().
|
|
||||||
* @param intent An Intent, which can return result data to the caller (various data can be
|
|
||||||
* attached to Intent "extras").
|
|
||||||
*/
|
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook for blocking the loading of external resources.
|
|
||||||
*
|
|
||||||
* This will be called when the WebView's shouldInterceptRequest wants to
|
|
||||||
* know whether to open a connection to an external resource. Return false
|
|
||||||
* to block the request: if any plugin returns false, Cordova will block
|
|
||||||
* the request. If all plugins return null, the default policy will be
|
|
||||||
* enforced. If at least one plugin returns true, and no plugins return
|
|
||||||
* false, then the request will proceed.
|
|
||||||
*
|
|
||||||
* Note that this only affects resource requests which are routed through
|
|
||||||
* WebViewClient.shouldInterceptRequest, such as XMLHttpRequest requests and
|
|
||||||
* img tag loads. WebSockets and media requests (such as <video> and <audio>
|
|
||||||
* tags) are not affected by this method. Use CSP headers to control access
|
|
||||||
* to such resources.
|
|
||||||
*/
|
|
||||||
public Boolean shouldAllowRequest(String url) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook for blocking navigation by the Cordova WebView. This applies both to top-level and
|
|
||||||
* iframe navigations.
|
|
||||||
*
|
|
||||||
* This will be called when the WebView's needs to know whether to navigate
|
|
||||||
* to a new page. Return false to block the navigation: if any plugin
|
|
||||||
* returns false, Cordova will block the navigation. If all plugins return
|
|
||||||
* null, the default policy will be enforced. It at least one plugin returns
|
|
||||||
* true, and no plugins return false, then the navigation will proceed.
|
|
||||||
*/
|
|
||||||
public Boolean shouldAllowNavigation(String url) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook for allowing page to call exec(). By default, this returns the result of
|
|
||||||
* shouldAllowNavigation(). It's generally unsafe to allow untrusted content to be loaded
|
|
||||||
* into a CordovaWebView, even within an iframe, so it's best not to touch this.
|
|
||||||
*/
|
|
||||||
public Boolean shouldAllowBridgeAccess(String url) {
|
|
||||||
return shouldAllowNavigation(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook for blocking the launching of Intents by the Cordova application.
|
|
||||||
*
|
|
||||||
* This will be called when the WebView will not navigate to a page, but
|
|
||||||
* could launch an intent to handle the URL. Return false to block this: if
|
|
||||||
* any plugin returns false, Cordova will block the navigation. If all
|
|
||||||
* plugins return null, the default policy will be enforced. If at least one
|
|
||||||
* plugin returns true, and no plugins return false, then the URL will be
|
|
||||||
* opened.
|
|
||||||
*/
|
|
||||||
public Boolean shouldOpenExternalUrl(String url) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows plugins to handle a link being clicked. Return true here to cancel the navigation.
|
|
||||||
*
|
|
||||||
* @param url The URL that is trying to be loaded in the Cordova webview.
|
|
||||||
* @return Return true to prevent the URL from loading. Default is false.
|
|
||||||
*/
|
|
||||||
public boolean onOverrideUrlLoading(String url) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook for redirecting requests. Applies to WebView requests as well as requests made by plugins.
|
|
||||||
* To handle the request directly, return a URI in the form:
|
|
||||||
*
|
|
||||||
* cdvplugin://pluginId/...
|
|
||||||
*
|
|
||||||
* And implement handleOpenForRead().
|
|
||||||
* To make this easier, use the toPluginUri() and fromPluginUri() helpers:
|
|
||||||
*
|
|
||||||
* public Uri remapUri(Uri uri) { return toPluginUri(uri); }
|
|
||||||
*
|
|
||||||
* public CordovaResourceApi.OpenForReadResult handleOpenForRead(Uri uri) throws IOException {
|
|
||||||
* Uri origUri = fromPluginUri(uri);
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
public Uri remapUri(Uri uri) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called to handle CordovaResourceApi.openForRead() calls for a cdvplugin://pluginId/ URL.
|
|
||||||
* Should never return null.
|
|
||||||
* Added in cordova-android@4.0.0
|
|
||||||
*/
|
|
||||||
public CordovaResourceApi.OpenForReadResult handleOpenForRead(Uri uri) throws IOException {
|
|
||||||
throw new FileNotFoundException("Plugin can't handle uri: " + uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refer to remapUri()
|
|
||||||
* Added in cordova-android@4.0.0
|
|
||||||
*/
|
|
||||||
protected Uri toPluginUri(Uri origUri) {
|
|
||||||
return new Uri.Builder()
|
|
||||||
.scheme(CordovaResourceApi.PLUGIN_URI_SCHEME)
|
|
||||||
.authority(serviceName)
|
|
||||||
.appendQueryParameter("origUri", origUri.toString())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refer to remapUri()
|
|
||||||
* Added in cordova-android@4.0.0
|
|
||||||
*/
|
|
||||||
protected Uri fromPluginUri(Uri pluginUri) {
|
|
||||||
return Uri.parse(pluginUri.getQueryParameter("origUri"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the WebView does a top-level navigation or refreshes.
|
|
||||||
*
|
|
||||||
* Plugins should stop any long-running processes and clean up internal state.
|
|
||||||
*
|
|
||||||
* Does nothing by default.
|
|
||||||
*/
|
|
||||||
public void onReset() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the system received an HTTP authentication request. Plugin can use
|
|
||||||
* the supplied HttpAuthHandler to process this auth challenge.
|
|
||||||
*
|
|
||||||
* @param view The WebView that is initiating the callback
|
|
||||||
* @param handler The HttpAuthHandler used to set the WebView's response
|
|
||||||
* @param host The host requiring authentication
|
|
||||||
* @param realm The realm for which authentication is required
|
|
||||||
*
|
|
||||||
* @return Returns True if plugin will resolve this auth challenge, otherwise False
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public boolean onReceivedHttpAuthRequest(CordovaWebView view, ICordovaHttpAuthHandler handler, String host, String realm) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when he system received an SSL client certificate request. Plugin can use
|
|
||||||
* the supplied ClientCertRequest to process this certificate challenge.
|
|
||||||
*
|
|
||||||
* @param view The WebView that is initiating the callback
|
|
||||||
* @param request The client certificate request
|
|
||||||
*
|
|
||||||
* @return Returns True if plugin will resolve this auth challenge, otherwise False
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public boolean onReceivedClientCertRequest(CordovaWebView view, ICordovaClientCertRequest request) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the system when the device configuration changes while your activity is running.
|
|
||||||
*
|
|
||||||
* @param newConfig The new device configuration
|
|
||||||
*/
|
|
||||||
public void onConfigurationChanged(Configuration newConfig) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the Plugin Manager when we need to actually request permissions
|
|
||||||
*
|
|
||||||
* @param requestCode Passed to the activity to track the request
|
|
||||||
*
|
|
||||||
* @return Returns the permission that was stored in the plugin
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void requestPermissions(int requestCode) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Called by the WebView implementation to check for geolocation permissions, can be used
|
|
||||||
* by other Java methods in the event that a plugin is using this as a dependency.
|
|
||||||
*
|
|
||||||
* @return Returns true if the plugin has all the permissions it needs to operate.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean hasPermisssion() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the system when the user grants permissions
|
|
||||||
*
|
|
||||||
* @param requestCode
|
|
||||||
* @param permissions
|
|
||||||
* @param grantResults
|
|
||||||
*/
|
|
||||||
public void onRequestPermissionResult(int requestCode, String[] permissions,
|
|
||||||
int[] grantResults) throws JSONException {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.cordova.LOG;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
public class CordovaPreferences {
|
|
||||||
private HashMap<String, String> prefs = new HashMap<String, String>(20);
|
|
||||||
private Bundle preferencesBundleExtras;
|
|
||||||
|
|
||||||
public void setPreferencesBundle(Bundle extras) {
|
|
||||||
preferencesBundleExtras = extras;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(String name, String value) {
|
|
||||||
prefs.put(name.toLowerCase(Locale.ENGLISH), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(String name, boolean value) {
|
|
||||||
set(name, "" + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(String name, int value) {
|
|
||||||
set(name, "" + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(String name, double value) {
|
|
||||||
set(name, "" + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getAll() {
|
|
||||||
return prefs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getBoolean(String name, boolean defaultValue) {
|
|
||||||
name = name.toLowerCase(Locale.ENGLISH);
|
|
||||||
String value = prefs.get(name);
|
|
||||||
if (value != null) {
|
|
||||||
return Boolean.parseBoolean(value);
|
|
||||||
}
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Added in 4.0.0
|
|
||||||
public boolean contains(String name) {
|
|
||||||
return getString(name, null) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getInteger(String name, int defaultValue) {
|
|
||||||
name = name.toLowerCase(Locale.ENGLISH);
|
|
||||||
String value = prefs.get(name);
|
|
||||||
if (value != null) {
|
|
||||||
// Use Integer.decode() can't handle it if the highest bit is set.
|
|
||||||
return (int)(long)Long.decode(value);
|
|
||||||
}
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getDouble(String name, double defaultValue) {
|
|
||||||
name = name.toLowerCase(Locale.ENGLISH);
|
|
||||||
String value = prefs.get(name);
|
|
||||||
if (value != null) {
|
|
||||||
return Double.valueOf(value);
|
|
||||||
}
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getString(String name, String defaultValue) {
|
|
||||||
name = name.toLowerCase(Locale.ENGLISH);
|
|
||||||
String value = prefs.get(name);
|
|
||||||
if (value != null) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,472 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.AssetFileDescriptor;
|
|
||||||
import android.content.res.AssetManager;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.util.Base64;
|
|
||||||
import android.webkit.MimeTypeMap;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* What this class provides:
|
|
||||||
* 1. Helpers for reading & writing to URLs.
|
|
||||||
* - E.g. handles assets, resources, content providers, files, data URIs, http[s]
|
|
||||||
* - E.g. Can be used to query for mime-type & content length.
|
|
||||||
*
|
|
||||||
* 2. To allow plugins to redirect URLs (via remapUrl).
|
|
||||||
* - All plugins should call remapUrl() on URLs they receive from JS *before*
|
|
||||||
* passing the URL onto other utility functions in this class.
|
|
||||||
* - For an example usage of this, refer to the org.apache.cordova.file plugin.
|
|
||||||
*
|
|
||||||
* Future Work:
|
|
||||||
* - Consider using a Cursor to query content URLs for their size (like the file plugin does).
|
|
||||||
* - Allow plugins to remapUri to "cdv-plugin://plugin-name/foo", which CordovaResourceApi
|
|
||||||
* would then delegate to pluginManager.getPlugin(plugin-name).openForRead(url)
|
|
||||||
* - Currently, plugins *can* do this by remapping to a data: URL, but it's inefficient
|
|
||||||
* for large payloads.
|
|
||||||
*/
|
|
||||||
public class CordovaResourceApi {
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final String LOG_TAG = "CordovaResourceApi";
|
|
||||||
|
|
||||||
public static final int URI_TYPE_FILE = 0;
|
|
||||||
public static final int URI_TYPE_ASSET = 1;
|
|
||||||
public static final int URI_TYPE_CONTENT = 2;
|
|
||||||
public static final int URI_TYPE_RESOURCE = 3;
|
|
||||||
public static final int URI_TYPE_DATA = 4;
|
|
||||||
public static final int URI_TYPE_HTTP = 5;
|
|
||||||
public static final int URI_TYPE_HTTPS = 6;
|
|
||||||
public static final int URI_TYPE_PLUGIN = 7;
|
|
||||||
public static final int URI_TYPE_UNKNOWN = -1;
|
|
||||||
|
|
||||||
public static final String PLUGIN_URI_SCHEME = "cdvplugin";
|
|
||||||
|
|
||||||
private static final String[] LOCAL_FILE_PROJECTION = { "_data" };
|
|
||||||
|
|
||||||
public static Thread jsThread;
|
|
||||||
|
|
||||||
private final AssetManager assetManager;
|
|
||||||
private final ContentResolver contentResolver;
|
|
||||||
private final PluginManager pluginManager;
|
|
||||||
private boolean threadCheckingEnabled = true;
|
|
||||||
|
|
||||||
|
|
||||||
public CordovaResourceApi(Context context, PluginManager pluginManager) {
|
|
||||||
this.contentResolver = context.getContentResolver();
|
|
||||||
this.assetManager = context.getAssets();
|
|
||||||
this.pluginManager = pluginManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setThreadCheckingEnabled(boolean value) {
|
|
||||||
threadCheckingEnabled = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isThreadCheckingEnabled() {
|
|
||||||
return threadCheckingEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static int getUriType(Uri uri) {
|
|
||||||
assertNonRelative(uri);
|
|
||||||
String scheme = uri.getScheme();
|
|
||||||
if (ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(scheme)) {
|
|
||||||
return URI_TYPE_CONTENT;
|
|
||||||
}
|
|
||||||
if (ContentResolver.SCHEME_ANDROID_RESOURCE.equalsIgnoreCase(scheme)) {
|
|
||||||
return URI_TYPE_RESOURCE;
|
|
||||||
}
|
|
||||||
if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(scheme)) {
|
|
||||||
if (uri.getPath().startsWith("/android_asset/")) {
|
|
||||||
return URI_TYPE_ASSET;
|
|
||||||
}
|
|
||||||
return URI_TYPE_FILE;
|
|
||||||
}
|
|
||||||
if ("data".equalsIgnoreCase(scheme)) {
|
|
||||||
return URI_TYPE_DATA;
|
|
||||||
}
|
|
||||||
if ("http".equalsIgnoreCase(scheme)) {
|
|
||||||
return URI_TYPE_HTTP;
|
|
||||||
}
|
|
||||||
if ("https".equalsIgnoreCase(scheme)) {
|
|
||||||
return URI_TYPE_HTTPS;
|
|
||||||
}
|
|
||||||
if (PLUGIN_URI_SCHEME.equalsIgnoreCase(scheme)) {
|
|
||||||
return URI_TYPE_PLUGIN;
|
|
||||||
}
|
|
||||||
return URI_TYPE_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Uri remapUri(Uri uri) {
|
|
||||||
assertNonRelative(uri);
|
|
||||||
Uri pluginUri = pluginManager.remapUri(uri);
|
|
||||||
return pluginUri != null ? pluginUri : uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String remapPath(String path) {
|
|
||||||
return remapUri(Uri.fromFile(new File(path))).getPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a File that points to the resource, or null if the resource
|
|
||||||
* is not on the local filesystem.
|
|
||||||
*/
|
|
||||||
public File mapUriToFile(Uri uri) {
|
|
||||||
assertBackgroundThread();
|
|
||||||
switch (getUriType(uri)) {
|
|
||||||
case URI_TYPE_FILE:
|
|
||||||
return new File(uri.getPath());
|
|
||||||
case URI_TYPE_CONTENT: {
|
|
||||||
Cursor cursor = contentResolver.query(uri, LOCAL_FILE_PROJECTION, null, null, null);
|
|
||||||
if (cursor != null) {
|
|
||||||
try {
|
|
||||||
int columnIndex = cursor.getColumnIndex(LOCAL_FILE_PROJECTION[0]);
|
|
||||||
if (columnIndex != -1 && cursor.getCount() > 0) {
|
|
||||||
cursor.moveToFirst();
|
|
||||||
String realPath = cursor.getString(columnIndex);
|
|
||||||
if (realPath != null) {
|
|
||||||
return new File(realPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMimeType(Uri uri) {
|
|
||||||
switch (getUriType(uri)) {
|
|
||||||
case URI_TYPE_FILE:
|
|
||||||
case URI_TYPE_ASSET:
|
|
||||||
return getMimeTypeFromPath(uri.getPath());
|
|
||||||
case URI_TYPE_CONTENT:
|
|
||||||
case URI_TYPE_RESOURCE:
|
|
||||||
return contentResolver.getType(uri);
|
|
||||||
case URI_TYPE_DATA: {
|
|
||||||
return getDataUriMimeType(uri);
|
|
||||||
}
|
|
||||||
case URI_TYPE_HTTP:
|
|
||||||
case URI_TYPE_HTTPS: {
|
|
||||||
try {
|
|
||||||
HttpURLConnection conn = (HttpURLConnection)new URL(uri.toString()).openConnection();
|
|
||||||
conn.setDoInput(false);
|
|
||||||
conn.setRequestMethod("HEAD");
|
|
||||||
String mimeType = conn.getHeaderField("Content-Type");
|
|
||||||
if (mimeType != null) {
|
|
||||||
mimeType = mimeType.split(";")[0];
|
|
||||||
}
|
|
||||||
return mimeType;
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//This already exists
|
|
||||||
private String getMimeTypeFromPath(String path) {
|
|
||||||
String extension = path;
|
|
||||||
int lastDot = extension.lastIndexOf('.');
|
|
||||||
if (lastDot != -1) {
|
|
||||||
extension = extension.substring(lastDot + 1);
|
|
||||||
}
|
|
||||||
// Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
|
|
||||||
extension = extension.toLowerCase(Locale.getDefault());
|
|
||||||
if (extension.equals("3ga")) {
|
|
||||||
return "audio/3gpp";
|
|
||||||
} else if (extension.equals("js")) {
|
|
||||||
// Missing from the map :(.
|
|
||||||
return "text/javascript";
|
|
||||||
}
|
|
||||||
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a stream to the given URI, also providing the MIME type & length.
|
|
||||||
* @return Never returns null.
|
|
||||||
* @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
|
|
||||||
* resolved before being passed into this function.
|
|
||||||
* @throws Throws an IOException if the URI cannot be opened.
|
|
||||||
* @throws Throws an IllegalStateException if called on a foreground thread.
|
|
||||||
*/
|
|
||||||
public OpenForReadResult openForRead(Uri uri) throws IOException {
|
|
||||||
return openForRead(uri, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a stream to the given URI, also providing the MIME type & length.
|
|
||||||
* @return Never returns null.
|
|
||||||
* @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
|
|
||||||
* resolved before being passed into this function.
|
|
||||||
* @throws Throws an IOException if the URI cannot be opened.
|
|
||||||
* @throws Throws an IllegalStateException if called on a foreground thread and skipThreadCheck is false.
|
|
||||||
*/
|
|
||||||
public OpenForReadResult openForRead(Uri uri, boolean skipThreadCheck) throws IOException {
|
|
||||||
if (!skipThreadCheck) {
|
|
||||||
assertBackgroundThread();
|
|
||||||
}
|
|
||||||
switch (getUriType(uri)) {
|
|
||||||
case URI_TYPE_FILE: {
|
|
||||||
FileInputStream inputStream = new FileInputStream(uri.getPath());
|
|
||||||
String mimeType = getMimeTypeFromPath(uri.getPath());
|
|
||||||
long length = inputStream.getChannel().size();
|
|
||||||
return new OpenForReadResult(uri, inputStream, mimeType, length, null);
|
|
||||||
}
|
|
||||||
case URI_TYPE_ASSET: {
|
|
||||||
String assetPath = uri.getPath().substring(15);
|
|
||||||
AssetFileDescriptor assetFd = null;
|
|
||||||
InputStream inputStream;
|
|
||||||
long length = -1;
|
|
||||||
try {
|
|
||||||
assetFd = assetManager.openFd(assetPath);
|
|
||||||
inputStream = assetFd.createInputStream();
|
|
||||||
length = assetFd.getLength();
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
// Will occur if the file is compressed.
|
|
||||||
inputStream = assetManager.open(assetPath);
|
|
||||||
length = inputStream.available();
|
|
||||||
}
|
|
||||||
String mimeType = getMimeTypeFromPath(assetPath);
|
|
||||||
return new OpenForReadResult(uri, inputStream, mimeType, length, assetFd);
|
|
||||||
}
|
|
||||||
case URI_TYPE_CONTENT:
|
|
||||||
case URI_TYPE_RESOURCE: {
|
|
||||||
String mimeType = contentResolver.getType(uri);
|
|
||||||
AssetFileDescriptor assetFd = contentResolver.openAssetFileDescriptor(uri, "r");
|
|
||||||
InputStream inputStream = assetFd.createInputStream();
|
|
||||||
long length = assetFd.getLength();
|
|
||||||
return new OpenForReadResult(uri, inputStream, mimeType, length, assetFd);
|
|
||||||
}
|
|
||||||
case URI_TYPE_DATA: {
|
|
||||||
OpenForReadResult ret = readDataUri(uri);
|
|
||||||
if (ret == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
case URI_TYPE_HTTP:
|
|
||||||
case URI_TYPE_HTTPS: {
|
|
||||||
HttpURLConnection conn = (HttpURLConnection)new URL(uri.toString()).openConnection();
|
|
||||||
conn.setDoInput(true);
|
|
||||||
String mimeType = conn.getHeaderField("Content-Type");
|
|
||||||
if (mimeType != null) {
|
|
||||||
mimeType = mimeType.split(";")[0];
|
|
||||||
}
|
|
||||||
int length = conn.getContentLength();
|
|
||||||
InputStream inputStream = conn.getInputStream();
|
|
||||||
return new OpenForReadResult(uri, inputStream, mimeType, length, null);
|
|
||||||
}
|
|
||||||
case URI_TYPE_PLUGIN: {
|
|
||||||
String pluginId = uri.getHost();
|
|
||||||
CordovaPlugin plugin = pluginManager.getPlugin(pluginId);
|
|
||||||
if (plugin == null) {
|
|
||||||
throw new FileNotFoundException("Invalid plugin ID in URI: " + uri);
|
|
||||||
}
|
|
||||||
return plugin.handleOpenForRead(uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new FileNotFoundException("URI not supported by CordovaResourceApi: " + uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
public OutputStream openOutputStream(Uri uri) throws IOException {
|
|
||||||
return openOutputStream(uri, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a stream to the given URI.
|
|
||||||
* @return Never returns null.
|
|
||||||
* @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
|
|
||||||
* resolved before being passed into this function.
|
|
||||||
* @throws Throws an IOException if the URI cannot be opened.
|
|
||||||
*/
|
|
||||||
public OutputStream openOutputStream(Uri uri, boolean append) throws IOException {
|
|
||||||
assertBackgroundThread();
|
|
||||||
switch (getUriType(uri)) {
|
|
||||||
case URI_TYPE_FILE: {
|
|
||||||
File localFile = new File(uri.getPath());
|
|
||||||
File parent = localFile.getParentFile();
|
|
||||||
if (parent != null) {
|
|
||||||
parent.mkdirs();
|
|
||||||
}
|
|
||||||
return new FileOutputStream(localFile, append);
|
|
||||||
}
|
|
||||||
case URI_TYPE_CONTENT:
|
|
||||||
case URI_TYPE_RESOURCE: {
|
|
||||||
AssetFileDescriptor assetFd = contentResolver.openAssetFileDescriptor(uri, append ? "wa" : "w");
|
|
||||||
return assetFd.createOutputStream();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new FileNotFoundException("URI not supported by CordovaResourceApi: " + uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpURLConnection createHttpConnection(Uri uri) throws IOException {
|
|
||||||
assertBackgroundThread();
|
|
||||||
return (HttpURLConnection)new URL(uri.toString()).openConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copies the input to the output in the most efficient manner possible.
|
|
||||||
// Closes both streams.
|
|
||||||
public void copyResource(OpenForReadResult input, OutputStream outputStream) throws IOException {
|
|
||||||
assertBackgroundThread();
|
|
||||||
try {
|
|
||||||
InputStream inputStream = input.inputStream;
|
|
||||||
if (inputStream instanceof FileInputStream && outputStream instanceof FileOutputStream) {
|
|
||||||
FileChannel inChannel = ((FileInputStream)input.inputStream).getChannel();
|
|
||||||
FileChannel outChannel = ((FileOutputStream)outputStream).getChannel();
|
|
||||||
long offset = 0;
|
|
||||||
long length = input.length;
|
|
||||||
if (input.assetFd != null) {
|
|
||||||
offset = input.assetFd.getStartOffset();
|
|
||||||
}
|
|
||||||
// transferFrom()'s 2nd arg is a relative position. Need to set the absolute
|
|
||||||
// position first.
|
|
||||||
inChannel.position(offset);
|
|
||||||
outChannel.transferFrom(inChannel, 0, length);
|
|
||||||
} else {
|
|
||||||
final int BUFFER_SIZE = 8192;
|
|
||||||
byte[] buffer = new byte[BUFFER_SIZE];
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);
|
|
||||||
|
|
||||||
if (bytesRead <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
outputStream.write(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
input.inputStream.close();
|
|
||||||
if (outputStream != null) {
|
|
||||||
outputStream.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void copyResource(Uri sourceUri, OutputStream outputStream) throws IOException {
|
|
||||||
copyResource(openForRead(sourceUri), outputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Added in 3.5.0.
|
|
||||||
public void copyResource(Uri sourceUri, Uri dstUri) throws IOException {
|
|
||||||
copyResource(openForRead(sourceUri), openOutputStream(dstUri));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertBackgroundThread() {
|
|
||||||
if (threadCheckingEnabled) {
|
|
||||||
Thread curThread = Thread.currentThread();
|
|
||||||
if (curThread == Looper.getMainLooper().getThread()) {
|
|
||||||
throw new IllegalStateException("Do not perform IO operations on the UI thread. Use CordovaInterface.getThreadPool() instead.");
|
|
||||||
}
|
|
||||||
if (curThread == jsThread) {
|
|
||||||
throw new IllegalStateException("Tried to perform an IO operation on the WebCore thread. Use CordovaInterface.getThreadPool() instead.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDataUriMimeType(Uri uri) {
|
|
||||||
String uriAsString = uri.getSchemeSpecificPart();
|
|
||||||
int commaPos = uriAsString.indexOf(',');
|
|
||||||
if (commaPos == -1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String[] mimeParts = uriAsString.substring(0, commaPos).split(";");
|
|
||||||
if (mimeParts.length > 0) {
|
|
||||||
return mimeParts[0];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private OpenForReadResult readDataUri(Uri uri) {
|
|
||||||
String uriAsString = uri.getSchemeSpecificPart();
|
|
||||||
int commaPos = uriAsString.indexOf(',');
|
|
||||||
if (commaPos == -1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String[] mimeParts = uriAsString.substring(0, commaPos).split(";");
|
|
||||||
String contentType = null;
|
|
||||||
boolean base64 = false;
|
|
||||||
if (mimeParts.length > 0) {
|
|
||||||
contentType = mimeParts[0];
|
|
||||||
}
|
|
||||||
for (int i = 1; i < mimeParts.length; ++i) {
|
|
||||||
if ("base64".equalsIgnoreCase(mimeParts[i])) {
|
|
||||||
base64 = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String dataPartAsString = uriAsString.substring(commaPos + 1);
|
|
||||||
byte[] data;
|
|
||||||
if (base64) {
|
|
||||||
data = Base64.decode(dataPartAsString, Base64.DEFAULT);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
data = dataPartAsString.getBytes("UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
data = dataPartAsString.getBytes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InputStream inputStream = new ByteArrayInputStream(data);
|
|
||||||
return new OpenForReadResult(uri, inputStream, contentType, data.length, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void assertNonRelative(Uri uri) {
|
|
||||||
if (!uri.isAbsolute()) {
|
|
||||||
throw new IllegalArgumentException("Relative URIs are not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class OpenForReadResult {
|
|
||||||
public final Uri uri;
|
|
||||||
public final InputStream inputStream;
|
|
||||||
public final String mimeType;
|
|
||||||
public final long length;
|
|
||||||
public final AssetFileDescriptor assetFd;
|
|
||||||
|
|
||||||
public OpenForReadResult(Uri uri, InputStream inputStream, String mimeType, long length, AssetFileDescriptor assetFd) {
|
|
||||||
this.uri = uri;
|
|
||||||
this.inputStream = inputStream;
|
|
||||||
this.mimeType = mimeType;
|
|
||||||
this.length = length;
|
|
||||||
this.assetFd = assetFd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.webkit.WebChromeClient.CustomViewCallback;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main interface for interacting with a Cordova webview - implemented by CordovaWebViewImpl.
|
|
||||||
* This is an interface so that it can be easily mocked in tests.
|
|
||||||
* Methods may be added to this interface without a major version bump, as plugins & embedders
|
|
||||||
* are not expected to implement it.
|
|
||||||
*/
|
|
||||||
public interface CordovaWebView {
|
|
||||||
public static final String CORDOVA_VERSION = "8.0.0";
|
|
||||||
|
|
||||||
void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences);
|
|
||||||
|
|
||||||
boolean isInitialized();
|
|
||||||
|
|
||||||
View getView();
|
|
||||||
|
|
||||||
void loadUrlIntoView(String url, boolean recreatePlugins);
|
|
||||||
|
|
||||||
void stopLoading();
|
|
||||||
|
|
||||||
boolean canGoBack();
|
|
||||||
|
|
||||||
void clearCache();
|
|
||||||
|
|
||||||
/** Use parameter-less overload */
|
|
||||||
@Deprecated
|
|
||||||
void clearCache(boolean b);
|
|
||||||
|
|
||||||
void clearHistory();
|
|
||||||
|
|
||||||
boolean backHistory();
|
|
||||||
|
|
||||||
void handlePause(boolean keepRunning);
|
|
||||||
|
|
||||||
void onNewIntent(Intent intent);
|
|
||||||
|
|
||||||
void handleResume(boolean keepRunning);
|
|
||||||
|
|
||||||
void handleStart();
|
|
||||||
|
|
||||||
void handleStop();
|
|
||||||
|
|
||||||
void handleDestroy();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send JavaScript statement back to JavaScript.
|
|
||||||
*
|
|
||||||
* Deprecated (https://issues.apache.org/jira/browse/CB-6851)
|
|
||||||
* Instead of executing snippets of JS, you should use the exec bridge
|
|
||||||
* to create a Java->JS communication channel.
|
|
||||||
* To do this:
|
|
||||||
* 1. Within plugin.xml (to have your JS run before deviceready):
|
|
||||||
* <js-module><runs/></js-module>
|
|
||||||
* 2. Within your .js (call exec on start-up):
|
|
||||||
* require('cordova/channel').onCordovaReady.subscribe(function() {
|
|
||||||
* require('cordova/exec')(win, null, 'Plugin', 'method', []);
|
|
||||||
* function win(message) {
|
|
||||||
* ... process message from java here ...
|
|
||||||
* }
|
|
||||||
* });
|
|
||||||
* 3. Within your .java:
|
|
||||||
* PluginResult dataResult = new PluginResult(PluginResult.Status.OK, CODE);
|
|
||||||
* dataResult.setKeepCallback(true);
|
|
||||||
* savedCallbackContext.sendPluginResult(dataResult);
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
void sendJavascript(String statememt);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the specified URL in the Cordova webview or a new browser instance.
|
|
||||||
*
|
|
||||||
* NOTE: If openExternal is false, only whitelisted URLs can be loaded.
|
|
||||||
*
|
|
||||||
* @param url The url to load.
|
|
||||||
* @param openExternal Load url in browser instead of Cordova webview.
|
|
||||||
* @param clearHistory Clear the history stack, so new page becomes top of history
|
|
||||||
* @param params Parameters for new app
|
|
||||||
*/
|
|
||||||
void showWebPage(String url, boolean openExternal, boolean clearHistory, Map<String, Object> params);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated in 4.0.0. Use your own View-toggling logic.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
boolean isCustomViewShowing();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated in 4.0.0. Use your own View-toggling logic.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
void showCustomView(View view, CustomViewCallback callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated in 4.0.0. Use your own View-toggling logic.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
void hideCustomView();
|
|
||||||
|
|
||||||
CordovaResourceApi getResourceApi();
|
|
||||||
|
|
||||||
void setButtonPlumbedToJs(int keyCode, boolean override);
|
|
||||||
boolean isButtonPlumbedToJs(int keyCode);
|
|
||||||
|
|
||||||
void sendPluginResult(PluginResult cr, String callbackId);
|
|
||||||
|
|
||||||
PluginManager getPluginManager();
|
|
||||||
CordovaWebViewEngine getEngine();
|
|
||||||
CordovaPreferences getPreferences();
|
|
||||||
ICordovaCookieManager getCookieManager();
|
|
||||||
|
|
||||||
String getUrl();
|
|
||||||
|
|
||||||
// TODO: Work on deleting these by removing refs from plugins.
|
|
||||||
Context getContext();
|
|
||||||
void loadUrl(String url);
|
|
||||||
Object postMessage(String id, Object data);
|
|
||||||
}
|
|
||||||
@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.webkit.ValueCallback;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for all Cordova engines.
|
|
||||||
* No methods will be added to this class (in order to be compatible with existing engines).
|
|
||||||
* Instead, we will create a new interface: e.g. CordovaWebViewEngineV2
|
|
||||||
*/
|
|
||||||
public interface CordovaWebViewEngine {
|
|
||||||
void init(CordovaWebView parentWebView, CordovaInterface cordova, Client client,
|
|
||||||
CordovaResourceApi resourceApi, PluginManager pluginManager,
|
|
||||||
NativeToJsMessageQueue nativeToJsMessageQueue);
|
|
||||||
|
|
||||||
CordovaWebView getCordovaWebView();
|
|
||||||
ICordovaCookieManager getCookieManager();
|
|
||||||
View getView();
|
|
||||||
|
|
||||||
void loadUrl(String url, boolean clearNavigationStack);
|
|
||||||
|
|
||||||
void stopLoading();
|
|
||||||
|
|
||||||
/** Return the currently loaded URL */
|
|
||||||
String getUrl();
|
|
||||||
|
|
||||||
void clearCache();
|
|
||||||
|
|
||||||
/** After calling clearHistory(), canGoBack() should be false. */
|
|
||||||
void clearHistory();
|
|
||||||
|
|
||||||
boolean canGoBack();
|
|
||||||
|
|
||||||
/** Returns whether a navigation occurred */
|
|
||||||
boolean goBack();
|
|
||||||
|
|
||||||
/** Pauses / resumes the WebView's event loop. */
|
|
||||||
void setPaused(boolean value);
|
|
||||||
|
|
||||||
/** Clean up all resources associated with the WebView. */
|
|
||||||
void destroy();
|
|
||||||
|
|
||||||
/** Add the evaulate Javascript method **/
|
|
||||||
void evaluateJavascript(String js, ValueCallback<String> callback);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to retrieve the associated CordovaWebView given a View without knowing the type of Engine.
|
|
||||||
* E.g. ((CordovaWebView.EngineView)activity.findViewById(android.R.id.webView)).getCordovaWebView();
|
|
||||||
*/
|
|
||||||
public interface EngineView {
|
|
||||||
CordovaWebView getCordovaWebView();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains methods that an engine uses to communicate with the parent CordovaWebView.
|
|
||||||
* Methods may be added in future cordova versions, but never removed.
|
|
||||||
*/
|
|
||||||
public interface Client {
|
|
||||||
Boolean onDispatchKeyEvent(KeyEvent event);
|
|
||||||
void clearLoadTimeoutTimer();
|
|
||||||
void onPageStarted(String newUrl);
|
|
||||||
void onReceivedError(int errorCode, String description, String failingUrl);
|
|
||||||
void onPageFinishedLoading(String url);
|
|
||||||
boolean onNavigationAttempt(String url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,617 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.webkit.WebChromeClient;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
|
|
||||||
import org.apache.cordova.engine.SystemWebViewEngine;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main class for interacting with a Cordova webview. Manages plugins, events, and a CordovaWebViewEngine.
|
|
||||||
* Class uses two-phase initialization. You must call init() before calling any other methods.
|
|
||||||
*/
|
|
||||||
public class CordovaWebViewImpl implements CordovaWebView {
|
|
||||||
|
|
||||||
public static final String TAG = "CordovaWebViewImpl";
|
|
||||||
|
|
||||||
private PluginManager pluginManager;
|
|
||||||
|
|
||||||
protected final CordovaWebViewEngine engine;
|
|
||||||
private CordovaInterface cordova;
|
|
||||||
|
|
||||||
// Flag to track that a loadUrl timeout occurred
|
|
||||||
private int loadUrlTimeout = 0;
|
|
||||||
|
|
||||||
private CordovaResourceApi resourceApi;
|
|
||||||
private CordovaPreferences preferences;
|
|
||||||
private CoreAndroid appPlugin;
|
|
||||||
private NativeToJsMessageQueue nativeToJsMessageQueue;
|
|
||||||
private EngineClient engineClient = new EngineClient();
|
|
||||||
private boolean hasPausedEver;
|
|
||||||
|
|
||||||
// The URL passed to loadUrl(), not necessarily the URL of the current page.
|
|
||||||
String loadedUrl;
|
|
||||||
|
|
||||||
/** custom view created by the browser (a video player for example) */
|
|
||||||
private View mCustomView;
|
|
||||||
private WebChromeClient.CustomViewCallback mCustomViewCallback;
|
|
||||||
|
|
||||||
private Set<Integer> boundKeyCodes = new HashSet<Integer>();
|
|
||||||
|
|
||||||
public static CordovaWebViewEngine createEngine(Context context, CordovaPreferences preferences) {
|
|
||||||
String className = preferences.getString("webview", SystemWebViewEngine.class.getCanonicalName());
|
|
||||||
try {
|
|
||||||
Class<?> webViewClass = Class.forName(className);
|
|
||||||
Constructor<?> constructor = webViewClass.getConstructor(Context.class, CordovaPreferences.class);
|
|
||||||
return (CordovaWebViewEngine) constructor.newInstance(context, preferences);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Failed to create webview. ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CordovaWebViewImpl(CordovaWebViewEngine cordovaWebViewEngine) {
|
|
||||||
this.engine = cordovaWebViewEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convenience method for when creating programmatically (not from Config.xml).
|
|
||||||
public void init(CordovaInterface cordova) {
|
|
||||||
init(cordova, new ArrayList<PluginEntry>(), new CordovaPreferences());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("Assert")
|
|
||||||
@Override
|
|
||||||
public void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences) {
|
|
||||||
if (this.cordova != null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
this.cordova = cordova;
|
|
||||||
this.preferences = preferences;
|
|
||||||
pluginManager = new PluginManager(this, this.cordova, pluginEntries);
|
|
||||||
resourceApi = new CordovaResourceApi(engine.getView().getContext(), pluginManager);
|
|
||||||
nativeToJsMessageQueue = new NativeToJsMessageQueue();
|
|
||||||
nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.NoOpBridgeMode());
|
|
||||||
nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.LoadUrlBridgeMode(engine, cordova));
|
|
||||||
|
|
||||||
if (preferences.getBoolean("DisallowOverscroll", false)) {
|
|
||||||
engine.getView().setOverScrollMode(View.OVER_SCROLL_NEVER);
|
|
||||||
}
|
|
||||||
engine.init(this, cordova, engineClient, resourceApi, pluginManager, nativeToJsMessageQueue);
|
|
||||||
// This isn't enforced by the compiler, so assert here.
|
|
||||||
assert engine.getView() instanceof CordovaWebViewEngine.EngineView;
|
|
||||||
|
|
||||||
pluginManager.addService(CoreAndroid.PLUGIN_NAME, "org.apache.cordova.CoreAndroid");
|
|
||||||
pluginManager.init();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isInitialized() {
|
|
||||||
return cordova != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void loadUrlIntoView(final String url, boolean recreatePlugins) {
|
|
||||||
LOG.d(TAG, ">>> loadUrl(" + url + ")");
|
|
||||||
if (url.equals("about:blank") || url.startsWith("javascript:")) {
|
|
||||||
engine.loadUrl(url, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
recreatePlugins = recreatePlugins || (loadedUrl == null);
|
|
||||||
|
|
||||||
if (recreatePlugins) {
|
|
||||||
// Don't re-initialize on first load.
|
|
||||||
if (loadedUrl != null) {
|
|
||||||
appPlugin = null;
|
|
||||||
pluginManager.init();
|
|
||||||
}
|
|
||||||
loadedUrl = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a timeout timer for loadUrl
|
|
||||||
final int currentLoadUrlTimeout = loadUrlTimeout;
|
|
||||||
final int loadUrlTimeoutValue = preferences.getInteger("LoadUrlTimeoutValue", 20000);
|
|
||||||
|
|
||||||
// Timeout error method
|
|
||||||
final Runnable loadError = new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
stopLoading();
|
|
||||||
LOG.e(TAG, "CordovaWebView: TIMEOUT ERROR!");
|
|
||||||
|
|
||||||
// Handle other errors by passing them to the webview in JS
|
|
||||||
JSONObject data = new JSONObject();
|
|
||||||
try {
|
|
||||||
data.put("errorCode", -6);
|
|
||||||
data.put("description", "The connection to the server was unsuccessful.");
|
|
||||||
data.put("url", url);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
// Will never happen.
|
|
||||||
}
|
|
||||||
pluginManager.postMessage("onReceivedError", data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Timeout timer method
|
|
||||||
final Runnable timeoutCheck = new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
synchronized (this) {
|
|
||||||
wait(loadUrlTimeoutValue);
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If timeout, then stop loading and handle error
|
|
||||||
if (loadUrlTimeout == currentLoadUrlTimeout) {
|
|
||||||
cordova.getActivity().runOnUiThread(loadError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final boolean _recreatePlugins = recreatePlugins;
|
|
||||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
if (loadUrlTimeoutValue > 0) {
|
|
||||||
cordova.getThreadPool().execute(timeoutCheck);
|
|
||||||
}
|
|
||||||
engine.loadUrl(url, _recreatePlugins);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void loadUrl(String url) {
|
|
||||||
loadUrlIntoView(url, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showWebPage(String url, boolean openExternal, boolean clearHistory, Map<String, Object> params) {
|
|
||||||
LOG.d(TAG, "showWebPage(%s, %b, %b, HashMap)", url, openExternal, clearHistory);
|
|
||||||
|
|
||||||
// If clearing history
|
|
||||||
if (clearHistory) {
|
|
||||||
engine.clearHistory();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If loading into our webview
|
|
||||||
if (!openExternal) {
|
|
||||||
// Make sure url is in whitelist
|
|
||||||
if (pluginManager.shouldAllowNavigation(url)) {
|
|
||||||
// TODO: What about params?
|
|
||||||
// Load new URL
|
|
||||||
loadUrlIntoView(url, true);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
LOG.w(TAG, "showWebPage: Refusing to load URL into webview since it is not in the <allow-navigation> whitelist. URL=" + url);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!pluginManager.shouldOpenExternalUrl(url)) {
|
|
||||||
LOG.w(TAG, "showWebPage: Refusing to send intent for URL since it is not in the <allow-intent> whitelist. URL=" + url);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
||||||
// To send an intent without CATEGORY_BROWSER, a custom plugin should be used.
|
|
||||||
intent.addCategory(Intent.CATEGORY_BROWSABLE);
|
|
||||||
Uri uri = Uri.parse(url);
|
|
||||||
// Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
|
|
||||||
// Adding the MIME type to http: URLs causes them to not be handled by the downloader.
|
|
||||||
if ("file".equals(uri.getScheme())) {
|
|
||||||
intent.setDataAndType(uri, resourceApi.getMimeType(uri));
|
|
||||||
} else {
|
|
||||||
intent.setData(uri);
|
|
||||||
}
|
|
||||||
cordova.getActivity().startActivity(intent);
|
|
||||||
} catch (android.content.ActivityNotFoundException e) {
|
|
||||||
LOG.e(TAG, "Error loading url " + url, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {
|
|
||||||
// This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
|
|
||||||
LOG.d(TAG, "showing Custom View");
|
|
||||||
// if a view already exists then immediately terminate the new one
|
|
||||||
if (mCustomView != null) {
|
|
||||||
callback.onCustomViewHidden();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the view and its callback for later (to kill it properly)
|
|
||||||
mCustomView = view;
|
|
||||||
mCustomViewCallback = callback;
|
|
||||||
|
|
||||||
// Add the custom view to its container.
|
|
||||||
ViewGroup parent = (ViewGroup) engine.getView().getParent();
|
|
||||||
parent.addView(view, new FrameLayout.LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
Gravity.CENTER));
|
|
||||||
|
|
||||||
// Hide the content view.
|
|
||||||
engine.getView().setVisibility(View.GONE);
|
|
||||||
|
|
||||||
// Finally show the custom view container.
|
|
||||||
parent.setVisibility(View.VISIBLE);
|
|
||||||
parent.bringToFront();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public void hideCustomView() {
|
|
||||||
// This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
|
|
||||||
if (mCustomView == null) return;
|
|
||||||
LOG.d(TAG, "Hiding Custom View");
|
|
||||||
|
|
||||||
// Hide the custom view.
|
|
||||||
mCustomView.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
// Remove the custom view from its container.
|
|
||||||
ViewGroup parent = (ViewGroup) engine.getView().getParent();
|
|
||||||
parent.removeView(mCustomView);
|
|
||||||
mCustomView = null;
|
|
||||||
mCustomViewCallback.onCustomViewHidden();
|
|
||||||
|
|
||||||
// Show the content view.
|
|
||||||
engine.getView().setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public boolean isCustomViewShowing() {
|
|
||||||
return mCustomView != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public void sendJavascript(String statement) {
|
|
||||||
nativeToJsMessageQueue.addJavaScript(statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendPluginResult(PluginResult cr, String callbackId) {
|
|
||||||
nativeToJsMessageQueue.addPluginResult(cr, callbackId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PluginManager getPluginManager() {
|
|
||||||
return pluginManager;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public CordovaPreferences getPreferences() {
|
|
||||||
return preferences;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public ICordovaCookieManager getCookieManager() {
|
|
||||||
return engine.getCookieManager();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public CordovaResourceApi getResourceApi() {
|
|
||||||
return resourceApi;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public CordovaWebViewEngine getEngine() {
|
|
||||||
return engine;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public View getView() {
|
|
||||||
return engine.getView();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public Context getContext() {
|
|
||||||
return engine.getView().getContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendJavascriptEvent(String event) {
|
|
||||||
if (appPlugin == null) {
|
|
||||||
appPlugin = (CoreAndroid)pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appPlugin == null) {
|
|
||||||
LOG.w(TAG, "Unable to fire event without existing plugin");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
appPlugin.fireJavascriptEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setButtonPlumbedToJs(int keyCode, boolean override) {
|
|
||||||
switch (keyCode) {
|
|
||||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
|
||||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
|
||||||
case KeyEvent.KEYCODE_BACK:
|
|
||||||
case KeyEvent.KEYCODE_MENU:
|
|
||||||
// TODO: Why are search and menu buttons handled separately?
|
|
||||||
if (override) {
|
|
||||||
boundKeyCodes.add(keyCode);
|
|
||||||
} else {
|
|
||||||
boundKeyCodes.remove(keyCode);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isButtonPlumbedToJs(int keyCode) {
|
|
||||||
return boundKeyCodes.contains(keyCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object postMessage(String id, Object data) {
|
|
||||||
return pluginManager.postMessage(id, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Engine method proxies:
|
|
||||||
@Override
|
|
||||||
public String getUrl() {
|
|
||||||
return engine.getUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stopLoading() {
|
|
||||||
// Clear timeout flag
|
|
||||||
loadUrlTimeout++;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canGoBack() {
|
|
||||||
return engine.canGoBack();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearCache() {
|
|
||||||
engine.clearCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public void clearCache(boolean b) {
|
|
||||||
engine.clearCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearHistory() {
|
|
||||||
engine.clearHistory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean backHistory() {
|
|
||||||
return engine.goBack();
|
|
||||||
}
|
|
||||||
|
|
||||||
/////// LifeCycle methods ///////
|
|
||||||
@Override
|
|
||||||
public void onNewIntent(Intent intent) {
|
|
||||||
if (this.pluginManager != null) {
|
|
||||||
this.pluginManager.onNewIntent(intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void handlePause(boolean keepRunning) {
|
|
||||||
if (!isInitialized()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
hasPausedEver = true;
|
|
||||||
pluginManager.onPause(keepRunning);
|
|
||||||
sendJavascriptEvent("pause");
|
|
||||||
|
|
||||||
// If app doesn't want to run in background
|
|
||||||
if (!keepRunning) {
|
|
||||||
// Pause JavaScript timers. This affects all webviews within the app!
|
|
||||||
engine.setPaused(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void handleResume(boolean keepRunning) {
|
|
||||||
if (!isInitialized()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resume JavaScript timers. This affects all webviews within the app!
|
|
||||||
engine.setPaused(false);
|
|
||||||
this.pluginManager.onResume(keepRunning);
|
|
||||||
|
|
||||||
// In order to match the behavior of the other platforms, we only send onResume after an
|
|
||||||
// onPause has occurred. The resume event might still be sent if the Activity was killed
|
|
||||||
// while waiting for the result of an external Activity once the result is obtained
|
|
||||||
if (hasPausedEver) {
|
|
||||||
sendJavascriptEvent("resume");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void handleStart() {
|
|
||||||
if (!isInitialized()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pluginManager.onStart();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void handleStop() {
|
|
||||||
if (!isInitialized()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pluginManager.onStop();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void handleDestroy() {
|
|
||||||
if (!isInitialized()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Cancel pending timeout timer.
|
|
||||||
loadUrlTimeout++;
|
|
||||||
|
|
||||||
// Forward to plugins
|
|
||||||
this.pluginManager.onDestroy();
|
|
||||||
|
|
||||||
// TODO: about:blank is a bit special (and the default URL for new frames)
|
|
||||||
// We should use a blank data: url instead so it's more obvious
|
|
||||||
this.loadUrl("about:blank");
|
|
||||||
|
|
||||||
// TODO: Should not destroy webview until after about:blank is done loading.
|
|
||||||
engine.destroy();
|
|
||||||
hideCustomView();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class EngineClient implements CordovaWebViewEngine.Client {
|
|
||||||
@Override
|
|
||||||
public void clearLoadTimeoutTimer() {
|
|
||||||
loadUrlTimeout++;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPageStarted(String newUrl) {
|
|
||||||
LOG.d(TAG, "onPageDidNavigate(" + newUrl + ")");
|
|
||||||
boundKeyCodes.clear();
|
|
||||||
pluginManager.onReset();
|
|
||||||
pluginManager.postMessage("onPageStarted", newUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceivedError(int errorCode, String description, String failingUrl) {
|
|
||||||
clearLoadTimeoutTimer();
|
|
||||||
JSONObject data = new JSONObject();
|
|
||||||
try {
|
|
||||||
data.put("errorCode", errorCode);
|
|
||||||
data.put("description", description);
|
|
||||||
data.put("url", failingUrl);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
pluginManager.postMessage("onReceivedError", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPageFinishedLoading(String url) {
|
|
||||||
LOG.d(TAG, "onPageFinished(" + url + ")");
|
|
||||||
|
|
||||||
clearLoadTimeoutTimer();
|
|
||||||
|
|
||||||
// Broadcast message that page has loaded
|
|
||||||
pluginManager.postMessage("onPageFinished", url);
|
|
||||||
|
|
||||||
// Make app visible after 2 sec in case there was a JS error and Cordova JS never initialized correctly
|
|
||||||
if (engine.getView().getVisibility() != View.VISIBLE) {
|
|
||||||
Thread t = new Thread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
Thread.sleep(2000);
|
|
||||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
pluginManager.postMessage("spinner", "stop");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
t.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shutdown if blank loaded
|
|
||||||
if (url.equals("about:blank")) {
|
|
||||||
pluginManager.postMessage("exit", null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean onDispatchKeyEvent(KeyEvent event) {
|
|
||||||
int keyCode = event.getKeyCode();
|
|
||||||
boolean isBackButton = keyCode == KeyEvent.KEYCODE_BACK;
|
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
||||||
if (isBackButton && mCustomView != null) {
|
|
||||||
return true;
|
|
||||||
} else if (boundKeyCodes.contains(keyCode)) {
|
|
||||||
return true;
|
|
||||||
} else if (isBackButton) {
|
|
||||||
return engine.canGoBack();
|
|
||||||
}
|
|
||||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
|
||||||
if (isBackButton && mCustomView != null) {
|
|
||||||
hideCustomView();
|
|
||||||
return true;
|
|
||||||
} else if (boundKeyCodes.contains(keyCode)) {
|
|
||||||
String eventName = null;
|
|
||||||
switch (keyCode) {
|
|
||||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
|
||||||
eventName = "volumedownbutton";
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
|
||||||
eventName = "volumeupbutton";
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_SEARCH:
|
|
||||||
eventName = "searchbutton";
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_MENU:
|
|
||||||
eventName = "menubutton";
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_BACK:
|
|
||||||
eventName = "backbutton";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (eventName != null) {
|
|
||||||
sendJavascriptEvent(eventName);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (isBackButton) {
|
|
||||||
return engine.goBack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onNavigationAttempt(String url) {
|
|
||||||
// Give plugins the chance to handle the url
|
|
||||||
if (pluginManager.onOverrideUrlLoading(url)) {
|
|
||||||
return true;
|
|
||||||
} else if (pluginManager.shouldAllowNavigation(url)) {
|
|
||||||
return false;
|
|
||||||
} else if (pluginManager.shouldOpenExternalUrl(url)) {
|
|
||||||
showWebPage(url, true, false, null);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
LOG.w(TAG, "Blocked (possibly sub-frame) navigation to non-allowed URL: " + url);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,407 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.telephony.TelephonyManager;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class exposes methods in Cordova that can be called from JavaScript.
|
|
||||||
*/
|
|
||||||
public class CoreAndroid extends CordovaPlugin {
|
|
||||||
|
|
||||||
public static final String PLUGIN_NAME = "CoreAndroid";
|
|
||||||
protected static final String TAG = "CordovaApp";
|
|
||||||
private BroadcastReceiver telephonyReceiver;
|
|
||||||
private CallbackContext messageChannel;
|
|
||||||
private PluginResult pendingResume;
|
|
||||||
private PluginResult pendingPause;
|
|
||||||
private final Object messageChannelLock = new Object();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an event to be fired on the Javascript side.
|
|
||||||
*
|
|
||||||
* @param action The name of the event to be fired
|
|
||||||
*/
|
|
||||||
public void fireJavascriptEvent(String action) {
|
|
||||||
sendEventMessage(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the context of the Command. This can then be used to do things like
|
|
||||||
* get file paths associated with the Activity.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void pluginInitialize() {
|
|
||||||
this.initTelephonyReceiver();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the request and returns PluginResult.
|
|
||||||
*
|
|
||||||
* @param action The action to execute.
|
|
||||||
* @param args JSONArry of arguments for the plugin.
|
|
||||||
* @param callbackContext The callback context from which we were invoked.
|
|
||||||
* @return A PluginResult object with a status and message.
|
|
||||||
*/
|
|
||||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
|
||||||
PluginResult.Status status = PluginResult.Status.OK;
|
|
||||||
String result = "";
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (action.equals("clearCache")) {
|
|
||||||
this.clearCache();
|
|
||||||
}
|
|
||||||
else if (action.equals("show")) {
|
|
||||||
// This gets called from JavaScript onCordovaReady to show the webview.
|
|
||||||
// I recommend we change the name of the Message as spinner/stop is not
|
|
||||||
// indicative of what this actually does (shows the webview).
|
|
||||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
webView.getPluginManager().postMessage("spinner", "stop");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (action.equals("loadUrl")) {
|
|
||||||
this.loadUrl(args.getString(0), args.optJSONObject(1));
|
|
||||||
}
|
|
||||||
else if (action.equals("cancelLoadUrl")) {
|
|
||||||
//this.cancelLoadUrl();
|
|
||||||
}
|
|
||||||
else if (action.equals("clearHistory")) {
|
|
||||||
this.clearHistory();
|
|
||||||
}
|
|
||||||
else if (action.equals("backHistory")) {
|
|
||||||
this.backHistory();
|
|
||||||
}
|
|
||||||
else if (action.equals("overrideButton")) {
|
|
||||||
this.overrideButton(args.getString(0), args.getBoolean(1));
|
|
||||||
}
|
|
||||||
else if (action.equals("overrideBackbutton")) {
|
|
||||||
this.overrideBackbutton(args.getBoolean(0));
|
|
||||||
}
|
|
||||||
else if (action.equals("exitApp")) {
|
|
||||||
this.exitApp();
|
|
||||||
}
|
|
||||||
else if (action.equals("messageChannel")) {
|
|
||||||
synchronized(messageChannelLock) {
|
|
||||||
messageChannel = callbackContext;
|
|
||||||
if (pendingPause != null) {
|
|
||||||
sendEventMessage(pendingPause);
|
|
||||||
pendingPause = null;
|
|
||||||
}
|
|
||||||
if (pendingResume != null) {
|
|
||||||
sendEventMessage(pendingResume);
|
|
||||||
pendingResume = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
callbackContext.sendPluginResult(new PluginResult(status, result));
|
|
||||||
return true;
|
|
||||||
} catch (JSONException e) {
|
|
||||||
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// LOCAL METHODS
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the resource cache.
|
|
||||||
*/
|
|
||||||
public void clearCache() {
|
|
||||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
webView.clearCache();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the url into the webview.
|
|
||||||
*
|
|
||||||
* @param url
|
|
||||||
* @param props Properties that can be passed in to the Cordova activity (i.e. loadingDialog, wait, ...)
|
|
||||||
* @throws JSONException
|
|
||||||
*/
|
|
||||||
public void loadUrl(String url, JSONObject props) throws JSONException {
|
|
||||||
LOG.d("App", "App.loadUrl("+url+","+props+")");
|
|
||||||
int wait = 0;
|
|
||||||
boolean openExternal = false;
|
|
||||||
boolean clearHistory = false;
|
|
||||||
|
|
||||||
// If there are properties, then set them on the Activity
|
|
||||||
HashMap<String, Object> params = new HashMap<String, Object>();
|
|
||||||
if (props != null) {
|
|
||||||
JSONArray keys = props.names();
|
|
||||||
for (int i = 0; i < keys.length(); i++) {
|
|
||||||
String key = keys.getString(i);
|
|
||||||
if (key.equals("wait")) {
|
|
||||||
wait = props.getInt(key);
|
|
||||||
}
|
|
||||||
else if (key.equalsIgnoreCase("openexternal")) {
|
|
||||||
openExternal = props.getBoolean(key);
|
|
||||||
}
|
|
||||||
else if (key.equalsIgnoreCase("clearhistory")) {
|
|
||||||
clearHistory = props.getBoolean(key);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Object value = props.get(key);
|
|
||||||
if (value == null) {
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (value.getClass().equals(String.class)) {
|
|
||||||
params.put(key, (String)value);
|
|
||||||
}
|
|
||||||
else if (value.getClass().equals(Boolean.class)) {
|
|
||||||
params.put(key, (Boolean)value);
|
|
||||||
}
|
|
||||||
else if (value.getClass().equals(Integer.class)) {
|
|
||||||
params.put(key, (Integer)value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If wait property, then delay loading
|
|
||||||
|
|
||||||
if (wait > 0) {
|
|
||||||
try {
|
|
||||||
synchronized(this) {
|
|
||||||
this.wait(wait);
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.webView.showWebPage(url, openExternal, clearHistory, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear page history for the app.
|
|
||||||
*/
|
|
||||||
public void clearHistory() {
|
|
||||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
webView.clearHistory();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Go to previous page displayed.
|
|
||||||
* This is the same as pressing the backbutton on Android device.
|
|
||||||
*/
|
|
||||||
public void backHistory() {
|
|
||||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
webView.backHistory();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override the default behavior of the Android back button.
|
|
||||||
* If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
|
|
||||||
*
|
|
||||||
* @param override T=override, F=cancel override
|
|
||||||
*/
|
|
||||||
public void overrideBackbutton(boolean override) {
|
|
||||||
LOG.i("App", "WARNING: Back Button Default Behavior will be overridden. The backbutton event will be fired!");
|
|
||||||
webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override the default behavior of the Android volume buttons.
|
|
||||||
* If overridden, when the volume button is pressed, the "volume[up|down]button" JavaScript event will be fired.
|
|
||||||
*
|
|
||||||
* @param button volumeup, volumedown
|
|
||||||
* @param override T=override, F=cancel override
|
|
||||||
*/
|
|
||||||
public void overrideButton(String button, boolean override) {
|
|
||||||
LOG.i("App", "WARNING: Volume Button Default Behavior will be overridden. The volume event will be fired!");
|
|
||||||
if (button.equals("volumeup")) {
|
|
||||||
webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
|
|
||||||
}
|
|
||||||
else if (button.equals("volumedown")) {
|
|
||||||
webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
|
|
||||||
}
|
|
||||||
else if (button.equals("menubutton")) {
|
|
||||||
webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_MENU, override);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether the Android back button is overridden by the user.
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public boolean isBackbuttonOverridden() {
|
|
||||||
return webView.isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exit the Android application.
|
|
||||||
*/
|
|
||||||
public void exitApp() {
|
|
||||||
this.webView.getPluginManager().postMessage("exit", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listen for telephony events: RINGING, OFFHOOK and IDLE
|
|
||||||
* Send these events to all plugins using
|
|
||||||
* CordovaActivity.onMessage("telephone", "ringing" | "offhook" | "idle")
|
|
||||||
*/
|
|
||||||
private void initTelephonyReceiver() {
|
|
||||||
IntentFilter intentFilter = new IntentFilter();
|
|
||||||
intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
|
|
||||||
//final CordovaInterface mycordova = this.cordova;
|
|
||||||
this.telephonyReceiver = new BroadcastReceiver() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
|
|
||||||
// If state has changed
|
|
||||||
if ((intent != null) && intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
|
|
||||||
if (intent.hasExtra(TelephonyManager.EXTRA_STATE)) {
|
|
||||||
String extraData = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
|
|
||||||
if (extraData.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
|
|
||||||
LOG.i(TAG, "Telephone RINGING");
|
|
||||||
webView.getPluginManager().postMessage("telephone", "ringing");
|
|
||||||
}
|
|
||||||
else if (extraData.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
|
|
||||||
LOG.i(TAG, "Telephone OFFHOOK");
|
|
||||||
webView.getPluginManager().postMessage("telephone", "offhook");
|
|
||||||
}
|
|
||||||
else if (extraData.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
|
|
||||||
LOG.i(TAG, "Telephone IDLE");
|
|
||||||
webView.getPluginManager().postMessage("telephone", "idle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register the receiver
|
|
||||||
webView.getContext().registerReceiver(this.telephonyReceiver, intentFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendEventMessage(String action) {
|
|
||||||
JSONObject obj = new JSONObject();
|
|
||||||
try {
|
|
||||||
obj.put("action", action);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
LOG.e(TAG, "Failed to create event message", e);
|
|
||||||
}
|
|
||||||
PluginResult result = new PluginResult(PluginResult.Status.OK, obj);
|
|
||||||
|
|
||||||
if (messageChannel == null) {
|
|
||||||
LOG.i(TAG, "Request to send event before messageChannel initialised: " + action);
|
|
||||||
if ("pause".equals(action)) {
|
|
||||||
pendingPause = result;
|
|
||||||
} else if ("resume".equals(action)) {
|
|
||||||
// When starting normally onPause then onResume is called
|
|
||||||
pendingPause = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sendEventMessage(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendEventMessage(PluginResult payload) {
|
|
||||||
payload.setKeepCallback(true);
|
|
||||||
if (messageChannel != null) {
|
|
||||||
messageChannel.sendPluginResult(payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Unregister the receiver
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void onDestroy()
|
|
||||||
{
|
|
||||||
webView.getContext().unregisterReceiver(this.telephonyReceiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to send the resume event in the case that the Activity is destroyed by the OS
|
|
||||||
*
|
|
||||||
* @param resumeEvent PluginResult containing the payload for the resume event to be fired
|
|
||||||
*/
|
|
||||||
public void sendResumeEvent(PluginResult resumeEvent) {
|
|
||||||
// This operation must be synchronized because plugin results that trigger resume
|
|
||||||
// events can be processed asynchronously
|
|
||||||
synchronized(messageChannelLock) {
|
|
||||||
if (messageChannel != null) {
|
|
||||||
sendEventMessage(resumeEvent);
|
|
||||||
} else {
|
|
||||||
// Might get called before the page loads, so we need to store it until the
|
|
||||||
// messageChannel gets created
|
|
||||||
this.pendingResume = resumeEvent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This needs to be implemented if you wish to use the Camera Plugin or other plugins
|
|
||||||
* that read the Build Configuration.
|
|
||||||
*
|
|
||||||
* Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to
|
|
||||||
* StackOverflow. This is annoying as hell!
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static Object getBuildConfigValue(Context ctx, String key)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Class<?> clazz = Class.forName(ctx.getPackageName() + ".BuildConfig");
|
|
||||||
Field field = clazz.getField(key);
|
|
||||||
return field.get(null);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
LOG.d(TAG, "Unable to get the BuildConfig, is this built with ANT?");
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (NoSuchFieldException e) {
|
|
||||||
LOG.d(TAG, key + " is not a valid field. Check your build.gradle");
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
LOG.d(TAG, "Illegal Access Exception: Let's print a stack trace.");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Any exposed Javascript API MUST implement these three things!
|
|
||||||
*/
|
|
||||||
public interface ExposedJsApi {
|
|
||||||
public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException;
|
|
||||||
public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException;
|
|
||||||
public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException;
|
|
||||||
}
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies interface for handling certificate requests.
|
|
||||||
*/
|
|
||||||
public interface ICordovaClientCertRequest {
|
|
||||||
/**
|
|
||||||
* Cancel this request
|
|
||||||
*/
|
|
||||||
public void cancel();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the host name of the server requesting the certificate.
|
|
||||||
*/
|
|
||||||
public String getHost();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the acceptable types of asymmetric keys (can be null).
|
|
||||||
*/
|
|
||||||
public String[] getKeyTypes();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the port number of the server requesting the certificate.
|
|
||||||
*/
|
|
||||||
public int getPort();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the acceptable certificate issuers for the certificate matching the private key (can be null).
|
|
||||||
*/
|
|
||||||
public Principal[] getPrincipals();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ignore the request for now. Do not remember user's choice.
|
|
||||||
*/
|
|
||||||
public void ignore();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Proceed with the specified private key and client certificate chain. Remember the user's positive choice and use it for future requests.
|
|
||||||
*
|
|
||||||
* @param privateKey The privateKey
|
|
||||||
* @param chain The certificate chain
|
|
||||||
*/
|
|
||||||
public void proceed(PrivateKey privateKey, X509Certificate[] chain);
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
public interface ICordovaCookieManager {
|
|
||||||
|
|
||||||
public void setCookiesEnabled(boolean accept);
|
|
||||||
|
|
||||||
public void setCookie(final String url, final String value);
|
|
||||||
|
|
||||||
public String getCookie(final String url);
|
|
||||||
|
|
||||||
public void clearCookies();
|
|
||||||
|
|
||||||
public void flush();
|
|
||||||
};
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies interface for HTTP auth handler object which is used to handle auth requests and
|
|
||||||
* specifying user credentials.
|
|
||||||
*/
|
|
||||||
public interface ICordovaHttpAuthHandler {
|
|
||||||
/**
|
|
||||||
* Instructs the WebView to cancel the authentication request.
|
|
||||||
*/
|
|
||||||
public void cancel ();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instructs the WebView to proceed with the authentication with the given credentials.
|
|
||||||
*
|
|
||||||
* @param username The user name
|
|
||||||
* @param password The password
|
|
||||||
*/
|
|
||||||
public void proceed (String username, String password);
|
|
||||||
}
|
|
||||||
@ -1,244 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log to Android logging system.
|
|
||||||
*
|
|
||||||
* Log message can be a string or a printf formatted string with arguments.
|
|
||||||
* See http://developer.android.com/reference/java/util/Formatter.html
|
|
||||||
*/
|
|
||||||
public class LOG {
|
|
||||||
|
|
||||||
public static final int VERBOSE = Log.VERBOSE;
|
|
||||||
public static final int DEBUG = Log.DEBUG;
|
|
||||||
public static final int INFO = Log.INFO;
|
|
||||||
public static final int WARN = Log.WARN;
|
|
||||||
public static final int ERROR = Log.ERROR;
|
|
||||||
|
|
||||||
// Current log level
|
|
||||||
public static int LOGLEVEL = Log.ERROR;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the current log level.
|
|
||||||
*
|
|
||||||
* @param logLevel
|
|
||||||
*/
|
|
||||||
public static void setLogLevel(int logLevel) {
|
|
||||||
LOGLEVEL = logLevel;
|
|
||||||
Log.i("CordovaLog", "Changing log level to " + logLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the current log level.
|
|
||||||
*
|
|
||||||
* @param logLevel
|
|
||||||
*/
|
|
||||||
public static void setLogLevel(String logLevel) {
|
|
||||||
if ("VERBOSE".equals(logLevel)) LOGLEVEL = VERBOSE;
|
|
||||||
else if ("DEBUG".equals(logLevel)) LOGLEVEL = DEBUG;
|
|
||||||
else if ("INFO".equals(logLevel)) LOGLEVEL = INFO;
|
|
||||||
else if ("WARN".equals(logLevel)) LOGLEVEL = WARN;
|
|
||||||
else if ("ERROR".equals(logLevel)) LOGLEVEL = ERROR;
|
|
||||||
Log.i("CordovaLog", "Changing log level to " + logLevel + "(" + LOGLEVEL + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if log level will be logged
|
|
||||||
*
|
|
||||||
* @param logLevel
|
|
||||||
* @return true if the parameter passed in is greater than or equal to the current log level
|
|
||||||
*/
|
|
||||||
public static boolean isLoggable(int logLevel) {
|
|
||||||
return (logLevel >= LOGLEVEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verbose log message.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
*/
|
|
||||||
public static void v(String tag, String s) {
|
|
||||||
if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Debug log message.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
*/
|
|
||||||
public static void d(String tag, String s) {
|
|
||||||
if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Info log message.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
*/
|
|
||||||
public static void i(String tag, String s) {
|
|
||||||
if (LOG.INFO >= LOGLEVEL) Log.i(tag, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Warning log message.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
*/
|
|
||||||
public static void w(String tag, String s) {
|
|
||||||
if (LOG.WARN >= LOGLEVEL) Log.w(tag, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error log message.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
*/
|
|
||||||
public static void e(String tag, String s) {
|
|
||||||
if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verbose log message.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
* @param e
|
|
||||||
*/
|
|
||||||
public static void v(String tag, String s, Throwable e) {
|
|
||||||
if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, s, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Debug log message.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
* @param e
|
|
||||||
*/
|
|
||||||
public static void d(String tag, String s, Throwable e) {
|
|
||||||
if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, s, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Info log message.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
* @param e
|
|
||||||
*/
|
|
||||||
public static void i(String tag, String s, Throwable e) {
|
|
||||||
if (LOG.INFO >= LOGLEVEL) Log.i(tag, s, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Warning log message.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param e
|
|
||||||
*/
|
|
||||||
public static void w(String tag, Throwable e) {
|
|
||||||
if (LOG.WARN >= LOGLEVEL) Log.w(tag, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Warning log message.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
* @param e
|
|
||||||
*/
|
|
||||||
public static void w(String tag, String s, Throwable e) {
|
|
||||||
if (LOG.WARN >= LOGLEVEL) Log.w(tag, s, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error log message.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
* @param e
|
|
||||||
*/
|
|
||||||
public static void e(String tag, String s, Throwable e) {
|
|
||||||
if (LOG.ERROR >= LOGLEVEL) Log.e(tag, s, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verbose log message with printf formatting.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
* @param args
|
|
||||||
*/
|
|
||||||
public static void v(String tag, String s, Object... args) {
|
|
||||||
if (LOG.VERBOSE >= LOGLEVEL) Log.v(tag, String.format(s, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Debug log message with printf formatting.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
* @param args
|
|
||||||
*/
|
|
||||||
public static void d(String tag, String s, Object... args) {
|
|
||||||
if (LOG.DEBUG >= LOGLEVEL) Log.d(tag, String.format(s, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Info log message with printf formatting.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
* @param args
|
|
||||||
*/
|
|
||||||
public static void i(String tag, String s, Object... args) {
|
|
||||||
if (LOG.INFO >= LOGLEVEL) Log.i(tag, String.format(s, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Warning log message with printf formatting.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
* @param args
|
|
||||||
*/
|
|
||||||
public static void w(String tag, String s, Object... args) {
|
|
||||||
if (LOG.WARN >= LOGLEVEL) Log.w(tag, String.format(s, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error log message with printf formatting.
|
|
||||||
*
|
|
||||||
* @param tag
|
|
||||||
* @param s
|
|
||||||
* @param args
|
|
||||||
*/
|
|
||||||
public static void e(String tag, String s, Object... args) {
|
|
||||||
if (LOG.ERROR >= LOGLEVEL) Log.e(tag, String.format(s, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,542 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds the list of messages to be sent to the WebView.
|
|
||||||
*/
|
|
||||||
public class NativeToJsMessageQueue {
|
|
||||||
private static final String LOG_TAG = "JsMessageQueue";
|
|
||||||
|
|
||||||
// Set this to true to force plugin results to be encoding as
|
|
||||||
// JS instead of the custom format (useful for benchmarking).
|
|
||||||
// Doesn't work for multipart messages.
|
|
||||||
private static final boolean FORCE_ENCODE_USING_EVAL = false;
|
|
||||||
|
|
||||||
// Disable sending back native->JS messages during an exec() when the active
|
|
||||||
// exec() is asynchronous. Set this to true when running bridge benchmarks.
|
|
||||||
static final boolean DISABLE_EXEC_CHAINING = false;
|
|
||||||
|
|
||||||
// Arbitrarily chosen upper limit for how much data to send to JS in one shot.
|
|
||||||
// This currently only chops up on message boundaries. It may be useful
|
|
||||||
// to allow it to break up messages.
|
|
||||||
private static int MAX_PAYLOAD_SIZE = 50 * 1024 * 10240;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When true, the active listener is not fired upon enqueue. When set to false,
|
|
||||||
* the active listener will be fired if the queue is non-empty.
|
|
||||||
*/
|
|
||||||
private boolean paused;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of JavaScript statements to be sent to JavaScript.
|
|
||||||
*/
|
|
||||||
private final LinkedList<JsMessage> queue = new LinkedList<JsMessage>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The array of listeners that can be used to send messages to JS.
|
|
||||||
*/
|
|
||||||
private ArrayList<BridgeMode> bridgeModes = new ArrayList<BridgeMode>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When null, the bridge is disabled. This occurs during page transitions.
|
|
||||||
* When disabled, all callbacks are dropped since they are assumed to be
|
|
||||||
* relevant to the previous page.
|
|
||||||
*/
|
|
||||||
private BridgeMode activeBridgeMode;
|
|
||||||
|
|
||||||
public void addBridgeMode(BridgeMode bridgeMode) {
|
|
||||||
bridgeModes.add(bridgeMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBridgeEnabled() {
|
|
||||||
return activeBridgeMode != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return queue.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the bridge mode.
|
|
||||||
*/
|
|
||||||
public void setBridgeMode(int value) {
|
|
||||||
if (value < -1 || value >= bridgeModes.size()) {
|
|
||||||
LOG.d(LOG_TAG, "Invalid NativeToJsBridgeMode: " + value);
|
|
||||||
} else {
|
|
||||||
BridgeMode newMode = value < 0 ? null : bridgeModes.get(value);
|
|
||||||
if (newMode != activeBridgeMode) {
|
|
||||||
LOG.d(LOG_TAG, "Set native->JS mode to " + (newMode == null ? "null" : newMode.getClass().getSimpleName()));
|
|
||||||
synchronized (this) {
|
|
||||||
activeBridgeMode = newMode;
|
|
||||||
if (newMode != null) {
|
|
||||||
newMode.reset();
|
|
||||||
if (!paused && !queue.isEmpty()) {
|
|
||||||
newMode.onNativeToJsMessageAvailable(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all messages and resets to the default bridge mode.
|
|
||||||
*/
|
|
||||||
public void reset() {
|
|
||||||
synchronized (this) {
|
|
||||||
queue.clear();
|
|
||||||
setBridgeMode(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int calculatePackedMessageLength(JsMessage message) {
|
|
||||||
int messageLen = message.calculateEncodedLength();
|
|
||||||
String messageLenStr = String.valueOf(messageLen);
|
|
||||||
return messageLenStr.length() + messageLen + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void packMessage(JsMessage message, StringBuilder sb) {
|
|
||||||
int len = message.calculateEncodedLength();
|
|
||||||
sb.append(len)
|
|
||||||
.append(' ');
|
|
||||||
message.encodeAsMessage(sb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Combines and returns queued messages combined into a single string.
|
|
||||||
* Combines as many messages as possible, while staying under MAX_PAYLOAD_SIZE.
|
|
||||||
* Returns null if the queue is empty.
|
|
||||||
*/
|
|
||||||
public String popAndEncode(boolean fromOnlineEvent) {
|
|
||||||
synchronized (this) {
|
|
||||||
if (activeBridgeMode == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
activeBridgeMode.notifyOfFlush(this, fromOnlineEvent);
|
|
||||||
if (queue.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int totalPayloadLen = 0;
|
|
||||||
int numMessagesToSend = 0;
|
|
||||||
for (JsMessage message : queue) {
|
|
||||||
int messageSize = calculatePackedMessageLength(message);
|
|
||||||
if (numMessagesToSend > 0 && totalPayloadLen + messageSize > MAX_PAYLOAD_SIZE && MAX_PAYLOAD_SIZE > 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
totalPayloadLen += messageSize;
|
|
||||||
numMessagesToSend += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder(totalPayloadLen);
|
|
||||||
for (int i = 0; i < numMessagesToSend; ++i) {
|
|
||||||
JsMessage message = queue.removeFirst();
|
|
||||||
packMessage(message, sb);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!queue.isEmpty()) {
|
|
||||||
// Attach a char to indicate that there are more messages pending.
|
|
||||||
sb.append('*');
|
|
||||||
}
|
|
||||||
String ret = sb.toString();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as popAndEncode(), except encodes in a form that can be executed as JS.
|
|
||||||
*/
|
|
||||||
public String popAndEncodeAsJs() {
|
|
||||||
synchronized (this) {
|
|
||||||
int length = queue.size();
|
|
||||||
if (length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int totalPayloadLen = 0;
|
|
||||||
int numMessagesToSend = 0;
|
|
||||||
for (JsMessage message : queue) {
|
|
||||||
int messageSize = message.calculateEncodedLength() + 50; // overestimate.
|
|
||||||
if (numMessagesToSend > 0 && totalPayloadLen + messageSize > MAX_PAYLOAD_SIZE && MAX_PAYLOAD_SIZE > 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
totalPayloadLen += messageSize;
|
|
||||||
numMessagesToSend += 1;
|
|
||||||
}
|
|
||||||
boolean willSendAllMessages = numMessagesToSend == queue.size();
|
|
||||||
StringBuilder sb = new StringBuilder(totalPayloadLen + (willSendAllMessages ? 0 : 100));
|
|
||||||
// Wrap each statement in a try/finally so that if one throws it does
|
|
||||||
// not affect the next.
|
|
||||||
for (int i = 0; i < numMessagesToSend; ++i) {
|
|
||||||
JsMessage message = queue.removeFirst();
|
|
||||||
if (willSendAllMessages && (i + 1 == numMessagesToSend)) {
|
|
||||||
message.encodeAsJsMessage(sb);
|
|
||||||
} else {
|
|
||||||
sb.append("try{");
|
|
||||||
message.encodeAsJsMessage(sb);
|
|
||||||
sb.append("}finally{");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!willSendAllMessages) {
|
|
||||||
sb.append("window.setTimeout(function(){cordova.require('cordova/plugin/android/polling').pollOnce();},0);");
|
|
||||||
}
|
|
||||||
for (int i = willSendAllMessages ? 1 : 0; i < numMessagesToSend; ++i) {
|
|
||||||
sb.append('}');
|
|
||||||
}
|
|
||||||
String ret = sb.toString();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a JavaScript statement to the list.
|
|
||||||
*/
|
|
||||||
public void addJavaScript(String statement) {
|
|
||||||
enqueueMessage(new JsMessage(statement));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a JavaScript statement to the list.
|
|
||||||
*/
|
|
||||||
public void addPluginResult(PluginResult result, String callbackId) {
|
|
||||||
if (callbackId == null) {
|
|
||||||
LOG.e(LOG_TAG, "Got plugin result with no callbackId", new Throwable());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Don't send anything if there is no result and there is no need to
|
|
||||||
// clear the callbacks.
|
|
||||||
boolean noResult = result.getStatus() == PluginResult.Status.NO_RESULT.ordinal();
|
|
||||||
boolean keepCallback = result.getKeepCallback();
|
|
||||||
if (noResult && keepCallback) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
JsMessage message = new JsMessage(result, callbackId);
|
|
||||||
if (FORCE_ENCODE_USING_EVAL) {
|
|
||||||
StringBuilder sb = new StringBuilder(message.calculateEncodedLength() + 50);
|
|
||||||
message.encodeAsJsMessage(sb);
|
|
||||||
message = new JsMessage(sb.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
enqueueMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enqueueMessage(JsMessage message) {
|
|
||||||
synchronized (this) {
|
|
||||||
if (activeBridgeMode == null) {
|
|
||||||
LOG.d(LOG_TAG, "Dropping Native->JS message due to disabled bridge");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
queue.add(message);
|
|
||||||
if (!paused) {
|
|
||||||
activeBridgeMode.onNativeToJsMessageAvailable(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPaused(boolean value) {
|
|
||||||
if (paused && value) {
|
|
||||||
// This should never happen. If a use-case for it comes up, we should
|
|
||||||
// change pause to be a counter.
|
|
||||||
LOG.e(LOG_TAG, "nested call to setPaused detected.", new Throwable());
|
|
||||||
}
|
|
||||||
paused = value;
|
|
||||||
if (!value) {
|
|
||||||
synchronized (this) {
|
|
||||||
if (!queue.isEmpty() && activeBridgeMode != null) {
|
|
||||||
activeBridgeMode.onNativeToJsMessageAvailable(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static abstract class BridgeMode {
|
|
||||||
public abstract void onNativeToJsMessageAvailable(NativeToJsMessageQueue queue);
|
|
||||||
public void notifyOfFlush(NativeToJsMessageQueue queue, boolean fromOnlineEvent) {}
|
|
||||||
public void reset() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Uses JS polls for messages on a timer.. */
|
|
||||||
public static class NoOpBridgeMode extends BridgeMode {
|
|
||||||
@Override public void onNativeToJsMessageAvailable(NativeToJsMessageQueue queue) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Uses webView.loadUrl("javascript:") to execute messages. */
|
|
||||||
public static class LoadUrlBridgeMode extends BridgeMode {
|
|
||||||
private final CordovaWebViewEngine engine;
|
|
||||||
private final CordovaInterface cordova;
|
|
||||||
|
|
||||||
public LoadUrlBridgeMode(CordovaWebViewEngine engine, CordovaInterface cordova) {
|
|
||||||
this.engine = engine;
|
|
||||||
this.cordova = cordova;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
|
|
||||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
String js = queue.popAndEncodeAsJs();
|
|
||||||
if (js != null) {
|
|
||||||
engine.loadUrl("javascript:" + js, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Uses online/offline events to tell the JS when to poll for messages. */
|
|
||||||
public static class OnlineEventsBridgeMode extends BridgeMode {
|
|
||||||
private final OnlineEventsBridgeModeDelegate delegate;
|
|
||||||
private boolean online;
|
|
||||||
private boolean ignoreNextFlush;
|
|
||||||
|
|
||||||
public interface OnlineEventsBridgeModeDelegate {
|
|
||||||
void setNetworkAvailable(boolean value);
|
|
||||||
void runOnUiThread(Runnable r);
|
|
||||||
}
|
|
||||||
|
|
||||||
public OnlineEventsBridgeMode(OnlineEventsBridgeModeDelegate delegate) {
|
|
||||||
this.delegate = delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() {
|
|
||||||
delegate.runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
online = false;
|
|
||||||
// If the following call triggers a notifyOfFlush, then ignore it.
|
|
||||||
ignoreNextFlush = true;
|
|
||||||
delegate.setNetworkAvailable(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
|
|
||||||
delegate.runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
if (!queue.isEmpty()) {
|
|
||||||
ignoreNextFlush = false;
|
|
||||||
delegate.setNetworkAvailable(online);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Track when online/offline events are fired so that we don't fire excess events.
|
|
||||||
@Override
|
|
||||||
public void notifyOfFlush(final NativeToJsMessageQueue queue, boolean fromOnlineEvent) {
|
|
||||||
if (fromOnlineEvent && !ignoreNextFlush) {
|
|
||||||
online = !online;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Uses webView.evaluateJavascript to execute messages. */
|
|
||||||
public static class EvalBridgeMode extends BridgeMode {
|
|
||||||
private final CordovaWebViewEngine engine;
|
|
||||||
private final CordovaInterface cordova;
|
|
||||||
|
|
||||||
public EvalBridgeMode(CordovaWebViewEngine engine, CordovaInterface cordova) {
|
|
||||||
this.engine = engine;
|
|
||||||
this.cordova = cordova;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
|
|
||||||
cordova.getActivity().runOnUiThread(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
String js = queue.popAndEncodeAsJs();
|
|
||||||
if (js != null) {
|
|
||||||
engine.evaluateJavascript(js, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static class JsMessage {
|
|
||||||
final String jsPayloadOrCallbackId;
|
|
||||||
final PluginResult pluginResult;
|
|
||||||
JsMessage(String js) {
|
|
||||||
if (js == null) {
|
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
jsPayloadOrCallbackId = js;
|
|
||||||
pluginResult = null;
|
|
||||||
}
|
|
||||||
JsMessage(PluginResult pluginResult, String callbackId) {
|
|
||||||
if (callbackId == null || pluginResult == null) {
|
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
jsPayloadOrCallbackId = callbackId;
|
|
||||||
this.pluginResult = pluginResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int calculateEncodedLengthHelper(PluginResult pluginResult) {
|
|
||||||
switch (pluginResult.getMessageType()) {
|
|
||||||
case PluginResult.MESSAGE_TYPE_BOOLEAN: // f or t
|
|
||||||
case PluginResult.MESSAGE_TYPE_NULL: // N
|
|
||||||
return 1;
|
|
||||||
case PluginResult.MESSAGE_TYPE_NUMBER: // n
|
|
||||||
return 1 + pluginResult.getMessage().length();
|
|
||||||
case PluginResult.MESSAGE_TYPE_STRING: // s
|
|
||||||
return 1 + pluginResult.getStrMessage().length();
|
|
||||||
case PluginResult.MESSAGE_TYPE_BINARYSTRING:
|
|
||||||
return 1 + pluginResult.getMessage().length();
|
|
||||||
case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
|
|
||||||
return 1 + pluginResult.getMessage().length();
|
|
||||||
case PluginResult.MESSAGE_TYPE_MULTIPART:
|
|
||||||
int ret = 1;
|
|
||||||
for (int i = 0; i < pluginResult.getMultipartMessagesSize(); i++) {
|
|
||||||
int length = calculateEncodedLengthHelper(pluginResult.getMultipartMessage(i));
|
|
||||||
int argLength = String.valueOf(length).length();
|
|
||||||
ret += argLength + 1 + length;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
case PluginResult.MESSAGE_TYPE_JSON:
|
|
||||||
default:
|
|
||||||
return pluginResult.getMessage().length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int calculateEncodedLength() {
|
|
||||||
if (pluginResult == null) {
|
|
||||||
return jsPayloadOrCallbackId.length() + 1;
|
|
||||||
}
|
|
||||||
int statusLen = String.valueOf(pluginResult.getStatus()).length();
|
|
||||||
int ret = 2 + statusLen + 1 + jsPayloadOrCallbackId.length() + 1;
|
|
||||||
return ret + calculateEncodedLengthHelper(pluginResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void encodeAsMessageHelper(StringBuilder sb, PluginResult pluginResult) {
|
|
||||||
switch (pluginResult.getMessageType()) {
|
|
||||||
case PluginResult.MESSAGE_TYPE_BOOLEAN:
|
|
||||||
sb.append(pluginResult.getMessage().charAt(0)); // t or f.
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_NULL: // N
|
|
||||||
sb.append('N');
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_NUMBER: // n
|
|
||||||
sb.append('n')
|
|
||||||
.append(pluginResult.getMessage());
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_STRING: // s
|
|
||||||
sb.append('s');
|
|
||||||
sb.append(pluginResult.getStrMessage());
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_BINARYSTRING: // S
|
|
||||||
sb.append('S');
|
|
||||||
sb.append(pluginResult.getMessage());
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_ARRAYBUFFER: // A
|
|
||||||
sb.append('A');
|
|
||||||
sb.append(pluginResult.getMessage());
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_MULTIPART:
|
|
||||||
sb.append('M');
|
|
||||||
for (int i = 0; i < pluginResult.getMultipartMessagesSize(); i++) {
|
|
||||||
PluginResult multipartMessage = pluginResult.getMultipartMessage(i);
|
|
||||||
sb.append(String.valueOf(calculateEncodedLengthHelper(multipartMessage)));
|
|
||||||
sb.append(' ');
|
|
||||||
encodeAsMessageHelper(sb, multipartMessage);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_JSON:
|
|
||||||
default:
|
|
||||||
sb.append(pluginResult.getMessage()); // [ or {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void encodeAsMessage(StringBuilder sb) {
|
|
||||||
if (pluginResult == null) {
|
|
||||||
sb.append('J')
|
|
||||||
.append(jsPayloadOrCallbackId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int status = pluginResult.getStatus();
|
|
||||||
boolean noResult = status == PluginResult.Status.NO_RESULT.ordinal();
|
|
||||||
boolean resultOk = status == PluginResult.Status.OK.ordinal();
|
|
||||||
boolean keepCallback = pluginResult.getKeepCallback();
|
|
||||||
|
|
||||||
sb.append((noResult || resultOk) ? 'S' : 'F')
|
|
||||||
.append(keepCallback ? '1' : '0')
|
|
||||||
.append(status)
|
|
||||||
.append(' ')
|
|
||||||
.append(jsPayloadOrCallbackId)
|
|
||||||
.append(' ');
|
|
||||||
|
|
||||||
encodeAsMessageHelper(sb, pluginResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
void buildJsMessage(StringBuilder sb) {
|
|
||||||
switch (pluginResult.getMessageType()) {
|
|
||||||
case PluginResult.MESSAGE_TYPE_MULTIPART:
|
|
||||||
int size = pluginResult.getMultipartMessagesSize();
|
|
||||||
for (int i=0; i<size; i++) {
|
|
||||||
PluginResult subresult = pluginResult.getMultipartMessage(i);
|
|
||||||
JsMessage submessage = new JsMessage(subresult, jsPayloadOrCallbackId);
|
|
||||||
submessage.buildJsMessage(sb);
|
|
||||||
if (i < (size-1)) {
|
|
||||||
sb.append(",");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_BINARYSTRING:
|
|
||||||
sb.append("atob('")
|
|
||||||
.append(pluginResult.getMessage())
|
|
||||||
.append("')");
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
|
|
||||||
sb.append("cordova.require('cordova/base64').toArrayBuffer('")
|
|
||||||
.append(pluginResult.getMessage())
|
|
||||||
.append("')");
|
|
||||||
break;
|
|
||||||
case PluginResult.MESSAGE_TYPE_NULL:
|
|
||||||
sb.append("null");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sb.append(pluginResult.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void encodeAsJsMessage(StringBuilder sb) {
|
|
||||||
if (pluginResult == null) {
|
|
||||||
sb.append(jsPayloadOrCallbackId);
|
|
||||||
} else {
|
|
||||||
int status = pluginResult.getStatus();
|
|
||||||
boolean success = (status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal());
|
|
||||||
sb.append("cordova.callbackFromNative('")
|
|
||||||
.append(jsPayloadOrCallbackId)
|
|
||||||
.append("',")
|
|
||||||
.append(success)
|
|
||||||
.append(",")
|
|
||||||
.append(status)
|
|
||||||
.append(",[");
|
|
||||||
buildJsMessage(sb);
|
|
||||||
sb.append("],")
|
|
||||||
.append(pluginResult.getKeepCallback())
|
|
||||||
.append(");");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class provides reflective methods for permission requesting and checking so that plugins
|
|
||||||
* written for cordova-android 5.0.0+ can still compile with earlier cordova-android versions.
|
|
||||||
*/
|
|
||||||
public class PermissionHelper {
|
|
||||||
private static final String LOG_TAG = "CordovaPermissionHelper";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requests a "dangerous" permission for the application at runtime. This is a helper method
|
|
||||||
* alternative to cordovaInterface.requestPermission() that does not require the project to be
|
|
||||||
* built with cordova-android 5.0.0+
|
|
||||||
*
|
|
||||||
* @param plugin The plugin the permission is being requested for
|
|
||||||
* @param requestCode A requestCode to be passed to the plugin's onRequestPermissionResult()
|
|
||||||
* along with the result of the permission request
|
|
||||||
* @param permission The permission to be requested
|
|
||||||
*/
|
|
||||||
public static void requestPermission(CordovaPlugin plugin, int requestCode, String permission) {
|
|
||||||
PermissionHelper.requestPermissions(plugin, requestCode, new String[] {permission});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requests "dangerous" permissions for the application at runtime. This is a helper method
|
|
||||||
* alternative to cordovaInterface.requestPermissions() that does not require the project to be
|
|
||||||
* built with cordova-android 5.0.0+
|
|
||||||
*
|
|
||||||
* @param plugin The plugin the permissions are being requested for
|
|
||||||
* @param requestCode A requestCode to be passed to the plugin's onRequestPermissionResult()
|
|
||||||
* along with the result of the permissions request
|
|
||||||
* @param permissions The permissions to be requested
|
|
||||||
*/
|
|
||||||
public static void requestPermissions(CordovaPlugin plugin, int requestCode, String[] permissions) {
|
|
||||||
plugin.cordova.requestPermissions(plugin, requestCode, permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks at runtime to see if the application has been granted a permission. This is a helper
|
|
||||||
* method alternative to cordovaInterface.hasPermission() that does not require the project to
|
|
||||||
* be built with cordova-android 5.0.0+
|
|
||||||
*
|
|
||||||
* @param plugin The plugin the permission is being checked against
|
|
||||||
* @param permission The permission to be checked
|
|
||||||
*
|
|
||||||
* @return True if the permission has already been granted and false otherwise
|
|
||||||
*/
|
|
||||||
public static boolean hasPermission(CordovaPlugin plugin, String permission) {
|
|
||||||
return plugin.cordova.hasPermission(permission);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void deliverPermissionResult(CordovaPlugin plugin, int requestCode, String[] permissions) {
|
|
||||||
// Generate the request results
|
|
||||||
int[] requestResults = new int[permissions.length];
|
|
||||||
Arrays.fill(requestResults, PackageManager.PERMISSION_GRANTED);
|
|
||||||
|
|
||||||
try {
|
|
||||||
plugin.onRequestPermissionResult(requestCode, permissions, requestResults);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
LOG.e(LOG_TAG, "JSONException when delivering permissions results", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import org.apache.cordova.CordovaPlugin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents a service entry object.
|
|
||||||
*/
|
|
||||||
public final class PluginEntry {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the service that this plugin implements
|
|
||||||
*/
|
|
||||||
public final String service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The plugin class name that implements the service.
|
|
||||||
*/
|
|
||||||
public final String pluginClass;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The pre-instantiated plugin to use for this entry.
|
|
||||||
*/
|
|
||||||
public final CordovaPlugin plugin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag that indicates the plugin object should be created when PluginManager is initialized.
|
|
||||||
*/
|
|
||||||
public final boolean onload;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs with a CordovaPlugin already instantiated.
|
|
||||||
*/
|
|
||||||
public PluginEntry(String service, CordovaPlugin plugin) {
|
|
||||||
this(service, plugin.getClass().getName(), true, plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param service The name of the service
|
|
||||||
* @param pluginClass The plugin class name
|
|
||||||
* @param onload Create plugin object when HTML page is loaded
|
|
||||||
*/
|
|
||||||
public PluginEntry(String service, String pluginClass, boolean onload) {
|
|
||||||
this(service, pluginClass, onload, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PluginEntry(String service, String pluginClass, boolean onload, CordovaPlugin plugin) {
|
|
||||||
this.service = service;
|
|
||||||
this.pluginClass = pluginClass;
|
|
||||||
this.onload = onload;
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,526 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Debug;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PluginManager is exposed to JavaScript in the Cordova WebView.
|
|
||||||
*
|
|
||||||
* Calling native plugin code can be done by calling PluginManager.exec(...)
|
|
||||||
* from JavaScript.
|
|
||||||
*/
|
|
||||||
public class PluginManager {
|
|
||||||
private static String TAG = "PluginManager";
|
|
||||||
private static final int SLOW_EXEC_WARNING_THRESHOLD = Debug.isDebuggerConnected() ? 60 : 16;
|
|
||||||
|
|
||||||
// List of service entries
|
|
||||||
private final LinkedHashMap<String, CordovaPlugin> pluginMap = new LinkedHashMap<String, CordovaPlugin>();
|
|
||||||
private final LinkedHashMap<String, PluginEntry> entryMap = new LinkedHashMap<String, PluginEntry>();
|
|
||||||
|
|
||||||
private final CordovaInterface ctx;
|
|
||||||
private final CordovaWebView app;
|
|
||||||
private boolean isInitialized;
|
|
||||||
|
|
||||||
private CordovaPlugin permissionRequester;
|
|
||||||
|
|
||||||
public PluginManager(CordovaWebView cordovaWebView, CordovaInterface cordova, Collection<PluginEntry> pluginEntries) {
|
|
||||||
this.ctx = cordova;
|
|
||||||
this.app = cordovaWebView;
|
|
||||||
setPluginEntries(pluginEntries);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<PluginEntry> getPluginEntries() {
|
|
||||||
return entryMap.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPluginEntries(Collection<PluginEntry> pluginEntries) {
|
|
||||||
if (isInitialized) {
|
|
||||||
this.onPause(false);
|
|
||||||
this.onDestroy();
|
|
||||||
pluginMap.clear();
|
|
||||||
entryMap.clear();
|
|
||||||
}
|
|
||||||
for (PluginEntry entry : pluginEntries) {
|
|
||||||
addService(entry);
|
|
||||||
}
|
|
||||||
if (isInitialized) {
|
|
||||||
startupPlugins();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init when loading a new HTML page into webview.
|
|
||||||
*/
|
|
||||||
public void init() {
|
|
||||||
LOG.d(TAG, "init()");
|
|
||||||
isInitialized = true;
|
|
||||||
this.onPause(false);
|
|
||||||
this.onDestroy();
|
|
||||||
pluginMap.clear();
|
|
||||||
this.startupPlugins();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create plugins objects that have onload set.
|
|
||||||
*/
|
|
||||||
private void startupPlugins() {
|
|
||||||
for (PluginEntry entry : entryMap.values()) {
|
|
||||||
// Add a null entry to for each non-startup plugin to avoid ConcurrentModificationException
|
|
||||||
// When iterating plugins.
|
|
||||||
if (entry.onload) {
|
|
||||||
getPlugin(entry.service);
|
|
||||||
} else {
|
|
||||||
pluginMap.put(entry.service, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receives a request for execution and fulfills it by finding the appropriate
|
|
||||||
* Java class and calling it's execute method.
|
|
||||||
*
|
|
||||||
* PluginManager.exec can be used either synchronously or async. In either case, a JSON encoded
|
|
||||||
* string is returned that will indicate if any errors have occurred when trying to find
|
|
||||||
* or execute the class denoted by the clazz argument.
|
|
||||||
*
|
|
||||||
* @param service String containing the service to run
|
|
||||||
* @param action String containing the action that the class is supposed to perform. This is
|
|
||||||
* passed to the plugin execute method and it is up to the plugin developer
|
|
||||||
* how to deal with it.
|
|
||||||
* @param callbackId String containing the id of the callback that is execute in JavaScript if
|
|
||||||
* this is an async plugin call.
|
|
||||||
* @param rawArgs An Array literal string containing any arguments needed in the
|
|
||||||
* plugin execute method.
|
|
||||||
*/
|
|
||||||
public void exec(final String service, final String action, final String callbackId, final String rawArgs) {
|
|
||||||
CordovaPlugin plugin = getPlugin(service);
|
|
||||||
if (plugin == null) {
|
|
||||||
LOG.d(TAG, "exec() call to unknown plugin: " + service);
|
|
||||||
PluginResult cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION);
|
|
||||||
app.sendPluginResult(cr, callbackId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CallbackContext callbackContext = new CallbackContext(callbackId, app);
|
|
||||||
try {
|
|
||||||
long pluginStartTime = System.currentTimeMillis();
|
|
||||||
boolean wasValidAction = plugin.execute(action, rawArgs, callbackContext);
|
|
||||||
long duration = System.currentTimeMillis() - pluginStartTime;
|
|
||||||
|
|
||||||
if (duration > SLOW_EXEC_WARNING_THRESHOLD) {
|
|
||||||
LOG.w(TAG, "THREAD WARNING: exec() call to " + service + "." + action + " blocked the main thread for " + duration + "ms. Plugin should use CordovaInterface.getThreadPool().");
|
|
||||||
}
|
|
||||||
if (!wasValidAction) {
|
|
||||||
PluginResult cr = new PluginResult(PluginResult.Status.INVALID_ACTION);
|
|
||||||
callbackContext.sendPluginResult(cr);
|
|
||||||
}
|
|
||||||
} catch (JSONException e) {
|
|
||||||
PluginResult cr = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
|
|
||||||
callbackContext.sendPluginResult(cr);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.e(TAG, "Uncaught exception from plugin", e);
|
|
||||||
callbackContext.error(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the plugin object that implements the service.
|
|
||||||
* If the plugin object does not already exist, then create it.
|
|
||||||
* If the service doesn't exist, then return null.
|
|
||||||
*
|
|
||||||
* @param service The name of the service.
|
|
||||||
* @return CordovaPlugin or null
|
|
||||||
*/
|
|
||||||
public CordovaPlugin getPlugin(String service) {
|
|
||||||
CordovaPlugin ret = pluginMap.get(service);
|
|
||||||
if (ret == null) {
|
|
||||||
PluginEntry pe = entryMap.get(service);
|
|
||||||
if (pe == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (pe.plugin != null) {
|
|
||||||
ret = pe.plugin;
|
|
||||||
} else {
|
|
||||||
ret = instantiatePlugin(pe.pluginClass);
|
|
||||||
}
|
|
||||||
ret.privateInitialize(service, ctx, app, app.getPreferences());
|
|
||||||
pluginMap.put(service, ret);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a plugin class that implements a service to the service entry table.
|
|
||||||
* This does not create the plugin object instance.
|
|
||||||
*
|
|
||||||
* @param service The service name
|
|
||||||
* @param className The plugin class name
|
|
||||||
*/
|
|
||||||
public void addService(String service, String className) {
|
|
||||||
PluginEntry entry = new PluginEntry(service, className, false);
|
|
||||||
this.addService(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a plugin class that implements a service to the service entry table.
|
|
||||||
* This does not create the plugin object instance.
|
|
||||||
*
|
|
||||||
* @param entry The plugin entry
|
|
||||||
*/
|
|
||||||
public void addService(PluginEntry entry) {
|
|
||||||
this.entryMap.put(entry.service, entry);
|
|
||||||
if (entry.plugin != null) {
|
|
||||||
entry.plugin.privateInitialize(entry.service, ctx, app, app.getPreferences());
|
|
||||||
pluginMap.put(entry.service, entry.plugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the system is about to start resuming a previous activity.
|
|
||||||
*
|
|
||||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
|
||||||
*/
|
|
||||||
public void onPause(boolean multitasking) {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null) {
|
|
||||||
plugin.onPause(multitasking);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the system received an HTTP authentication request. Plugins can use
|
|
||||||
* the supplied HttpAuthHandler to process this auth challenge.
|
|
||||||
*
|
|
||||||
* @param view The WebView that is initiating the callback
|
|
||||||
* @param handler The HttpAuthHandler used to set the WebView's response
|
|
||||||
* @param host The host requiring authentication
|
|
||||||
* @param realm The realm for which authentication is required
|
|
||||||
*
|
|
||||||
* @return Returns True if there is a plugin which will resolve this auth challenge, otherwise False
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public boolean onReceivedHttpAuthRequest(CordovaWebView view, ICordovaHttpAuthHandler handler, String host, String realm) {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null && plugin.onReceivedHttpAuthRequest(app, handler, host, realm)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when he system received an SSL client certificate request. Plugin can use
|
|
||||||
* the supplied ClientCertRequest to process this certificate challenge.
|
|
||||||
*
|
|
||||||
* @param view The WebView that is initiating the callback
|
|
||||||
* @param request The client certificate request
|
|
||||||
*
|
|
||||||
* @return Returns True if plugin will resolve this auth challenge, otherwise False
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public boolean onReceivedClientCertRequest(CordovaWebView view, ICordovaClientCertRequest request) {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null && plugin.onReceivedClientCertRequest(app, request)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity will start interacting with the user.
|
|
||||||
*
|
|
||||||
* @param multitasking Flag indicating if multitasking is turned on for app
|
|
||||||
*/
|
|
||||||
public void onResume(boolean multitasking) {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null) {
|
|
||||||
plugin.onResume(multitasking);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity is becoming visible to the user.
|
|
||||||
*/
|
|
||||||
public void onStart() {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null) {
|
|
||||||
plugin.onStart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity is no longer visible to the user.
|
|
||||||
*/
|
|
||||||
public void onStop() {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null) {
|
|
||||||
plugin.onStop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The final call you receive before your activity is destroyed.
|
|
||||||
*/
|
|
||||||
public void onDestroy() {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null) {
|
|
||||||
plugin.onDestroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a message to all plugins.
|
|
||||||
*
|
|
||||||
* @param id The message id
|
|
||||||
* @param data The message data
|
|
||||||
* @return Object to stop propagation or null
|
|
||||||
*/
|
|
||||||
public Object postMessage(String id, Object data) {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null) {
|
|
||||||
Object obj = plugin.onMessage(id, data);
|
|
||||||
if (obj != null) {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ctx.onMessage(id, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity receives a new intent.
|
|
||||||
*/
|
|
||||||
public void onNewIntent(Intent intent) {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null) {
|
|
||||||
plugin.onNewIntent(intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the webview is going to request an external resource.
|
|
||||||
*
|
|
||||||
* This delegates to the installed plugins, and returns true/false for the
|
|
||||||
* first plugin to provide a non-null result. If no plugins respond, then
|
|
||||||
* the default policy is applied.
|
|
||||||
*
|
|
||||||
* @param url The URL that is being requested.
|
|
||||||
* @return Returns true to allow the resource to load,
|
|
||||||
* false to block the resource.
|
|
||||||
*/
|
|
||||||
public boolean shouldAllowRequest(String url) {
|
|
||||||
for (PluginEntry entry : this.entryMap.values()) {
|
|
||||||
CordovaPlugin plugin = pluginMap.get(entry.service);
|
|
||||||
if (plugin != null) {
|
|
||||||
Boolean result = plugin.shouldAllowRequest(url);
|
|
||||||
if (result != null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default policy:
|
|
||||||
if (url.startsWith("blob:") || url.startsWith("data:") || url.startsWith("about:blank")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// TalkBack requires this, so allow it by default.
|
|
||||||
if (url.startsWith("https://ssl.gstatic.com/accessibility/javascript/android/")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (url.startsWith("file://")) {
|
|
||||||
//This directory on WebKit/Blink based webviews contains SQLite databases!
|
|
||||||
//DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING!
|
|
||||||
return !url.contains("/app_webview/");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the webview is going to change the URL of the loaded content.
|
|
||||||
*
|
|
||||||
* This delegates to the installed plugins, and returns true/false for the
|
|
||||||
* first plugin to provide a non-null result. If no plugins respond, then
|
|
||||||
* the default policy is applied.
|
|
||||||
*
|
|
||||||
* @param url The URL that is being requested.
|
|
||||||
* @return Returns true to allow the navigation,
|
|
||||||
* false to block the navigation.
|
|
||||||
*/
|
|
||||||
public boolean shouldAllowNavigation(String url) {
|
|
||||||
for (PluginEntry entry : this.entryMap.values()) {
|
|
||||||
CordovaPlugin plugin = pluginMap.get(entry.service);
|
|
||||||
if (plugin != null) {
|
|
||||||
Boolean result = plugin.shouldAllowNavigation(url);
|
|
||||||
if (result != null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default policy:
|
|
||||||
return url.startsWith("file://") || url.startsWith("about:blank");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the webview is requesting the exec() bridge be enabled.
|
|
||||||
*/
|
|
||||||
public boolean shouldAllowBridgeAccess(String url) {
|
|
||||||
for (PluginEntry entry : this.entryMap.values()) {
|
|
||||||
CordovaPlugin plugin = pluginMap.get(entry.service);
|
|
||||||
if (plugin != null) {
|
|
||||||
Boolean result = plugin.shouldAllowBridgeAccess(url);
|
|
||||||
if (result != null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default policy:
|
|
||||||
return url.startsWith("file://");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the webview is going not going to navigate, but may launch
|
|
||||||
* an Intent for an URL.
|
|
||||||
*
|
|
||||||
* This delegates to the installed plugins, and returns true/false for the
|
|
||||||
* first plugin to provide a non-null result. If no plugins respond, then
|
|
||||||
* the default policy is applied.
|
|
||||||
*
|
|
||||||
* @param url The URL that is being requested.
|
|
||||||
* @return Returns true to allow the URL to launch an intent,
|
|
||||||
* false to block the intent.
|
|
||||||
*/
|
|
||||||
public Boolean shouldOpenExternalUrl(String url) {
|
|
||||||
for (PluginEntry entry : this.entryMap.values()) {
|
|
||||||
CordovaPlugin plugin = pluginMap.get(entry.service);
|
|
||||||
if (plugin != null) {
|
|
||||||
Boolean result = plugin.shouldOpenExternalUrl(url);
|
|
||||||
if (result != null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Default policy:
|
|
||||||
// External URLs are not allowed
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the URL of the webview changes.
|
|
||||||
*
|
|
||||||
* @param url The URL that is being changed to.
|
|
||||||
* @return Return false to allow the URL to load, return true to prevent the URL from loading.
|
|
||||||
*/
|
|
||||||
public boolean onOverrideUrlLoading(String url) {
|
|
||||||
for (PluginEntry entry : this.entryMap.values()) {
|
|
||||||
CordovaPlugin plugin = pluginMap.get(entry.service);
|
|
||||||
if (plugin != null && plugin.onOverrideUrlLoading(url)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the app navigates or refreshes.
|
|
||||||
*/
|
|
||||||
public void onReset() {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null) {
|
|
||||||
plugin.onReset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Uri remapUri(Uri uri) {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null) {
|
|
||||||
Uri ret = plugin.remapUri(uri);
|
|
||||||
if (ret != null) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a plugin based on class name.
|
|
||||||
*/
|
|
||||||
private CordovaPlugin instantiatePlugin(String className) {
|
|
||||||
CordovaPlugin ret = null;
|
|
||||||
try {
|
|
||||||
Class<?> c = null;
|
|
||||||
if ((className != null) && !("".equals(className))) {
|
|
||||||
c = Class.forName(className);
|
|
||||||
}
|
|
||||||
if (c != null & CordovaPlugin.class.isAssignableFrom(c)) {
|
|
||||||
ret = (CordovaPlugin) c.newInstance();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.out.println("Error adding plugin " + className + ".");
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by the system when the device configuration changes while your activity is running.
|
|
||||||
*
|
|
||||||
* @param newConfig The new device configuration
|
|
||||||
*/
|
|
||||||
public void onConfigurationChanged(Configuration newConfig) {
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null) {
|
|
||||||
plugin.onConfigurationChanged(newConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bundle onSaveInstanceState() {
|
|
||||||
Bundle state = new Bundle();
|
|
||||||
for (CordovaPlugin plugin : this.pluginMap.values()) {
|
|
||||||
if (plugin != null) {
|
|
||||||
Bundle pluginState = plugin.onSaveInstanceState();
|
|
||||||
if(pluginState != null) {
|
|
||||||
state.putBundle(plugin.getServiceName(), pluginState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,198 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import android.util.Base64;
|
|
||||||
|
|
||||||
public class PluginResult {
|
|
||||||
private final int status;
|
|
||||||
private final int messageType;
|
|
||||||
private boolean keepCallback = false;
|
|
||||||
private String strMessage;
|
|
||||||
private String encodedMessage;
|
|
||||||
private List<PluginResult> multipartMessages;
|
|
||||||
|
|
||||||
public PluginResult(Status status) {
|
|
||||||
this(status, PluginResult.StatusMessages[status.ordinal()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginResult(Status status, String message) {
|
|
||||||
this.status = status.ordinal();
|
|
||||||
this.messageType = message == null ? MESSAGE_TYPE_NULL : MESSAGE_TYPE_STRING;
|
|
||||||
this.strMessage = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginResult(Status status, JSONArray message) {
|
|
||||||
this.status = status.ordinal();
|
|
||||||
this.messageType = MESSAGE_TYPE_JSON;
|
|
||||||
encodedMessage = message.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginResult(Status status, JSONObject message) {
|
|
||||||
this.status = status.ordinal();
|
|
||||||
this.messageType = MESSAGE_TYPE_JSON;
|
|
||||||
encodedMessage = message.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginResult(Status status, int i) {
|
|
||||||
this.status = status.ordinal();
|
|
||||||
this.messageType = MESSAGE_TYPE_NUMBER;
|
|
||||||
this.encodedMessage = ""+i;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginResult(Status status, float f) {
|
|
||||||
this.status = status.ordinal();
|
|
||||||
this.messageType = MESSAGE_TYPE_NUMBER;
|
|
||||||
this.encodedMessage = ""+f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginResult(Status status, boolean b) {
|
|
||||||
this.status = status.ordinal();
|
|
||||||
this.messageType = MESSAGE_TYPE_BOOLEAN;
|
|
||||||
this.encodedMessage = Boolean.toString(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginResult(Status status, byte[] data) {
|
|
||||||
this(status, data, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginResult(Status status, byte[] data, boolean binaryString) {
|
|
||||||
this.status = status.ordinal();
|
|
||||||
this.messageType = binaryString ? MESSAGE_TYPE_BINARYSTRING : MESSAGE_TYPE_ARRAYBUFFER;
|
|
||||||
this.encodedMessage = Base64.encodeToString(data, Base64.NO_WRAP);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The keepCallback and status of multipartMessages are ignored.
|
|
||||||
public PluginResult(Status status, List<PluginResult> multipartMessages) {
|
|
||||||
this.status = status.ordinal();
|
|
||||||
this.messageType = MESSAGE_TYPE_MULTIPART;
|
|
||||||
this.multipartMessages = multipartMessages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKeepCallback(boolean b) {
|
|
||||||
this.keepCallback = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getStatus() {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMessageType() {
|
|
||||||
return messageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
if (encodedMessage == null) {
|
|
||||||
encodedMessage = JSONObject.quote(strMessage);
|
|
||||||
}
|
|
||||||
return encodedMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMultipartMessagesSize() {
|
|
||||||
return multipartMessages.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginResult getMultipartMessage(int index) {
|
|
||||||
return multipartMessages.get(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If messageType == MESSAGE_TYPE_STRING, then returns the message string.
|
|
||||||
* Otherwise, returns null.
|
|
||||||
*/
|
|
||||||
public String getStrMessage() {
|
|
||||||
return strMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getKeepCallback() {
|
|
||||||
return this.keepCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated // Use sendPluginResult instead of sendJavascript.
|
|
||||||
public String getJSONString() {
|
|
||||||
return "{\"status\":" + this.status + ",\"message\":" + this.getMessage() + ",\"keepCallback\":" + this.keepCallback + "}";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated // Use sendPluginResult instead of sendJavascript.
|
|
||||||
public String toCallbackString(String callbackId) {
|
|
||||||
// If no result to be sent and keeping callback, then no need to sent back to JavaScript
|
|
||||||
if ((status == PluginResult.Status.NO_RESULT.ordinal()) && keepCallback) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the success (OK, NO_RESULT & !KEEP_CALLBACK)
|
|
||||||
if ((status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal())) {
|
|
||||||
return toSuccessCallbackString(callbackId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return toErrorCallbackString(callbackId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated // Use sendPluginResult instead of sendJavascript.
|
|
||||||
public String toSuccessCallbackString(String callbackId) {
|
|
||||||
return "cordova.callbackSuccess('"+callbackId+"',"+this.getJSONString()+");";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated // Use sendPluginResult instead of sendJavascript.
|
|
||||||
public String toErrorCallbackString(String callbackId) {
|
|
||||||
return "cordova.callbackError('"+callbackId+"', " + this.getJSONString()+ ");";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int MESSAGE_TYPE_STRING = 1;
|
|
||||||
public static final int MESSAGE_TYPE_JSON = 2;
|
|
||||||
public static final int MESSAGE_TYPE_NUMBER = 3;
|
|
||||||
public static final int MESSAGE_TYPE_BOOLEAN = 4;
|
|
||||||
public static final int MESSAGE_TYPE_NULL = 5;
|
|
||||||
public static final int MESSAGE_TYPE_ARRAYBUFFER = 6;
|
|
||||||
// Use BINARYSTRING when your string may contain null characters.
|
|
||||||
// This is required to work around a bug in the platform :(.
|
|
||||||
public static final int MESSAGE_TYPE_BINARYSTRING = 7;
|
|
||||||
public static final int MESSAGE_TYPE_MULTIPART = 8;
|
|
||||||
|
|
||||||
public static String[] StatusMessages = new String[] {
|
|
||||||
"No result",
|
|
||||||
"OK",
|
|
||||||
"Class not found",
|
|
||||||
"Illegal access",
|
|
||||||
"Instantiation error",
|
|
||||||
"Malformed url",
|
|
||||||
"IO error",
|
|
||||||
"Invalid action",
|
|
||||||
"JSON error",
|
|
||||||
"Error"
|
|
||||||
};
|
|
||||||
|
|
||||||
public enum Status {
|
|
||||||
NO_RESULT,
|
|
||||||
OK,
|
|
||||||
CLASS_NOT_FOUND_EXCEPTION,
|
|
||||||
ILLEGAL_ACCESS_EXCEPTION,
|
|
||||||
INSTANTIATION_EXCEPTION,
|
|
||||||
MALFORMED_URL_EXCEPTION,
|
|
||||||
IO_EXCEPTION,
|
|
||||||
INVALID_ACTION,
|
|
||||||
JSON_EXCEPTION,
|
|
||||||
ERROR
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ResumeCallback extends CallbackContext {
|
|
||||||
private final String TAG = "CordovaResumeCallback";
|
|
||||||
private String serviceName;
|
|
||||||
private PluginManager pluginManager;
|
|
||||||
|
|
||||||
public ResumeCallback(String serviceName, PluginManager pluginManager) {
|
|
||||||
super("resumecallback", null);
|
|
||||||
this.serviceName = serviceName;
|
|
||||||
this.pluginManager = pluginManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendPluginResult(PluginResult pluginResult) {
|
|
||||||
synchronized (this) {
|
|
||||||
if (finished) {
|
|
||||||
LOG.w(TAG, serviceName + " attempted to send a second callback to ResumeCallback\nResult was: " + pluginResult.getMessage());
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
finished = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONObject event = new JSONObject();
|
|
||||||
JSONObject pluginResultObject = new JSONObject();
|
|
||||||
|
|
||||||
try {
|
|
||||||
pluginResultObject.put("pluginServiceName", this.serviceName);
|
|
||||||
pluginResultObject.put("pluginStatus", PluginResult.StatusMessages[pluginResult.getStatus()]);
|
|
||||||
|
|
||||||
event.put("action", "resume");
|
|
||||||
event.put("pendingResult", pluginResultObject);
|
|
||||||
} catch (JSONException e) {
|
|
||||||
LOG.e(TAG, "Unable to create resume object for Activity Result");
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginResult eventResult = new PluginResult(PluginResult.Status.OK, event);
|
|
||||||
|
|
||||||
// We send a list of results to the js so that we don't have to decode
|
|
||||||
// the PluginResult passed to this CallbackContext into JSON twice.
|
|
||||||
// The results are combined into an event payload before the event is
|
|
||||||
// fired on the js side of things (see platform.js)
|
|
||||||
List<PluginResult> result = new ArrayList<PluginResult>();
|
|
||||||
result.add(eventResult);
|
|
||||||
result.add(pluginResult);
|
|
||||||
|
|
||||||
CoreAndroid appPlugin = (CoreAndroid) pluginManager.getPlugin(CoreAndroid.PLUGIN_NAME);
|
|
||||||
appPlugin.sendResumeEvent(new PluginResult(PluginResult.Status.OK, result));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova;
|
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.apache.cordova.LOG;
|
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
public class Whitelist {
|
|
||||||
private static class URLPattern {
|
|
||||||
public Pattern scheme;
|
|
||||||
public Pattern host;
|
|
||||||
public Integer port;
|
|
||||||
public Pattern path;
|
|
||||||
|
|
||||||
private String regexFromPattern(String pattern, boolean allowWildcards) {
|
|
||||||
final String toReplace = "\\.[]{}()^$?+|";
|
|
||||||
StringBuilder regex = new StringBuilder();
|
|
||||||
for (int i=0; i < pattern.length(); i++) {
|
|
||||||
char c = pattern.charAt(i);
|
|
||||||
if (c == '*' && allowWildcards) {
|
|
||||||
regex.append(".");
|
|
||||||
} else if (toReplace.indexOf(c) > -1) {
|
|
||||||
regex.append('\\');
|
|
||||||
}
|
|
||||||
regex.append(c);
|
|
||||||
}
|
|
||||||
return regex.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public URLPattern(String scheme, String host, String port, String path) throws MalformedURLException {
|
|
||||||
try {
|
|
||||||
if (scheme == null || "*".equals(scheme)) {
|
|
||||||
this.scheme = null;
|
|
||||||
} else {
|
|
||||||
this.scheme = Pattern.compile(regexFromPattern(scheme, false), Pattern.CASE_INSENSITIVE);
|
|
||||||
}
|
|
||||||
if ("*".equals(host)) {
|
|
||||||
this.host = null;
|
|
||||||
} else if (host.startsWith("*.")) {
|
|
||||||
this.host = Pattern.compile("([a-z0-9.-]*\\.)?" + regexFromPattern(host.substring(2), false), Pattern.CASE_INSENSITIVE);
|
|
||||||
} else {
|
|
||||||
this.host = Pattern.compile(regexFromPattern(host, false), Pattern.CASE_INSENSITIVE);
|
|
||||||
}
|
|
||||||
if (port == null || "*".equals(port)) {
|
|
||||||
this.port = null;
|
|
||||||
} else {
|
|
||||||
this.port = Integer.parseInt(port,10);
|
|
||||||
}
|
|
||||||
if (path == null || "/*".equals(path)) {
|
|
||||||
this.path = null;
|
|
||||||
} else {
|
|
||||||
this.path = Pattern.compile(regexFromPattern(path, true));
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new MalformedURLException("Port must be a number");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean matches(Uri uri) {
|
|
||||||
try {
|
|
||||||
return ((scheme == null || scheme.matcher(uri.getScheme()).matches()) &&
|
|
||||||
(host == null || host.matcher(uri.getHost()).matches()) &&
|
|
||||||
(port == null || port.equals(uri.getPort())) &&
|
|
||||||
(path == null || path.matcher(uri.getPath()).matches()));
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.d(TAG, e.toString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArrayList<URLPattern> whiteList;
|
|
||||||
|
|
||||||
public static final String TAG = "Whitelist";
|
|
||||||
|
|
||||||
public Whitelist() {
|
|
||||||
this.whiteList = new ArrayList<URLPattern>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Match patterns (from http://developer.chrome.com/extensions/match_patterns.html)
|
|
||||||
*
|
|
||||||
* <url-pattern> := <scheme>://<host><path>
|
|
||||||
* <scheme> := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome-extension'
|
|
||||||
* <host> := '*' | '*.' <any char except '/' and '*'>+
|
|
||||||
* <path> := '/' <any chars>
|
|
||||||
*
|
|
||||||
* We extend this to explicitly allow a port attached to the host, and we allow
|
|
||||||
* the scheme to be omitted for backwards compatibility. (Also host is not required
|
|
||||||
* to begin with a "*" or "*.".)
|
|
||||||
*/
|
|
||||||
public void addWhiteListEntry(String origin, boolean subdomains) {
|
|
||||||
if (whiteList != null) {
|
|
||||||
try {
|
|
||||||
// Unlimited access to network resources
|
|
||||||
if (origin.compareTo("*") == 0) {
|
|
||||||
LOG.d(TAG, "Unlimited access to network resources");
|
|
||||||
whiteList = null;
|
|
||||||
}
|
|
||||||
else { // specific access
|
|
||||||
Pattern parts = Pattern.compile("^((\\*|[A-Za-z-]+):(//)?)?(\\*|((\\*\\.)?[^*/:]+))?(:(\\d+))?(/.*)?");
|
|
||||||
Matcher m = parts.matcher(origin);
|
|
||||||
if (m.matches()) {
|
|
||||||
String scheme = m.group(2);
|
|
||||||
String host = m.group(4);
|
|
||||||
// Special case for two urls which are allowed to have empty hosts
|
|
||||||
if (("file".equals(scheme) || "content".equals(scheme)) && host == null) host = "*";
|
|
||||||
String port = m.group(8);
|
|
||||||
String path = m.group(9);
|
|
||||||
if (scheme == null) {
|
|
||||||
// XXX making it stupid friendly for people who forget to include protocol/SSL
|
|
||||||
whiteList.add(new URLPattern("http", host, port, path));
|
|
||||||
whiteList.add(new URLPattern("https", host, port, path));
|
|
||||||
} else {
|
|
||||||
whiteList.add(new URLPattern(scheme, host, port, path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.d(TAG, "Failed to add origin %s", origin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if URL is in approved list of URLs to load.
|
|
||||||
*
|
|
||||||
* @param uri
|
|
||||||
* @return true if wide open or whitelisted
|
|
||||||
*/
|
|
||||||
public boolean isUrlWhiteListed(String uri) {
|
|
||||||
// If there is no whitelist, then it's wide open
|
|
||||||
if (whiteList == null) return true;
|
|
||||||
|
|
||||||
Uri parsedUri = Uri.parse(uri);
|
|
||||||
// Look for match in white list
|
|
||||||
Iterator<URLPattern> pit = whiteList.iterator();
|
|
||||||
while (pit.hasNext()) {
|
|
||||||
URLPattern p = pit.next();
|
|
||||||
if (p.matches(parsedUri)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.cordova.engine;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.webkit.CookieManager;
|
|
||||||
import android.webkit.WebView;
|
|
||||||
|
|
||||||
import org.apache.cordova.ICordovaCookieManager;
|
|
||||||
|
|
||||||
class SystemCookieManager implements ICordovaCookieManager {
|
|
||||||
|
|
||||||
protected final WebView webView;
|
|
||||||
private final CookieManager cookieManager;
|
|
||||||
|
|
||||||
//Added because lint can't see the conditional RIGHT ABOVE this
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public SystemCookieManager(WebView webview) {
|
|
||||||
webView = webview;
|
|
||||||
cookieManager = CookieManager.getInstance();
|
|
||||||
|
|
||||||
//REALLY? Nobody has seen this UNTIL NOW?
|
|
||||||
cookieManager.setAcceptFileSchemeCookies(true);
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
cookieManager.setAcceptThirdPartyCookies(webView, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCookiesEnabled(boolean accept) {
|
|
||||||
cookieManager.setAcceptCookie(accept);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCookie(final String url, final String value) {
|
|
||||||
cookieManager.setCookie(url, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCookie(final String url) {
|
|
||||||
return cookieManager.getCookie(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearCookies() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
cookieManager.removeAllCookies(null);
|
|
||||||
} else {
|
|
||||||
cookieManager.removeAllCookie();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
cookieManager.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova.engine;
|
|
||||||
|
|
||||||
import android.webkit.JavascriptInterface;
|
|
||||||
|
|
||||||
import org.apache.cordova.CordovaBridge;
|
|
||||||
import org.apache.cordova.ExposedJsApi;
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains APIs that the JS can call. All functions in here should also have
|
|
||||||
* an equivalent entry in CordovaChromeClient.java, and be added to
|
|
||||||
* cordova-js/lib/android/plugin/android/promptbasednativeapi.js
|
|
||||||
*/
|
|
||||||
class SystemExposedJsApi implements ExposedJsApi {
|
|
||||||
private final CordovaBridge bridge;
|
|
||||||
|
|
||||||
SystemExposedJsApi(CordovaBridge bridge) {
|
|
||||||
this.bridge = bridge;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JavascriptInterface
|
|
||||||
public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
|
|
||||||
return bridge.jsExec(bridgeSecret, service, action, callbackId, arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JavascriptInterface
|
|
||||||
public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
|
|
||||||
bridge.jsSetNativeToJsBridgeMode(bridgeSecret, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JavascriptInterface
|
|
||||||
public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
|
|
||||||
return bridge.jsRetrieveJsMessages(bridgeSecret, fromOnlineEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,280 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova.engine;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup.LayoutParams;
|
|
||||||
import android.webkit.ConsoleMessage;
|
|
||||||
import android.webkit.GeolocationPermissions.Callback;
|
|
||||||
import android.webkit.JsPromptResult;
|
|
||||||
import android.webkit.JsResult;
|
|
||||||
import android.webkit.ValueCallback;
|
|
||||||
import android.webkit.WebChromeClient;
|
|
||||||
import android.webkit.WebStorage;
|
|
||||||
import android.webkit.WebView;
|
|
||||||
import android.webkit.PermissionRequest;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.ProgressBar;
|
|
||||||
import android.widget.RelativeLayout;
|
|
||||||
|
|
||||||
import org.apache.cordova.CordovaDialogsHelper;
|
|
||||||
import org.apache.cordova.CordovaPlugin;
|
|
||||||
import org.apache.cordova.LOG;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is the WebChromeClient that implements callbacks for our web view.
|
|
||||||
* The kind of callbacks that happen here are on the chrome outside the document,
|
|
||||||
* such as onCreateWindow(), onConsoleMessage(), onProgressChanged(), etc. Related
|
|
||||||
* to but different than CordovaWebViewClient.
|
|
||||||
*/
|
|
||||||
public class SystemWebChromeClient extends WebChromeClient {
|
|
||||||
|
|
||||||
private static final int FILECHOOSER_RESULTCODE = 5173;
|
|
||||||
private static final String LOG_TAG = "SystemWebChromeClient";
|
|
||||||
private long MAX_QUOTA = 100 * 1024 * 1024;
|
|
||||||
protected final SystemWebViewEngine parentEngine;
|
|
||||||
|
|
||||||
// the video progress view
|
|
||||||
private View mVideoProgressView;
|
|
||||||
|
|
||||||
private CordovaDialogsHelper dialogsHelper;
|
|
||||||
private Context appContext;
|
|
||||||
|
|
||||||
private WebChromeClient.CustomViewCallback mCustomViewCallback;
|
|
||||||
private View mCustomView;
|
|
||||||
|
|
||||||
public SystemWebChromeClient(SystemWebViewEngine parentEngine) {
|
|
||||||
this.parentEngine = parentEngine;
|
|
||||||
appContext = parentEngine.webView.getContext();
|
|
||||||
dialogsHelper = new CordovaDialogsHelper(appContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the client to display a javascript alert dialog.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
|
|
||||||
dialogsHelper.showAlert(message, new CordovaDialogsHelper.Result() {
|
|
||||||
@Override public void gotResult(boolean success, String value) {
|
|
||||||
if (success) {
|
|
||||||
result.confirm();
|
|
||||||
} else {
|
|
||||||
result.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the client to display a confirm dialog to the user.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
|
|
||||||
dialogsHelper.showConfirm(message, new CordovaDialogsHelper.Result() {
|
|
||||||
@Override
|
|
||||||
public void gotResult(boolean success, String value) {
|
|
||||||
if (success) {
|
|
||||||
result.confirm();
|
|
||||||
} else {
|
|
||||||
result.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the client to display a prompt dialog to the user.
|
|
||||||
* If the client returns true, WebView will assume that the client will
|
|
||||||
* handle the prompt dialog and call the appropriate JsPromptResult method.
|
|
||||||
*
|
|
||||||
* Since we are hacking prompts for our own purposes, we should not be using them for
|
|
||||||
* this purpose, perhaps we should hack console.log to do this instead!
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean onJsPrompt(WebView view, String origin, String message, String defaultValue, final JsPromptResult result) {
|
|
||||||
// Unlike the @JavascriptInterface bridge, this method is always called on the UI thread.
|
|
||||||
String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message, defaultValue);
|
|
||||||
if (handledRet != null) {
|
|
||||||
result.confirm(handledRet);
|
|
||||||
} else {
|
|
||||||
dialogsHelper.showPrompt(message, defaultValue, new CordovaDialogsHelper.Result() {
|
|
||||||
@Override
|
|
||||||
public void gotResult(boolean success, String value) {
|
|
||||||
if (success) {
|
|
||||||
result.confirm(value);
|
|
||||||
} else {
|
|
||||||
result.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle database quota exceeded notification.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
|
|
||||||
long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
|
|
||||||
{
|
|
||||||
LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d currentQuota: %d totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
|
|
||||||
quotaUpdater.updateQuota(MAX_QUOTA);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onConsoleMessage(ConsoleMessage consoleMessage)
|
|
||||||
{
|
|
||||||
if (consoleMessage.message() != null)
|
|
||||||
LOG.d(LOG_TAG, "%s: Line %d : %s" , consoleMessage.sourceId() , consoleMessage.lineNumber(), consoleMessage.message());
|
|
||||||
return super.onConsoleMessage(consoleMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
/**
|
|
||||||
* Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
|
|
||||||
*
|
|
||||||
* This also checks for the Geolocation Plugin and requests permission from the application to use Geolocation.
|
|
||||||
*
|
|
||||||
* @param origin
|
|
||||||
* @param callback
|
|
||||||
*/
|
|
||||||
public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
|
|
||||||
super.onGeolocationPermissionsShowPrompt(origin, callback);
|
|
||||||
callback.invoke(origin, true, false);
|
|
||||||
//Get the plugin, it should be loaded
|
|
||||||
CordovaPlugin geolocation = parentEngine.pluginManager.getPlugin("Geolocation");
|
|
||||||
if(geolocation != null && !geolocation.hasPermisssion())
|
|
||||||
{
|
|
||||||
geolocation.requestPermissions(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// API level 7 is required for this, see if we could lower this using something else
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) {
|
|
||||||
parentEngine.getCordovaWebView().showCustomView(view, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void onHideCustomView() {
|
|
||||||
parentEngine.getCordovaWebView().hideCustomView();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
/**
|
|
||||||
* Ask the host application for a custom progress view to show while
|
|
||||||
* a <video> is loading.
|
|
||||||
* @return View The progress view.
|
|
||||||
*/
|
|
||||||
public View getVideoLoadingProgressView() {
|
|
||||||
|
|
||||||
if (mVideoProgressView == null) {
|
|
||||||
// Create a new Loading view programmatically.
|
|
||||||
|
|
||||||
// create the linear layout
|
|
||||||
LinearLayout layout = new LinearLayout(parentEngine.getView().getContext());
|
|
||||||
layout.setOrientation(LinearLayout.VERTICAL);
|
|
||||||
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
|
||||||
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
|
|
||||||
layout.setLayoutParams(layoutParams);
|
|
||||||
// the proress bar
|
|
||||||
ProgressBar bar = new ProgressBar(parentEngine.getView().getContext());
|
|
||||||
LinearLayout.LayoutParams barLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
|
||||||
barLayoutParams.gravity = Gravity.CENTER;
|
|
||||||
bar.setLayoutParams(barLayoutParams);
|
|
||||||
layout.addView(bar);
|
|
||||||
|
|
||||||
mVideoProgressView = layout;
|
|
||||||
}
|
|
||||||
return mVideoProgressView;
|
|
||||||
}
|
|
||||||
|
|
||||||
// <input type=file> support:
|
|
||||||
// openFileChooser() is for pre KitKat and in KitKat mr1 (it's known broken in KitKat).
|
|
||||||
// For Lollipop, we use onShowFileChooser().
|
|
||||||
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
|
|
||||||
this.openFileChooser(uploadMsg, "*/*");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType ) {
|
|
||||||
this.openFileChooser(uploadMsg, acceptType, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void openFileChooser(final ValueCallback<Uri> uploadMsg, String acceptType, String capture)
|
|
||||||
{
|
|
||||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
||||||
intent.setType("*/*");
|
|
||||||
parentEngine.cordova.startActivityForResult(new CordovaPlugin() {
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
|
||||||
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
|
|
||||||
LOG.d(LOG_TAG, "Receive file chooser URL: " + result);
|
|
||||||
uploadMsg.onReceiveValue(result);
|
|
||||||
}
|
|
||||||
}, intent, FILECHOOSER_RESULTCODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
@Override
|
|
||||||
public boolean onShowFileChooser(WebView webView, final ValueCallback<Uri[]> filePathsCallback, final WebChromeClient.FileChooserParams fileChooserParams) {
|
|
||||||
Intent intent = fileChooserParams.createIntent();
|
|
||||||
try {
|
|
||||||
parentEngine.cordova.startActivityForResult(new CordovaPlugin() {
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
|
||||||
Uri[] result = WebChromeClient.FileChooserParams.parseResult(resultCode, intent);
|
|
||||||
LOG.d(LOG_TAG, "Receive file chooser URL: " + result);
|
|
||||||
filePathsCallback.onReceiveValue(result);
|
|
||||||
}
|
|
||||||
}, intent, FILECHOOSER_RESULTCODE);
|
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
LOG.w("No activity found to handle file chooser intent.", e);
|
|
||||||
filePathsCallback.onReceiveValue(null);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
@Override
|
|
||||||
public void onPermissionRequest(final PermissionRequest request) {
|
|
||||||
LOG.d(LOG_TAG, "onPermissionRequest: " + Arrays.toString(request.getResources()));
|
|
||||||
request.grant(request.getResources());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroyLastDialog(){
|
|
||||||
dialogsHelper.destroyLastDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.cordova.engine;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.webkit.WebChromeClient;
|
|
||||||
import android.webkit.WebView;
|
|
||||||
import android.webkit.WebViewClient;
|
|
||||||
|
|
||||||
import org.apache.cordova.CordovaInterface;
|
|
||||||
import org.apache.cordova.CordovaWebView;
|
|
||||||
import org.apache.cordova.CordovaWebViewEngine;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom WebView subclass that enables us to capture events needed for Cordova.
|
|
||||||
*/
|
|
||||||
public class SystemWebView extends WebView implements CordovaWebViewEngine.EngineView {
|
|
||||||
private SystemWebViewClient viewClient;
|
|
||||||
SystemWebChromeClient chromeClient;
|
|
||||||
private SystemWebViewEngine parentEngine;
|
|
||||||
private CordovaInterface cordova;
|
|
||||||
|
|
||||||
public SystemWebView(Context context) {
|
|
||||||
this(context, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SystemWebView(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Package visibility to enforce that only SystemWebViewEngine should call this method.
|
|
||||||
void init(SystemWebViewEngine parentEngine, CordovaInterface cordova) {
|
|
||||||
this.cordova = cordova;
|
|
||||||
this.parentEngine = parentEngine;
|
|
||||||
if (this.viewClient == null) {
|
|
||||||
setWebViewClient(new SystemWebViewClient(parentEngine));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.chromeClient == null) {
|
|
||||||
setWebChromeClient(new SystemWebChromeClient(parentEngine));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CordovaWebView getCordovaWebView() {
|
|
||||||
return parentEngine != null ? parentEngine.getCordovaWebView() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWebViewClient(WebViewClient client) {
|
|
||||||
viewClient = (SystemWebViewClient)client;
|
|
||||||
super.setWebViewClient(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWebChromeClient(WebChromeClient client) {
|
|
||||||
chromeClient = (SystemWebChromeClient)client;
|
|
||||||
super.setWebChromeClient(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
|
||||||
Boolean ret = parentEngine.client.onDispatchKeyEvent(event);
|
|
||||||
if (ret != null) {
|
|
||||||
return ret.booleanValue();
|
|
||||||
}
|
|
||||||
return super.dispatchKeyEvent(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,370 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.cordova.engine;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.net.http.SslError;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.webkit.ClientCertRequest;
|
|
||||||
import android.webkit.HttpAuthHandler;
|
|
||||||
import android.webkit.SslErrorHandler;
|
|
||||||
import android.webkit.WebResourceResponse;
|
|
||||||
import android.webkit.WebView;
|
|
||||||
import android.webkit.WebViewClient;
|
|
||||||
|
|
||||||
import org.apache.cordova.AuthenticationToken;
|
|
||||||
import org.apache.cordova.CordovaClientCertRequest;
|
|
||||||
import org.apache.cordova.CordovaHttpAuthHandler;
|
|
||||||
import org.apache.cordova.CordovaResourceApi;
|
|
||||||
import org.apache.cordova.LOG;
|
|
||||||
import org.apache.cordova.PluginManager;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is the WebViewClient that implements callbacks for our web view.
|
|
||||||
* The kind of callbacks that happen here are regarding the rendering of the
|
|
||||||
* document instead of the chrome surrounding it, such as onPageStarted(),
|
|
||||||
* shouldOverrideUrlLoading(), etc. Related to but different than
|
|
||||||
* CordovaChromeClient.
|
|
||||||
*/
|
|
||||||
public class SystemWebViewClient extends WebViewClient {
|
|
||||||
|
|
||||||
private static final String TAG = "SystemWebViewClient";
|
|
||||||
protected final SystemWebViewEngine parentEngine;
|
|
||||||
private boolean doClearHistory = false;
|
|
||||||
boolean isCurrentlyLoading;
|
|
||||||
|
|
||||||
/** The authorization tokens. */
|
|
||||||
private Hashtable<String, AuthenticationToken> authenticationTokens = new Hashtable<String, AuthenticationToken>();
|
|
||||||
|
|
||||||
public SystemWebViewClient(SystemWebViewEngine parentEngine) {
|
|
||||||
this.parentEngine = parentEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Give the host application a chance to take over the control when a new url
|
|
||||||
* is about to be loaded in the current WebView.
|
|
||||||
*
|
|
||||||
* @param view The WebView that is initiating the callback.
|
|
||||||
* @param url The url to be loaded.
|
|
||||||
* @return true to override, false for default behavior
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
|
||||||
return parentEngine.client.onNavigationAttempt(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On received http auth request.
|
|
||||||
* The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
|
|
||||||
|
|
||||||
// Get the authentication token (if specified)
|
|
||||||
AuthenticationToken token = this.getAuthenticationToken(host, realm);
|
|
||||||
if (token != null) {
|
|
||||||
handler.proceed(token.getUserName(), token.getPassword());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if there is some plugin which can resolve this auth challenge
|
|
||||||
PluginManager pluginManager = this.parentEngine.pluginManager;
|
|
||||||
if (pluginManager != null && pluginManager.onReceivedHttpAuthRequest(null, new CordovaHttpAuthHandler(handler), host, realm)) {
|
|
||||||
parentEngine.client.clearLoadTimeoutTimer();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// By default handle 401 like we'd normally do!
|
|
||||||
super.onReceivedHttpAuthRequest(view, handler, host, realm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On received client cert request.
|
|
||||||
* The method forwards the request to any running plugins before using the default implementation.
|
|
||||||
*
|
|
||||||
* @param view
|
|
||||||
* @param request
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
public void onReceivedClientCertRequest (WebView view, ClientCertRequest request)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Check if there is some plugin which can resolve this certificate request
|
|
||||||
PluginManager pluginManager = this.parentEngine.pluginManager;
|
|
||||||
if (pluginManager != null && pluginManager.onReceivedClientCertRequest(null, new CordovaClientCertRequest(request))) {
|
|
||||||
parentEngine.client.clearLoadTimeoutTimer();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// By default pass to WebViewClient
|
|
||||||
super.onReceivedClientCertRequest(view, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify the host application that a page has started loading.
|
|
||||||
* This method is called once for each main frame load so a page with iframes or framesets will call onPageStarted
|
|
||||||
* one time for the main frame. This also means that onPageStarted will not be called when the contents of an
|
|
||||||
* embedded frame changes, i.e. clicking a link whose target is an iframe.
|
|
||||||
*
|
|
||||||
* @param view The webview initiating the callback.
|
|
||||||
* @param url The url of the page.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
|
||||||
super.onPageStarted(view, url, favicon);
|
|
||||||
isCurrentlyLoading = true;
|
|
||||||
// Flush stale messages & reset plugins.
|
|
||||||
parentEngine.bridge.reset();
|
|
||||||
parentEngine.client.onPageStarted(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify the host application that a page has finished loading.
|
|
||||||
* This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param view The webview initiating the callback.
|
|
||||||
* @param url The url of the page.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onPageFinished(WebView view, String url) {
|
|
||||||
super.onPageFinished(view, url);
|
|
||||||
// Ignore excessive calls, if url is not about:blank (CB-8317).
|
|
||||||
if (!isCurrentlyLoading && !url.startsWith("about:")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
isCurrentlyLoading = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Because of a timing issue we need to clear this history in onPageFinished as well as
|
|
||||||
* onPageStarted. However we only want to do this if the doClearHistory boolean is set to
|
|
||||||
* true. You see when you load a url with a # in it which is common in jQuery applications
|
|
||||||
* onPageStared is not called. Clearing the history at that point would break jQuery apps.
|
|
||||||
*/
|
|
||||||
if (this.doClearHistory) {
|
|
||||||
view.clearHistory();
|
|
||||||
this.doClearHistory = false;
|
|
||||||
}
|
|
||||||
parentEngine.client.onPageFinishedLoading(url);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable).
|
|
||||||
* The errorCode parameter corresponds to one of the ERROR_* constants.
|
|
||||||
*
|
|
||||||
* @param view The WebView that is initiating the callback.
|
|
||||||
* @param errorCode The error code corresponding to an ERROR_* value.
|
|
||||||
* @param description A String describing the error.
|
|
||||||
* @param failingUrl The url that failed to load.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
|
|
||||||
// Ignore error due to stopLoading().
|
|
||||||
if (!isCurrentlyLoading) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LOG.d(TAG, "CordovaWebViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl);
|
|
||||||
|
|
||||||
// If this is a "Protocol Not Supported" error, then revert to the previous
|
|
||||||
// page. If there was no previous page, then punt. The application's config
|
|
||||||
// is likely incorrect (start page set to sms: or something like that)
|
|
||||||
if (errorCode == WebViewClient.ERROR_UNSUPPORTED_SCHEME) {
|
|
||||||
parentEngine.client.clearLoadTimeoutTimer();
|
|
||||||
|
|
||||||
if (view.canGoBack()) {
|
|
||||||
view.goBack();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
super.onReceivedError(view, errorCode, description, failingUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parentEngine.client.onReceivedError(errorCode, description, failingUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify the host application that an SSL error occurred while loading a resource.
|
|
||||||
* The host application must call either handler.cancel() or handler.proceed().
|
|
||||||
* Note that the decision may be retained for use in response to future SSL errors.
|
|
||||||
* The default behavior is to cancel the load.
|
|
||||||
*
|
|
||||||
* @param view The WebView that is initiating the callback.
|
|
||||||
* @param handler An SslErrorHandler object that will handle the user's response.
|
|
||||||
* @param error The SSL error object.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
|
|
||||||
|
|
||||||
final String packageName = parentEngine.cordova.getActivity().getPackageName();
|
|
||||||
final PackageManager pm = parentEngine.cordova.getActivity().getPackageManager();
|
|
||||||
|
|
||||||
ApplicationInfo appInfo;
|
|
||||||
try {
|
|
||||||
appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
|
|
||||||
if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
|
|
||||||
// debug = true
|
|
||||||
handler.proceed();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// debug = false
|
|
||||||
super.onReceivedSslError(view, handler, error);
|
|
||||||
}
|
|
||||||
} catch (NameNotFoundException e) {
|
|
||||||
// When it doubt, lock it out!
|
|
||||||
super.onReceivedSslError(view, handler, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the authentication token.
|
|
||||||
*
|
|
||||||
* @param authenticationToken
|
|
||||||
* @param host
|
|
||||||
* @param realm
|
|
||||||
*/
|
|
||||||
public void setAuthenticationToken(AuthenticationToken authenticationToken, String host, String realm) {
|
|
||||||
if (host == null) {
|
|
||||||
host = "";
|
|
||||||
}
|
|
||||||
if (realm == null) {
|
|
||||||
realm = "";
|
|
||||||
}
|
|
||||||
this.authenticationTokens.put(host.concat(realm), authenticationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the authentication token.
|
|
||||||
*
|
|
||||||
* @param host
|
|
||||||
* @param realm
|
|
||||||
*
|
|
||||||
* @return the authentication token or null if did not exist
|
|
||||||
*/
|
|
||||||
public AuthenticationToken removeAuthenticationToken(String host, String realm) {
|
|
||||||
return this.authenticationTokens.remove(host.concat(realm));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the authentication token.
|
|
||||||
*
|
|
||||||
* In order it tries:
|
|
||||||
* 1- host + realm
|
|
||||||
* 2- host
|
|
||||||
* 3- realm
|
|
||||||
* 4- no host, no realm
|
|
||||||
*
|
|
||||||
* @param host
|
|
||||||
* @param realm
|
|
||||||
*
|
|
||||||
* @return the authentication token
|
|
||||||
*/
|
|
||||||
public AuthenticationToken getAuthenticationToken(String host, String realm) {
|
|
||||||
AuthenticationToken token = null;
|
|
||||||
token = this.authenticationTokens.get(host.concat(realm));
|
|
||||||
|
|
||||||
if (token == null) {
|
|
||||||
// try with just the host
|
|
||||||
token = this.authenticationTokens.get(host);
|
|
||||||
|
|
||||||
// Try the realm
|
|
||||||
if (token == null) {
|
|
||||||
token = this.authenticationTokens.get(realm);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no host found, just query for default
|
|
||||||
if (token == null) {
|
|
||||||
token = this.authenticationTokens.get("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear all authentication tokens.
|
|
||||||
*/
|
|
||||||
public void clearAuthenticationTokens() {
|
|
||||||
this.authenticationTokens.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
|
|
||||||
try {
|
|
||||||
// Check the against the whitelist and lock out access to the WebView directory
|
|
||||||
// Changing this will cause problems for your application
|
|
||||||
if (!parentEngine.pluginManager.shouldAllowRequest(url)) {
|
|
||||||
LOG.w(TAG, "URL blocked by whitelist: " + url);
|
|
||||||
// Results in a 404.
|
|
||||||
return new WebResourceResponse("text/plain", "UTF-8", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
CordovaResourceApi resourceApi = parentEngine.resourceApi;
|
|
||||||
Uri origUri = Uri.parse(url);
|
|
||||||
// Allow plugins to intercept WebView requests.
|
|
||||||
Uri remappedUri = resourceApi.remapUri(origUri);
|
|
||||||
|
|
||||||
if (!origUri.equals(remappedUri) || needsSpecialsInAssetUrlFix(origUri) || needsKitKatContentUrlFix(origUri)) {
|
|
||||||
CordovaResourceApi.OpenForReadResult result = resourceApi.openForRead(remappedUri, true);
|
|
||||||
return new WebResourceResponse(result.mimeType, "UTF-8", result.inputStream);
|
|
||||||
}
|
|
||||||
// If we don't need to special-case the request, let the browser load it.
|
|
||||||
return null;
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (!(e instanceof FileNotFoundException)) {
|
|
||||||
LOG.e(TAG, "Error occurred while loading a file (returning a 404).", e);
|
|
||||||
}
|
|
||||||
// Results in a 404.
|
|
||||||
return new WebResourceResponse("text/plain", "UTF-8", null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean needsKitKatContentUrlFix(Uri uri) {
|
|
||||||
return "content".equals(uri.getScheme());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean needsSpecialsInAssetUrlFix(Uri uri) {
|
|
||||||
if (CordovaResourceApi.getUriType(uri) != CordovaResourceApi.URI_TYPE_ASSET) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (uri.getQuery() != null || uri.getFragment() != null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!uri.toString().contains("%")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,319 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.cordova.engine;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.view.View;
|
|
||||||
import android.webkit.ValueCallback;
|
|
||||||
import android.webkit.WebSettings;
|
|
||||||
import android.webkit.WebSettings.LayoutAlgorithm;
|
|
||||||
import android.webkit.WebView;
|
|
||||||
|
|
||||||
import org.apache.cordova.CordovaBridge;
|
|
||||||
import org.apache.cordova.CordovaInterface;
|
|
||||||
import org.apache.cordova.CordovaPreferences;
|
|
||||||
import org.apache.cordova.CordovaResourceApi;
|
|
||||||
import org.apache.cordova.CordovaWebView;
|
|
||||||
import org.apache.cordova.CordovaWebViewEngine;
|
|
||||||
import org.apache.cordova.ICordovaCookieManager;
|
|
||||||
import org.apache.cordova.LOG;
|
|
||||||
import org.apache.cordova.NativeToJsMessageQueue;
|
|
||||||
import org.apache.cordova.PluginManager;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Glue class between CordovaWebView (main Cordova logic) and SystemWebView (the actual View).
|
|
||||||
* We make the Engine separate from the actual View so that:
|
|
||||||
* A) We don't need to worry about WebView methods clashing with CordovaWebViewEngine methods
|
|
||||||
* (e.g.: goBack() is void for WebView, and boolean for CordovaWebViewEngine)
|
|
||||||
* B) Separating the actual View from the Engine makes API surfaces smaller.
|
|
||||||
* Class uses two-phase initialization. However, CordovaWebView is responsible for calling .init().
|
|
||||||
*/
|
|
||||||
public class SystemWebViewEngine implements CordovaWebViewEngine {
|
|
||||||
public static final String TAG = "SystemWebViewEngine";
|
|
||||||
|
|
||||||
protected final SystemWebView webView;
|
|
||||||
protected final SystemCookieManager cookieManager;
|
|
||||||
protected CordovaPreferences preferences;
|
|
||||||
protected CordovaBridge bridge;
|
|
||||||
protected CordovaWebViewEngine.Client client;
|
|
||||||
protected CordovaWebView parentWebView;
|
|
||||||
protected CordovaInterface cordova;
|
|
||||||
protected PluginManager pluginManager;
|
|
||||||
protected CordovaResourceApi resourceApi;
|
|
||||||
protected NativeToJsMessageQueue nativeToJsMessageQueue;
|
|
||||||
private BroadcastReceiver receiver;
|
|
||||||
|
|
||||||
/** Used when created via reflection. */
|
|
||||||
public SystemWebViewEngine(Context context, CordovaPreferences preferences) {
|
|
||||||
this(new SystemWebView(context), preferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SystemWebViewEngine(SystemWebView webView) {
|
|
||||||
this(webView, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SystemWebViewEngine(SystemWebView webView, CordovaPreferences preferences) {
|
|
||||||
this.preferences = preferences;
|
|
||||||
this.webView = webView;
|
|
||||||
cookieManager = new SystemCookieManager(webView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(CordovaWebView parentWebView, CordovaInterface cordova, CordovaWebViewEngine.Client client,
|
|
||||||
CordovaResourceApi resourceApi, PluginManager pluginManager,
|
|
||||||
NativeToJsMessageQueue nativeToJsMessageQueue) {
|
|
||||||
if (this.cordova != null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
// Needed when prefs are not passed by the constructor
|
|
||||||
if (preferences == null) {
|
|
||||||
preferences = parentWebView.getPreferences();
|
|
||||||
}
|
|
||||||
this.parentWebView = parentWebView;
|
|
||||||
this.cordova = cordova;
|
|
||||||
this.client = client;
|
|
||||||
this.resourceApi = resourceApi;
|
|
||||||
this.pluginManager = pluginManager;
|
|
||||||
this.nativeToJsMessageQueue = nativeToJsMessageQueue;
|
|
||||||
webView.init(this, cordova);
|
|
||||||
|
|
||||||
initWebViewSettings();
|
|
||||||
|
|
||||||
nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode.OnlineEventsBridgeModeDelegate() {
|
|
||||||
@Override
|
|
||||||
public void setNetworkAvailable(boolean value) {
|
|
||||||
//sometimes this can be called after calling webview.destroy() on destroy()
|
|
||||||
//thus resulting in a NullPointerException
|
|
||||||
if(webView!=null) {
|
|
||||||
webView.setNetworkAvailable(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void runOnUiThread(Runnable r) {
|
|
||||||
SystemWebViewEngine.this.cordova.getActivity().runOnUiThread(r);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.EvalBridgeMode(this, cordova));
|
|
||||||
bridge = new CordovaBridge(pluginManager, nativeToJsMessageQueue);
|
|
||||||
exposeJsInterface(webView, bridge);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CordovaWebView getCordovaWebView() {
|
|
||||||
return parentWebView;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ICordovaCookieManager getCookieManager() {
|
|
||||||
return cookieManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getView() {
|
|
||||||
return webView;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint({"NewApi", "SetJavaScriptEnabled"})
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private void initWebViewSettings() {
|
|
||||||
webView.setInitialScale(0);
|
|
||||||
webView.setVerticalScrollBarEnabled(false);
|
|
||||||
// Enable JavaScript
|
|
||||||
final WebSettings settings = webView.getSettings();
|
|
||||||
settings.setJavaScriptEnabled(true);
|
|
||||||
settings.setJavaScriptCanOpenWindowsAutomatically(true);
|
|
||||||
settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
|
|
||||||
|
|
||||||
String manufacturer = android.os.Build.MANUFACTURER;
|
|
||||||
LOG.d(TAG, "CordovaWebView is running on device made by: " + manufacturer);
|
|
||||||
|
|
||||||
//We don't save any form data in the application
|
|
||||||
settings.setSaveFormData(false);
|
|
||||||
settings.setSavePassword(false);
|
|
||||||
|
|
||||||
// Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist
|
|
||||||
// while we do this
|
|
||||||
settings.setAllowUniversalAccessFromFileURLs(true);
|
|
||||||
settings.setMediaPlaybackRequiresUserGesture(false);
|
|
||||||
|
|
||||||
// Enable database
|
|
||||||
// We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16
|
|
||||||
String databasePath = webView.getContext().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
|
|
||||||
settings.setDatabaseEnabled(true);
|
|
||||||
settings.setDatabasePath(databasePath);
|
|
||||||
|
|
||||||
|
|
||||||
//Determine whether we're in debug or release mode, and turn on Debugging!
|
|
||||||
ApplicationInfo appInfo = webView.getContext().getApplicationContext().getApplicationInfo();
|
|
||||||
if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
|
|
||||||
enableRemoteDebugging();
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.setGeolocationDatabasePath(databasePath);
|
|
||||||
|
|
||||||
// Enable DOM storage
|
|
||||||
settings.setDomStorageEnabled(true);
|
|
||||||
|
|
||||||
// Enable built-in geolocation
|
|
||||||
settings.setGeolocationEnabled(true);
|
|
||||||
|
|
||||||
// Enable AppCache
|
|
||||||
// Fix for CB-2282
|
|
||||||
settings.setAppCacheMaxSize(5 * 1048576);
|
|
||||||
settings.setAppCachePath(databasePath);
|
|
||||||
settings.setAppCacheEnabled(true);
|
|
||||||
|
|
||||||
// Fix for CB-1405
|
|
||||||
// Google issue 4641
|
|
||||||
String defaultUserAgent = settings.getUserAgentString();
|
|
||||||
|
|
||||||
// Fix for CB-3360
|
|
||||||
String overrideUserAgent = preferences.getString("OverrideUserAgent", null);
|
|
||||||
if (overrideUserAgent != null) {
|
|
||||||
settings.setUserAgentString(overrideUserAgent);
|
|
||||||
} else {
|
|
||||||
String appendUserAgent = preferences.getString("AppendUserAgent", null);
|
|
||||||
if (appendUserAgent != null) {
|
|
||||||
settings.setUserAgentString(defaultUserAgent + " " + appendUserAgent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// End CB-3360
|
|
||||||
|
|
||||||
IntentFilter intentFilter = new IntentFilter();
|
|
||||||
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
|
|
||||||
if (this.receiver == null) {
|
|
||||||
this.receiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
settings.getUserAgentString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
webView.getContext().registerReceiver(this.receiver, intentFilter);
|
|
||||||
}
|
|
||||||
// end CB-1405
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enableRemoteDebugging() {
|
|
||||||
try {
|
|
||||||
WebView.setWebContentsDebuggingEnabled(true);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
LOG.d(TAG, "You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! ");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Yeah, we know. It'd be great if lint was just a little smarter.
|
|
||||||
@SuppressLint("AddJavascriptInterface")
|
|
||||||
private static void exposeJsInterface(WebView webView, CordovaBridge bridge) {
|
|
||||||
SystemExposedJsApi exposedJsApi = new SystemExposedJsApi(bridge);
|
|
||||||
webView.addJavascriptInterface(exposedJsApi, "_cordovaNative");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the url into the webview.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void loadUrl(final String url, boolean clearNavigationStack) {
|
|
||||||
webView.loadUrl(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUrl() {
|
|
||||||
return webView.getUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stopLoading() {
|
|
||||||
webView.stopLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearCache() {
|
|
||||||
webView.clearCache(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearHistory() {
|
|
||||||
webView.clearHistory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canGoBack() {
|
|
||||||
return webView.canGoBack();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Go to previous page in history. (We manage our own history)
|
|
||||||
*
|
|
||||||
* @return true if we went back, false if we are already at top
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean goBack() {
|
|
||||||
// Check webview first to see if there is a history
|
|
||||||
// This is needed to support curPage#diffLink, since they are added to parentEngine's history, but not our history url array (JQMobile behavior)
|
|
||||||
if (webView.canGoBack()) {
|
|
||||||
webView.goBack();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPaused(boolean value) {
|
|
||||||
if (value) {
|
|
||||||
webView.onPause();
|
|
||||||
webView.pauseTimers();
|
|
||||||
} else {
|
|
||||||
webView.onResume();
|
|
||||||
webView.resumeTimers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
webView.chromeClient.destroyLastDialog();
|
|
||||||
webView.destroy();
|
|
||||||
// unregister the receiver
|
|
||||||
if (receiver != null) {
|
|
||||||
try {
|
|
||||||
webView.getContext().unregisterReceiver(receiver);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void evaluateJavascript(String js, ValueCallback<String> callback) {
|
|
||||||
webView.evaluateJavascript(js, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,606 +0,0 @@
|
|||||||
{
|
|
||||||
"prepare_queue": {
|
|
||||||
"installed": [],
|
|
||||||
"uninstalled": []
|
|
||||||
},
|
|
||||||
"config_munge": {
|
|
||||||
"files": {
|
|
||||||
"res/xml/config.xml": {
|
|
||||||
"parents": {
|
|
||||||
"/*": [
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"ActionSheet\"><param name=\"android-package\" value=\"nl.xservices.plugins.actionsheet.ActionSheet\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"Permissions\"><param name=\"android-package\" value=\"com.android.plugins.Permissions\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"AppVersion\"><param name=\"android-package\" value=\"uk.co.whiteoctober.cordova.AppVersion\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"Camera\"><param name=\"android-package\" value=\"org.apache.cordova.camera.CameraLauncher\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"DatePickerPlugin\"><param name=\"android-package\" value=\"com.plugin.datepicker.DatePickerPlugin\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"Device\"><param name=\"android-package\" value=\"org.apache.cordova.device.Device\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"Notification\"><param name=\"android-package\" value=\"org.apache.cordova.dialogs.Notification\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"Fingerprint\"><param name=\"android-package\" value=\"de.niklasmerz.cordova.fingerprint.Fingerprint\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"Geolocation\"><param name=\"android-package\" value=\"org.apache.cordova.geolocation.Geolocation\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"SplashScreen\"><param name=\"android-package\" value=\"org.apache.cordova.splashscreen.SplashScreen\" /><param name=\"onload\" value=\"true\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"StatusBar\"><param name=\"android-package\" value=\"org.apache.cordova.statusbar.StatusBar\" /><param name=\"onload\" value=\"true\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"Whitelist\"><param name=\"android-package\" value=\"org.apache.cordova.whitelist.WhitelistPlugin\" /><param name=\"onload\" value=\"true\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"SQLitePlugin\"><param name=\"android-package\" value=\"io.sqlc.SQLitePlugin\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"PushNotification\"><param name=\"android-package\" value=\"com.adobe.phonegap.push.PushPlugin\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"LaunchNavigator\"><param name=\"android-package\" value=\"uk.co.workingedge.phonegap.plugin.LaunchNavigator\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"BackgroundGeolocation\"><param name=\"android-package\" value=\"com.tenforwardconsulting.bgloc.cordova.BackgroundGeolocationPlugin\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AndroidManifest.xml": {
|
|
||||||
"parents": {
|
|
||||||
"/*": [
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.USE_FINGERPRINT\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-feature android:name=\"android.hardware.location.gps\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />",
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"application": [
|
|
||||||
{
|
|
||||||
"xml": "<provider android:authorities=\"${applicationId}.provider\" android:exported=\"false\" android:grantUriPermissions=\"true\" android:name=\"org.apache.cordova.camera.FileProvider\"><meta-data android:name=\"android.support.FILE_PROVIDER_PATHS\" android:resource=\"@xml/camera_provider_paths\" /></provider>",
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"/manifest/application": [
|
|
||||||
{
|
|
||||||
"xml": "<activity android:exported=\"true\" android:name=\"com.adobe.phonegap.push.PushHandlerActivity\" android:permission=\"${applicationId}.permission.PushHandlerActivity\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<receiver android:name=\"com.adobe.phonegap.push.BackgroundActionButtonHandler\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<receiver android:name=\"com.adobe.phonegap.push.PushDismissedHandler\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<service android:name=\"com.adobe.phonegap.push.FCMService\"><intent-filter><action android:name=\"com.google.firebase.MESSAGING_EVENT\" /></intent-filter></service>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<service android:name=\"com.adobe.phonegap.push.PushInstanceIDListenerService\"><intent-filter><action android:name=\"com.google.firebase.INSTANCE_ID_EVENT\" /></intent-filter></service>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<meta-data android:name=\"com.google.android.gms.version\" android:value=\"@integer/google_play_services_version\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<service android:exported=\"true\" android:name=\"com.marianhello.bgloc.sync.SyncService\" android:process=\":sync\"><intent-filter><action android:name=\"android.content.SyncAdapter\" /></intent-filter><meta-data android:name=\"android.content.SyncAdapter\" android:resource=\"@xml/syncadapter\" /></service>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<service android:name=\"com.marianhello.bgloc.sync.AuthenticatorService\"><intent-filter><action android:name=\"android.accounts.AccountAuthenticator\" /></intent-filter><meta-data android:name=\"android.accounts.AccountAuthenticator\" android:resource=\"@xml/authenticator\" /></service>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<provider android:authorities=\"@string/mauron85_bgloc_content_authority\" android:exported=\"false\" android:name=\"com.marianhello.bgloc.data.provider.LocationContentProvider\" android:syncable=\"true\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<service android:enabled=\"true\" android:exported=\"false\" android:name=\"com.marianhello.bgloc.service.LocationServiceImpl\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<receiver android:enabled=\"true\" android:exported=\"true\" android:name=\"com.marianhello.bgloc.BootCompletedReceiver\"><intent-filter><action android:name=\"android.intent.action.BOOT_COMPLETED\" /></intent-filter></receiver>",
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"/manifest": [
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />",
|
|
||||||
"count": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.INTERNET\" />",
|
|
||||||
"count": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.WAKE_LOCK\" />",
|
|
||||||
"count": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.VIBRATE\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.AUTHENTICATE_ACCOUNTS\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.READ_SYNC_SETTINGS\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.WRITE_SYNC_SETTINGS\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"com.google.android.gms.permission.ACTIVITY_RECOGNITION\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.permission.ACCESS_LOCATION_EXTRA_COMMANDS\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<uses-permission android:name=\"android.hardware.location\" />",
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"config.xml": {
|
|
||||||
"parents": {
|
|
||||||
"/*": [
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"Keyboard\"><param name=\"android-package\" onload=\"true\" value=\"io.ionic.keyboard.IonicKeyboard\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<allow-navigation href=\"http://localhost:8080/*\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<preference name=\"webView\" value=\"com.ionicframework.cordova.webview.IonicWebViewEngine\" />",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"IonicWebView\"><param name=\"android-package\" value=\"com.ionicframework.cordova.webview.IonicWebView\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<feature name=\"RequestLocationAccuracy\"><param name=\"android-package\" value=\"cordova.plugin.RequestLocationAccuracy\" /></feature>",
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"res/values/strings.xml": {
|
|
||||||
"parents": {
|
|
||||||
"/resources": [
|
|
||||||
{
|
|
||||||
"xml": "<string name=\"mauron85_bgloc_account_name\">@string/app_name</string>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<string name=\"mauron85_bgloc_account_type\">com.sineedge.pdgenie.account</string>",
|
|
||||||
"count": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xml": "<string name=\"mauron85_bgloc_content_authority\">com.sineedge.pdgenie</string>",
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"res/xml/authenticator.xml": {
|
|
||||||
"parents": {
|
|
||||||
"/*": [
|
|
||||||
{
|
|
||||||
"xml": "<account-authenticator android:accountType=\"@string/mauron85_bgloc_account_type\" android:icon=\"@mipmap/icon\" android:label=\"@string/app_name\" android:smallIcon=\"@mipmap/icon\" xmlns:android=\"http://schemas.android.com/apk/res/android\" />",
|
|
||||||
"count": 1,
|
|
||||||
"mode": "overwrite",
|
|
||||||
"plugin": "cordova-plugin-mauron85-background-geolocation",
|
|
||||||
"oldAttrib": {
|
|
||||||
"android:accountType": "@string/mauron85_bgloc_account_type",
|
|
||||||
"android:icon": "@mipmap/icon",
|
|
||||||
"android:label": "@string/app_name",
|
|
||||||
"android:smallIcon": "@mipmap/icon",
|
|
||||||
"xmlns:android": "http://schemas.android.com/apk/res/android"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"res/xml/syncadapter.xml": {
|
|
||||||
"parents": {
|
|
||||||
"/*": [
|
|
||||||
{
|
|
||||||
"xml": "<sync-adapter android:accountType=\"@string/mauron85_bgloc_account_type\" android:allowParallelSyncs=\"false\" android:contentAuthority=\"@string/mauron85_bgloc_content_authority\" android:isAlwaysSyncable=\"true\" android:supportsUploading=\"true\" android:userVisible=\"false\" xmlns:android=\"http://schemas.android.com/apk/res/android\" />",
|
|
||||||
"count": 1,
|
|
||||||
"mode": "overwrite",
|
|
||||||
"plugin": "cordova-plugin-mauron85-background-geolocation",
|
|
||||||
"oldAttrib": {
|
|
||||||
"android:accountType": "@string/mauron85_bgloc_account_type",
|
|
||||||
"android:allowParallelSyncs": "false",
|
|
||||||
"android:contentAuthority": "@string/mauron85_bgloc_content_authority",
|
|
||||||
"android:isAlwaysSyncable": "true",
|
|
||||||
"android:supportsUploading": "true",
|
|
||||||
"android:userVisible": "false",
|
|
||||||
"xmlns:android": "http://schemas.android.com/apk/res/android"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"installed_plugins": {
|
|
||||||
"cordova-plugin-actionsheet": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-android-permissions": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-app-version": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-camera": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-datepicker": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-device": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-dialogs": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-fingerprint-aio": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-geolocation": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-ionic-keyboard": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-ionic-webview": {
|
|
||||||
"ANDROID_SUPPORT_ANNOTATIONS_VERSION": "27.+",
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-request-location-accuracy": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-splashscreen": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-statusbar": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-whitelist": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-sqlite-storage": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-support-google-services": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"phonegap-plugin-multidex": {
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"phonegap-plugin-push": {
|
|
||||||
"ANDROID_SUPPORT_V13_VERSION": "27.+",
|
|
||||||
"FCM_VERSION": "11.6.2",
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"uk.co.workingedge.phonegap.plugin.launchnavigator": {
|
|
||||||
"OKHTTP_VERSION": "3.+",
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
},
|
|
||||||
"cordova-plugin-mauron85-background-geolocation": {
|
|
||||||
"GOOGLE_PLAY_SERVICES_VERSION": "11+",
|
|
||||||
"ANDROID_SUPPORT_LIBRARY_VERSION": "26+",
|
|
||||||
"ICON": "@mipmap/icon",
|
|
||||||
"SMALL_ICON": "@mipmap/icon",
|
|
||||||
"ACCOUNT_NAME": "@string/app_name",
|
|
||||||
"ACCOUNT_LABEL": "@string/app_name",
|
|
||||||
"ACCOUNT_TYPE": "$PACKAGE_NAME.account",
|
|
||||||
"CONTENT_AUTHORITY": "$PACKAGE_NAME",
|
|
||||||
"PACKAGE_NAME": "com.sineedge.pdgenie"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependent_plugins": {},
|
|
||||||
"modules": [
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-actionsheet.ActionSheet",
|
|
||||||
"file": "plugins/cordova-plugin-actionsheet/www/ActionSheet.js",
|
|
||||||
"pluginId": "cordova-plugin-actionsheet",
|
|
||||||
"clobbers": [
|
|
||||||
"window.plugins.actionsheet"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-android-permissions.Permissions",
|
|
||||||
"file": "plugins/cordova-plugin-android-permissions/www/permissions.js",
|
|
||||||
"pluginId": "cordova-plugin-android-permissions",
|
|
||||||
"clobbers": [
|
|
||||||
"cordova.plugins.permissions"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-app-version.AppVersionPlugin",
|
|
||||||
"file": "plugins/cordova-plugin-app-version/www/AppVersionPlugin.js",
|
|
||||||
"pluginId": "cordova-plugin-app-version",
|
|
||||||
"clobbers": [
|
|
||||||
"cordova.getAppVersion"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-camera.Camera",
|
|
||||||
"file": "plugins/cordova-plugin-camera/www/CameraConstants.js",
|
|
||||||
"pluginId": "cordova-plugin-camera",
|
|
||||||
"clobbers": [
|
|
||||||
"Camera"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-camera.CameraPopoverOptions",
|
|
||||||
"file": "plugins/cordova-plugin-camera/www/CameraPopoverOptions.js",
|
|
||||||
"pluginId": "cordova-plugin-camera",
|
|
||||||
"clobbers": [
|
|
||||||
"CameraPopoverOptions"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-camera.camera",
|
|
||||||
"file": "plugins/cordova-plugin-camera/www/Camera.js",
|
|
||||||
"pluginId": "cordova-plugin-camera",
|
|
||||||
"clobbers": [
|
|
||||||
"navigator.camera"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-camera.CameraPopoverHandle",
|
|
||||||
"file": "plugins/cordova-plugin-camera/www/CameraPopoverHandle.js",
|
|
||||||
"pluginId": "cordova-plugin-camera",
|
|
||||||
"clobbers": [
|
|
||||||
"CameraPopoverHandle"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-datepicker.DatePicker",
|
|
||||||
"file": "plugins/cordova-plugin-datepicker/www/android/DatePicker.js",
|
|
||||||
"pluginId": "cordova-plugin-datepicker",
|
|
||||||
"clobbers": [
|
|
||||||
"datePicker"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-device.device",
|
|
||||||
"file": "plugins/cordova-plugin-device/www/device.js",
|
|
||||||
"pluginId": "cordova-plugin-device",
|
|
||||||
"clobbers": [
|
|
||||||
"device"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-dialogs.notification",
|
|
||||||
"file": "plugins/cordova-plugin-dialogs/www/notification.js",
|
|
||||||
"pluginId": "cordova-plugin-dialogs",
|
|
||||||
"merges": [
|
|
||||||
"navigator.notification"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-dialogs.notification_android",
|
|
||||||
"file": "plugins/cordova-plugin-dialogs/www/android/notification.js",
|
|
||||||
"pluginId": "cordova-plugin-dialogs",
|
|
||||||
"merges": [
|
|
||||||
"navigator.notification"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-fingerprint-aio.Fingerprint",
|
|
||||||
"file": "plugins/cordova-plugin-fingerprint-aio/www/Fingerprint.js",
|
|
||||||
"pluginId": "cordova-plugin-fingerprint-aio",
|
|
||||||
"clobbers": [
|
|
||||||
"Fingerprint"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-geolocation.geolocation",
|
|
||||||
"file": "plugins/cordova-plugin-geolocation/www/android/geolocation.js",
|
|
||||||
"pluginId": "cordova-plugin-geolocation",
|
|
||||||
"clobbers": [
|
|
||||||
"navigator.geolocation"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-geolocation.PositionError",
|
|
||||||
"file": "plugins/cordova-plugin-geolocation/www/PositionError.js",
|
|
||||||
"pluginId": "cordova-plugin-geolocation",
|
|
||||||
"runs": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-ionic-keyboard.keyboard",
|
|
||||||
"file": "plugins/cordova-plugin-ionic-keyboard/www/android/keyboard.js",
|
|
||||||
"pluginId": "cordova-plugin-ionic-keyboard",
|
|
||||||
"clobbers": [
|
|
||||||
"window.Keyboard"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-ionic-webview.IonicWebView",
|
|
||||||
"file": "plugins/cordova-plugin-ionic-webview/src/www/util.js",
|
|
||||||
"pluginId": "cordova-plugin-ionic-webview",
|
|
||||||
"clobbers": [
|
|
||||||
"Ionic.WebView"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-request-location-accuracy.RequestLocationAccuracy",
|
|
||||||
"file": "plugins/cordova-plugin-request-location-accuracy/www/android/RequestLocationAccuracy.js",
|
|
||||||
"pluginId": "cordova-plugin-request-location-accuracy",
|
|
||||||
"clobbers": [
|
|
||||||
"cordova.plugins.locationAccuracy"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-splashscreen.SplashScreen",
|
|
||||||
"file": "plugins/cordova-plugin-splashscreen/www/splashscreen.js",
|
|
||||||
"pluginId": "cordova-plugin-splashscreen",
|
|
||||||
"clobbers": [
|
|
||||||
"navigator.splashscreen"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-statusbar.statusbar",
|
|
||||||
"file": "plugins/cordova-plugin-statusbar/www/statusbar.js",
|
|
||||||
"pluginId": "cordova-plugin-statusbar",
|
|
||||||
"clobbers": [
|
|
||||||
"window.StatusBar"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-sqlite-storage.SQLitePlugin",
|
|
||||||
"file": "plugins/cordova-sqlite-storage/www/SQLitePlugin.js",
|
|
||||||
"pluginId": "cordova-sqlite-storage",
|
|
||||||
"clobbers": [
|
|
||||||
"SQLitePlugin"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "phonegap-plugin-push.PushNotification",
|
|
||||||
"file": "plugins/phonegap-plugin-push/www/push.js",
|
|
||||||
"pluginId": "phonegap-plugin-push",
|
|
||||||
"clobbers": [
|
|
||||||
"PushNotification"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "uk.co.workingedge.phonegap.plugin.launchnavigator.Common",
|
|
||||||
"file": "plugins/uk.co.workingedge.phonegap.plugin.launchnavigator/www/common.js",
|
|
||||||
"pluginId": "uk.co.workingedge.phonegap.plugin.launchnavigator",
|
|
||||||
"clobbers": [
|
|
||||||
"launchnavigator"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "uk.co.workingedge.phonegap.plugin.launchnavigator.LocalForage",
|
|
||||||
"file": "plugins/uk.co.workingedge.phonegap.plugin.launchnavigator/www/localforage.v1.5.0.min.js",
|
|
||||||
"pluginId": "uk.co.workingedge.phonegap.plugin.launchnavigator",
|
|
||||||
"clobbers": [
|
|
||||||
"localforage"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "uk.co.workingedge.phonegap.plugin.launchnavigator.LaunchNavigator",
|
|
||||||
"file": "plugins/uk.co.workingedge.phonegap.plugin.launchnavigator/www/android/launchnavigator.js",
|
|
||||||
"pluginId": "uk.co.workingedge.phonegap.plugin.launchnavigator",
|
|
||||||
"merges": [
|
|
||||||
"launchnavigator"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-mauron85-background-geolocation.BackgroundGeolocation",
|
|
||||||
"file": "plugins/cordova-plugin-mauron85-background-geolocation/www/BackgroundGeolocation.js",
|
|
||||||
"pluginId": "cordova-plugin-mauron85-background-geolocation",
|
|
||||||
"clobbers": [
|
|
||||||
"BackgroundGeolocation"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "cordova-plugin-mauron85-background-geolocation.radio",
|
|
||||||
"file": "plugins/cordova-plugin-mauron85-background-geolocation/www/radio.js",
|
|
||||||
"pluginId": "cordova-plugin-mauron85-background-geolocation"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"plugin_metadata": {
|
|
||||||
"cordova-plugin-actionsheet": "2.3.3",
|
|
||||||
"cordova-plugin-android-permissions": "1.0.0",
|
|
||||||
"cordova-plugin-app-version": "0.1.9",
|
|
||||||
"cordova-plugin-camera": "4.0.3",
|
|
||||||
"cordova-plugin-datepicker": "0.9.3",
|
|
||||||
"cordova-plugin-device": "2.0.2",
|
|
||||||
"cordova-plugin-dialogs": "2.0.1",
|
|
||||||
"cordova-plugin-fingerprint-aio": "1.4.1",
|
|
||||||
"cordova-plugin-geolocation": "2.4.3",
|
|
||||||
"cordova-plugin-ionic-keyboard": "2.1.3",
|
|
||||||
"cordova-plugin-ionic-webview": "2.2.0",
|
|
||||||
"cordova-plugin-request-location-accuracy": "2.2.3",
|
|
||||||
"cordova-plugin-splashscreen": "5.0.2",
|
|
||||||
"cordova-plugin-statusbar": "2.4.2",
|
|
||||||
"cordova-plugin-whitelist": "1.3.3",
|
|
||||||
"cordova-sqlite-storage": "3.2.1",
|
|
||||||
"cordova-support-google-services": "1.1.0",
|
|
||||||
"phonegap-plugin-multidex": "1.0.0",
|
|
||||||
"phonegap-plugin-push": "2.2.3",
|
|
||||||
"uk.co.workingedge.phonegap.plugin.launchnavigator": "4.2.2",
|
|
||||||
"cordova-plugin-mauron85-background-geolocation": "3.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,342 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
google()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:3.3.0'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow plugins to declare Maven dependencies via build-extras.gradle.
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task wrapper(type: Wrapper) {
|
|
||||||
gradleVersion = '4.10.3'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.
|
|
||||||
// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html
|
|
||||||
ext {
|
|
||||||
apply from: '../CordovaLib/cordova.gradle'
|
|
||||||
|
|
||||||
// The value for android.compileSdkVersion.
|
|
||||||
if (!project.hasProperty('cdvCompileSdkVersion')) {
|
|
||||||
cdvCompileSdkVersion = null;
|
|
||||||
}
|
|
||||||
// The value for android.buildToolsVersion.
|
|
||||||
if (!project.hasProperty('cdvBuildToolsVersion')) {
|
|
||||||
cdvBuildToolsVersion = null;
|
|
||||||
}
|
|
||||||
// Sets the versionCode to the given value.
|
|
||||||
if (!project.hasProperty('cdvVersionCode')) {
|
|
||||||
cdvVersionCode = null
|
|
||||||
}
|
|
||||||
// Sets the minSdkVersion to the given value.
|
|
||||||
if (!project.hasProperty('cdvMinSdkVersion')) {
|
|
||||||
cdvMinSdkVersion = null
|
|
||||||
}
|
|
||||||
// Whether to build architecture-specific APKs.
|
|
||||||
if (!project.hasProperty('cdvBuildMultipleApks')) {
|
|
||||||
cdvBuildMultipleApks = null
|
|
||||||
}
|
|
||||||
// Whether to append a 0 "abi digit" to versionCode when only a single APK is build
|
|
||||||
if (!project.hasProperty('cdvVersionCodeForceAbiDigit')) {
|
|
||||||
cdvVersionCodeForceAbiDigit = null
|
|
||||||
}
|
|
||||||
// .properties files to use for release signing.
|
|
||||||
if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {
|
|
||||||
cdvReleaseSigningPropertiesFile = null
|
|
||||||
}
|
|
||||||
// .properties files to use for debug signing.
|
|
||||||
if (!project.hasProperty('cdvDebugSigningPropertiesFile')) {
|
|
||||||
cdvDebugSigningPropertiesFile = null
|
|
||||||
}
|
|
||||||
// Set by build.js script.
|
|
||||||
if (!project.hasProperty('cdvBuildArch')) {
|
|
||||||
cdvBuildArch = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plugin gradle extensions can append to this to have code run at the end.
|
|
||||||
cdvPluginPostBuildExtras = []
|
|
||||||
}
|
|
||||||
|
|
||||||
// PLUGIN GRADLE EXTENSIONS START
|
|
||||||
apply from: "../cordova-support-google-services/pdgenie-build.gradle"
|
|
||||||
apply from: "../phonegap-plugin-multidex/pdgenie-multidex.gradle"
|
|
||||||
apply from: "../cordova-plugin-mauron85-background-geolocation/pdgenie-dependencies.gradle"
|
|
||||||
// PLUGIN GRADLE EXTENSIONS END
|
|
||||||
|
|
||||||
def hasBuildExtras1 = file('build-extras.gradle').exists()
|
|
||||||
if (hasBuildExtras1) {
|
|
||||||
apply from: 'build-extras.gradle'
|
|
||||||
}
|
|
||||||
|
|
||||||
def hasBuildExtras2 = file('../build-extras.gradle').exists()
|
|
||||||
if (hasBuildExtras2) {
|
|
||||||
apply from: '../build-extras.gradle'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set property defaults after extension .gradle files.
|
|
||||||
if (ext.cdvCompileSdkVersion == null) {
|
|
||||||
ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget()
|
|
||||||
//ext.cdvCompileSdkVersion = project.ext.defaultCompileSdkVersion
|
|
||||||
}
|
|
||||||
if (ext.cdvBuildToolsVersion == null) {
|
|
||||||
ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
|
|
||||||
//ext.cdvBuildToolsVersion = project.ext.defaultBuildToolsVersion
|
|
||||||
}
|
|
||||||
if (ext.cdvDebugSigningPropertiesFile == null && file('../debug-signing.properties').exists()) {
|
|
||||||
ext.cdvDebugSigningPropertiesFile = '../debug-signing.properties'
|
|
||||||
}
|
|
||||||
if (ext.cdvReleaseSigningPropertiesFile == null && file('../release-signing.properties').exists()) {
|
|
||||||
ext.cdvReleaseSigningPropertiesFile = '../release-signing.properties'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cast to appropriate types.
|
|
||||||
ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();
|
|
||||||
ext.cdvVersionCodeForceAbiDigit = cdvVersionCodeForceAbiDigit == null ? false : cdvVersionCodeForceAbiDigit.toBoolean();
|
|
||||||
ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? defaultMinSdkVersion : Integer.parseInt('' + cdvMinSdkVersion)
|
|
||||||
ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)
|
|
||||||
|
|
||||||
def computeBuildTargetName(debugBuild) {
|
|
||||||
def ret = 'assemble'
|
|
||||||
if (cdvBuildMultipleApks && cdvBuildArch) {
|
|
||||||
def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch
|
|
||||||
ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1);
|
|
||||||
}
|
|
||||||
return ret + (debugBuild ? 'Debug' : 'Release')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make cdvBuild a task that depends on the debug/arch-sepecific task.
|
|
||||||
task cdvBuildDebug
|
|
||||||
cdvBuildDebug.dependsOn {
|
|
||||||
return computeBuildTargetName(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
task cdvBuildRelease
|
|
||||||
cdvBuildRelease.dependsOn {
|
|
||||||
return computeBuildTargetName(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
task cdvPrintProps {
|
|
||||||
doLast {
|
|
||||||
println('cdvCompileSdkVersion=' + cdvCompileSdkVersion)
|
|
||||||
println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)
|
|
||||||
println('cdvVersionCode=' + cdvVersionCode)
|
|
||||||
println('cdvVersionCodeForceAbiDigit=' + cdvVersionCodeForceAbiDigit)
|
|
||||||
println('cdvMinSdkVersion=' + cdvMinSdkVersion)
|
|
||||||
println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
|
|
||||||
println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
|
|
||||||
println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)
|
|
||||||
println('cdvBuildArch=' + cdvBuildArch)
|
|
||||||
println('computedVersionCode=' + android.defaultConfig.versionCode)
|
|
||||||
android.productFlavors.each { flavor ->
|
|
||||||
println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
defaultConfig {
|
|
||||||
versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode"))
|
|
||||||
applicationId privateHelpers.extractStringFromManifest("package")
|
|
||||||
|
|
||||||
if (cdvMinSdkVersion != null) {
|
|
||||||
minSdkVersion cdvMinSdkVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lintOptions {
|
|
||||||
abortOnError false;
|
|
||||||
}
|
|
||||||
|
|
||||||
compileSdkVersion cdvCompileSdkVersion
|
|
||||||
buildToolsVersion cdvBuildToolsVersion
|
|
||||||
|
|
||||||
// This code exists for Crosswalk and other Native APIs.
|
|
||||||
// By default, we multiply the existing version code in the
|
|
||||||
// Android Manifest by 10 and add a number for each architecture.
|
|
||||||
// If you are not using Crosswalk or SQLite, you can
|
|
||||||
// ignore this chunk of code, and your version codes will be respected.
|
|
||||||
|
|
||||||
if (Boolean.valueOf(cdvBuildMultipleApks)) {
|
|
||||||
flavorDimensions "default"
|
|
||||||
|
|
||||||
productFlavors {
|
|
||||||
armeabi {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 1
|
|
||||||
ndk {
|
|
||||||
abiFilters = ["armeabi"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
armv7 {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 2
|
|
||||||
ndk {
|
|
||||||
abiFilters = ["armeabi-v7a"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arm64 {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 3
|
|
||||||
ndk {
|
|
||||||
abiFilters = ["arm64-v8a"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x86 {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 4
|
|
||||||
ndk {
|
|
||||||
abiFilters = ["x86"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x86_64 {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 5
|
|
||||||
ndk {
|
|
||||||
abiFilters = ["x86_64"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (Boolean.valueOf(cdvVersionCodeForceAbiDigit)) {
|
|
||||||
// This provides compatibility to the default logic for versionCode before cordova-android 5.2.0
|
|
||||||
defaultConfig {
|
|
||||||
versionCode defaultConfig.versionCode*10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cdvReleaseSigningPropertiesFile) {
|
|
||||||
signingConfigs {
|
|
||||||
release {
|
|
||||||
// These must be set or Gradle will complain (even if they are overridden).
|
|
||||||
keyAlias = ""
|
|
||||||
keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph.
|
|
||||||
storeFile = null
|
|
||||||
storePassword = "__unset"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
signingConfig signingConfigs.release
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cdvDebugSigningPropertiesFile) {
|
|
||||||
addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* WARNING: Cordova Lib and platform scripts do management inside of this code here,
|
|
||||||
* if you are adding the dependencies manually, do so outside the comments, otherwise
|
|
||||||
* the Cordova tools will overwrite them
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation fileTree(dir: 'libs', include: '*.jar')
|
|
||||||
// SUB-PROJECT DEPENDENCIES START
|
|
||||||
implementation(project(path: ":CordovaLib"))
|
|
||||||
implementation "com.android.support:support-v4:24.1.1+"
|
|
||||||
implementation "com.android.support:support-annotations:27.+"
|
|
||||||
implementation "com.google.android.gms:play-services-location:9.8.0"
|
|
||||||
implementation "com.android.support:support-v13:27.+"
|
|
||||||
implementation "me.leolin:ShortcutBadger:1.1.17@aar"
|
|
||||||
implementation "com.google.firebase:firebase-messaging:9.8.0"
|
|
||||||
implementation "com.squareup.okhttp3:okhttp:3.+"
|
|
||||||
implementation "com.android.support:support-v4:26+"
|
|
||||||
implementation "com.android.support:appcompat-v7:26+"
|
|
||||||
// SUB-PROJECT DEPENDENCIES END
|
|
||||||
}
|
|
||||||
|
|
||||||
def promptForReleaseKeyPassword() {
|
|
||||||
if (!cdvReleaseSigningPropertiesFile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ('__unset'.equals(android.signingConfigs.release.storePassword)) {
|
|
||||||
android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ')
|
|
||||||
}
|
|
||||||
if ('__unset'.equals(android.signingConfigs.release.keyPassword)) {
|
|
||||||
android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gradle.taskGraph.whenReady { taskGraph ->
|
|
||||||
taskGraph.getAllTasks().each() { task ->
|
|
||||||
if(['validateReleaseSigning', 'validateSigningRelease', 'validateSigningArmv7Release', 'validateSigningX76Release'].contains(task.name)) {
|
|
||||||
promptForReleaseKeyPassword()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def addSigningProps(propsFilePath, signingConfig) {
|
|
||||||
def propsFile = file(propsFilePath)
|
|
||||||
def props = new Properties()
|
|
||||||
propsFile.withReader { reader ->
|
|
||||||
props.load(reader)
|
|
||||||
}
|
|
||||||
|
|
||||||
def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))
|
|
||||||
if (!storeFile.isAbsolute()) {
|
|
||||||
storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile())
|
|
||||||
}
|
|
||||||
if (!storeFile.exists()) {
|
|
||||||
throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath())
|
|
||||||
}
|
|
||||||
signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')
|
|
||||||
signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword))
|
|
||||||
signingConfig.storeFile = storeFile
|
|
||||||
signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword))
|
|
||||||
def storeType = props.get('storeType', props.get('key.store.type', ''))
|
|
||||||
if (!storeType) {
|
|
||||||
def filename = storeFile.getName().toLowerCase();
|
|
||||||
if (filename.endsWith('.p12') || filename.endsWith('.pfx')) {
|
|
||||||
storeType = 'pkcs12'
|
|
||||||
} else {
|
|
||||||
storeType = signingConfig.storeType // "jks"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
signingConfig.storeType = storeType
|
|
||||||
}
|
|
||||||
|
|
||||||
for (def func : cdvPluginPostBuildExtras) {
|
|
||||||
func()
|
|
||||||
}
|
|
||||||
|
|
||||||
// This can be defined within build-extras.gradle as:
|
|
||||||
// ext.postBuildExtras = { ... code here ... }
|
|
||||||
if (hasProperty('postBuildExtras')) {
|
|
||||||
postBuildExtras()
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2015 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="40.0dp"
|
|
||||||
android:height="40.0dp"
|
|
||||||
android:viewportWidth="40.0"
|
|
||||||
android:viewportHeight="40.0">
|
|
||||||
<path
|
|
||||||
android:pathData="M20.0,0.0C8.96,0.0 0.0,8.95 0.0,20.0s8.96,20.0 20.0,20.0c11.04,0.0 20.0,-8.95 20.0,-20.0S31.04,0.0 20.0,0.0z"
|
|
||||||
android:fillColor="#F4511E"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M21.33,29.33l-2.67,0.0l0.0,-2.67l2.67,0.0L21.33,29.33zM21.33,22.67l-2.67,0.0l0.0,-12.0l2.67,0.0L21.33,22.67z"
|
|
||||||
android:fillColor="#FFFFFF"/>
|
|
||||||
</vector>
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
~ Copyright (C) 2015 The Android Open Source Project
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License
|
|
||||||
-->
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="40.0dp"
|
|
||||||
android:height="40.0dp"
|
|
||||||
android:viewportWidth="40.0"
|
|
||||||
android:viewportHeight="40.0">
|
|
||||||
<path
|
|
||||||
android:pathData="M20.0,20.0m-20.0,0.0a20.0,20.0 0.0,1.0 1.0,40.0 0.0a20.0,20.0 0.0,1.0 1.0,-40.0 0.0"
|
|
||||||
android:fillColor="#009688"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M11.2,21.41l1.63,-1.619999 4.17,4.169998 10.59,-10.589999 1.619999,1.63 -12.209999,12.209999z"
|
|
||||||
android:fillColor="#FFFFFF"/>
|
|
||||||
</vector>
|
|
||||||
|
Before Width: | Height: | Size: 771 B |
|
Before Width: | Height: | Size: 881 B |
|
Before Width: | Height: | Size: 383 B |
|
Before Width: | Height: | Size: 461 B |
|
Before Width: | Height: | Size: 490 B |
|
Before Width: | Height: | Size: 587 B |
|
Before Width: | Height: | Size: 952 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-af\\values-af.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-af\\values-af.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,159,267,390,490,596,681,784,902,978,1055,1136,1243,1346,1443,1551,1653,1755,1872,1970,2050",
|
|
||||||
"endColumns": "103,107,122,99,105,84,102,117,75,76,80,106,102,96,107,101,101,116,97,79,100",
|
|
||||||
"endOffsets": "154,262,385,485,591,676,779,897,973,1050,1131,1238,1341,1438,1546,1648,1750,1867,1965,2045,2146"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,38,39",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,209,317,440,540,646,731,834,952,1028,1105,1186,1293,1396,1493,1601,1703,1805,1922,4554,4634",
|
|
||||||
"endColumns": "103,107,122,99,105,84,102,117,75,76,80,106,102,96,107,101,101,116,97,79,100",
|
|
||||||
"endOffsets": "204,312,435,535,641,726,829,947,1023,1100,1181,1288,1391,1488,1596,1698,1800,1917,2015,4629,4730"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-af\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,388,576,700,808,1017,1137,1264,1489,1595,1783,1908,2106,2286,2378,2467",
|
|
||||||
"endColumns": "104,187,123,107,208,119,126,224,105,187,124,197,179,91,88,103",
|
|
||||||
"endOffsets": "387,575,699,807,1016,1136,1263,1488,1594,1782,1907,2105,2285,2377,2466,2570"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "2020,2129,2317,2445,2557,2766,2890,3223,3448,3558,3746,3875,4073,4257,4353,4446",
|
|
||||||
"endColumns": "108,187,127,111,208,123,130,224,109,187,128,197,183,95,92,107",
|
|
||||||
"endOffsets": "2124,2312,2440,2552,2761,2885,3016,3443,3553,3741,3870,4068,4252,4348,4441,4549"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-af\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "201",
|
|
||||||
"endOffsets": "486"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "3021",
|
|
||||||
"endColumns": "201",
|
|
||||||
"endOffsets": "3218"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-am\\values-am.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-am\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,383,554,674,774,960,1081,1208,1395,1496,1672,1793,1987,2140,2226,2309",
|
|
||||||
"endColumns": "99,170,119,99,185,120,126,186,100,175,120,193,152,85,82,95",
|
|
||||||
"endOffsets": "382,553,673,773,959,1080,1207,1394,1495,1671,1792,1986,2139,2225,2308,2404"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "1997,2101,2272,2396,2500,2686,2811,3133,3320,3425,3601,3726,3920,4077,4167,4254",
|
|
||||||
"endColumns": "103,170,123,103,185,124,130,186,104,175,124,193,156,89,86,99",
|
|
||||||
"endOffsets": "2096,2267,2391,2495,2681,2806,2937,3315,3420,3596,3721,3915,4072,4162,4249,4349"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-am\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "190",
|
|
||||||
"endOffsets": "475"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "2942",
|
|
||||||
"endColumns": "190",
|
|
||||||
"endOffsets": "3128"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-am\\values-am.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,157,265,388,487,593,679,782,895,973,1051,1130,1230,1330,1426,1529,1628,1735,1851,1947,2026",
|
|
||||||
"endColumns": "101,107,122,98,105,85,102,112,77,77,78,99,99,95,102,98,106,115,95,78,100",
|
|
||||||
"endOffsets": "152,260,383,482,588,674,777,890,968,1046,1125,1225,1325,1421,1524,1623,1730,1846,1942,2021,2122"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,38,39",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,207,315,438,537,643,729,832,945,1023,1101,1180,1280,1380,1476,1579,1678,1785,1901,4354,4433",
|
|
||||||
"endColumns": "101,107,122,98,105,85,102,112,77,77,78,99,99,95,102,98,106,115,95,78,100",
|
|
||||||
"endOffsets": "202,310,433,532,638,724,827,940,1018,1096,1175,1275,1375,1471,1574,1673,1780,1896,1992,4428,4529"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-ar\\values-ar.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-ar\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,385,561,681,784,981,1107,1234,1430,1532,1713,1833,2031,2203,2293,2385",
|
|
||||||
"endColumns": "101,175,119,102,196,125,126,195,101,180,119,197,171,89,91,108",
|
|
||||||
"endOffsets": "384,560,680,783,980,1106,1233,1429,1531,1712,1832,2030,2202,2292,2384,2493"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "2032,2138,2314,2438,2545,2742,2872,3193,3389,3495,3676,3800,3998,4174,4268,4364",
|
|
||||||
"endColumns": "105,175,123,106,196,129,130,195,105,180,123,197,175,93,95,112",
|
|
||||||
"endOffsets": "2133,2309,2433,2540,2737,2867,2998,3384,3490,3671,3795,3993,4169,4263,4359,4472"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-ar\\values-ar.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,172,280,403,507,616,698,799,913,992,1071,1150,1255,1356,1452,1560,1663,1766,1885,1982,2063",
|
|
||||||
"endColumns": "116,107,122,103,108,81,100,113,78,78,78,104,100,95,107,102,102,118,96,80,100",
|
|
||||||
"endOffsets": "167,275,398,502,611,693,794,908,987,1066,1145,1250,1351,1447,1555,1658,1761,1880,1977,2058,2159"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,38,39",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,222,330,453,557,666,748,849,963,1042,1121,1200,1305,1406,1502,1610,1713,1816,1935,4477,4558",
|
|
||||||
"endColumns": "116,107,122,103,108,81,100,113,78,78,78,104,100,95,107,102,102,118,96,80,100",
|
|
||||||
"endOffsets": "217,325,448,552,661,743,844,958,1037,1116,1195,1300,1401,1497,1605,1708,1811,1930,2027,4553,4654"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-ar\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "189",
|
|
||||||
"endOffsets": "474"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "3003",
|
|
||||||
"endColumns": "189",
|
|
||||||
"endOffsets": "3188"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-az\\values-az.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-az\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,390,577,708,816,1021,1152,1283,1508,1616,1796,1931,2134,2316,2406,2497",
|
|
||||||
"endColumns": "106,186,130,107,204,130,130,224,107,179,134,202,181,89,90,105",
|
|
||||||
"endOffsets": "389,576,707,815,1020,1151,1282,1507,1615,1795,1930,2133,2315,2405,2496,2602"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "20,21,22,23,24,25,26,28,29,30,31,32,33,34,35,36",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "1943,2054,2241,2376,2488,2693,2828,3184,3409,3521,3701,3840,4043,4229,4323,4418",
|
|
||||||
"endColumns": "110,186,134,111,204,134,134,224,111,179,138,202,185,93,94,109",
|
|
||||||
"endOffsets": "2049,2236,2371,2483,2688,2823,2958,3404,3516,3696,3835,4038,4224,4318,4413,4523"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-az\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "220",
|
|
||||||
"endOffsets": "505"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "27",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "2963",
|
|
||||||
"endColumns": "220",
|
|
||||||
"endOffsets": "3179"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-az\\values-az.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,163,271,394,493,605,693,800,914,995,1074,1159,1266,1373,1473,1582,1686,1796,1893,1976",
|
|
||||||
"endColumns": "107,107,122,98,111,87,106,113,80,78,84,106,106,99,108,103,109,96,82,100",
|
|
||||||
"endOffsets": "158,266,389,488,600,688,795,909,990,1069,1154,1261,1368,1468,1577,1681,1791,1888,1971,2072"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,37,38",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,213,321,444,543,655,743,850,964,1045,1124,1209,1316,1423,1523,1632,1736,1846,4528,4611",
|
|
||||||
"endColumns": "107,107,122,98,111,87,106,113,80,78,84,106,106,99,108,103,109,96,82,100",
|
|
||||||
"endOffsets": "208,316,439,538,650,738,845,959,1040,1119,1204,1311,1418,1518,1627,1731,1841,1938,4606,4707"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-b+sr+Latn\\values-b+sr+Latn.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-b+sr+Latn\\values-b+sr+Latn.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,164,272,395,499,605,691,795,913,995,1076,1164,1270,1378,1479,1584,1692,1793,1921,2018,2102",
|
|
||||||
"endColumns": "108,107,122,103,105,85,103,117,81,80,87,105,107,100,104,107,100,127,96,83,100",
|
|
||||||
"endOffsets": "159,267,390,494,600,686,790,908,990,1071,1159,1265,1373,1474,1579,1687,1788,1916,2013,2097,2198"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-be\\values-be.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-be\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,388,582,705,813,1027,1151,1280,1501,1606,1800,1926,2138,2323,2418,2506",
|
|
||||||
"endColumns": "104,193,122,107,213,123,128,220,104,193,125,211,184,94,87,103",
|
|
||||||
"endOffsets": "387,581,704,812,1026,1150,1279,1500,1605,1799,1925,2137,2322,2417,2505,2609"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "2075,2184,2378,2505,2617,2831,2959,3297,3518,3627,3821,3951,4163,4352,4451,4543",
|
|
||||||
"endColumns": "108,193,126,111,213,127,132,220,108,193,129,211,188,98,91,107",
|
|
||||||
"endOffsets": "2179,2373,2500,2612,2826,2954,3087,3513,3622,3816,3946,4158,4347,4446,4538,4646"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-be\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "204",
|
|
||||||
"endOffsets": "489"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "3092",
|
|
||||||
"endColumns": "204",
|
|
||||||
"endOffsets": "3292"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-be\\values-be.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,175,283,406,509,625,711,819,937,1016,1094,1177,1283,1389,1487,1595,1700,1805,1925,2025,2106",
|
|
||||||
"endColumns": "119,107,122,102,115,85,107,117,78,77,82,105,105,97,107,104,104,119,99,80,108",
|
|
||||||
"endOffsets": "170,278,401,504,620,706,814,932,1011,1089,1172,1278,1384,1482,1590,1695,1800,1920,2020,2101,2210"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,38,39",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,225,333,456,559,675,761,869,987,1066,1144,1227,1333,1439,1537,1645,1750,1855,1975,4651,4732",
|
|
||||||
"endColumns": "119,107,122,102,115,85,107,117,78,77,82,105,105,97,107,104,104,119,99,80,108",
|
|
||||||
"endOffsets": "220,328,451,554,670,756,864,982,1061,1139,1222,1328,1434,1532,1640,1745,1850,1970,2070,4727,4836"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-bg\\values-bg.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-bg\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,390,587,720,829,1055,1188,1322,1550,1660,1866,2002,2218,2410,2506,2591",
|
|
||||||
"endColumns": "106,196,132,108,225,132,133,227,109,205,135,215,191,95,84,97",
|
|
||||||
"endOffsets": "389,586,719,828,1054,1187,1321,1549,1659,1865,2001,2217,2409,2505,2590,2688"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "2096,2207,2404,2541,2654,2880,3017,3352,3580,3694,3900,4040,4256,4452,4552,4641",
|
|
||||||
"endColumns": "110,196,136,112,225,136,137,227,113,205,139,215,195,99,88,101",
|
|
||||||
"endOffsets": "2202,2399,2536,2649,2875,3012,3150,3575,3689,3895,4035,4251,4447,4547,4636,4738"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-bg\\values-bg.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,170,281,409,516,621,707,812,933,1012,1090,1173,1287,1396,1496,1610,1716,1824,1947,2046,2129",
|
|
||||||
"endColumns": "114,110,127,106,104,85,104,120,78,77,82,113,108,99,113,105,107,122,98,82,100",
|
|
||||||
"endOffsets": "165,276,404,511,616,702,807,928,1007,1085,1168,1282,1391,1491,1605,1711,1819,1942,2041,2124,2225"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,38,39",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,220,331,459,566,671,757,862,983,1062,1140,1223,1337,1446,1546,1660,1766,1874,1997,4743,4826",
|
|
||||||
"endColumns": "114,110,127,106,104,85,104,120,78,77,82,113,108,99,113,105,107,122,98,82,100",
|
|
||||||
"endOffsets": "215,326,454,561,666,752,857,978,1057,1135,1218,1332,1441,1541,1655,1761,1869,1992,2091,4821,4922"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-bg\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "196",
|
|
||||||
"endOffsets": "481"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "3155",
|
|
||||||
"endColumns": "196",
|
|
||||||
"endOffsets": "3347"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-bn\\values-bn.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-bn\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,390,581,707,816,1012,1132,1261,1465,1572,1759,1885,2078,2253,2339,2431",
|
|
||||||
"endColumns": "106,190,125,108,195,119,128,203,106,186,125,192,174,85,91,113",
|
|
||||||
"endOffsets": "389,580,706,815,1011,1131,1260,1464,1571,1758,1884,2077,2252,2338,2430,2544"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "2129,2240,2431,2561,2674,2870,2994,3338,3542,3653,3840,3970,4163,4342,4432,4528",
|
|
||||||
"endColumns": "110,190,129,112,195,123,132,203,110,186,129,192,178,89,95,117",
|
|
||||||
"endOffsets": "2235,2426,2556,2669,2865,2989,3122,3537,3648,3835,3965,4158,4337,4427,4523,4641"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-bn\\values-bn.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,164,272,395,507,613,707,812,941,1019,1097,1184,1294,1410,1517,1627,1733,1846,1974,2079,2169",
|
|
||||||
"endColumns": "108,107,122,111,105,93,104,128,77,77,86,109,115,106,109,105,112,127,104,89,100",
|
|
||||||
"endOffsets": "159,267,390,502,608,702,807,936,1014,1092,1179,1289,1405,1512,1622,1728,1841,1969,2074,2164,2265"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,38,39",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,214,322,445,557,663,757,862,991,1069,1147,1234,1344,1460,1567,1677,1783,1896,2024,4646,4736",
|
|
||||||
"endColumns": "108,107,122,111,105,93,104,128,77,77,86,109,115,106,109,105,112,127,104,89,100",
|
|
||||||
"endOffsets": "209,317,440,552,658,752,857,986,1064,1142,1229,1339,1455,1562,1672,1778,1891,2019,2124,4731,4832"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-bn\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "210",
|
|
||||||
"endOffsets": "495"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "3127",
|
|
||||||
"endColumns": "210",
|
|
||||||
"endOffsets": "3333"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-bs\\values-bs.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-bs\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,387,579,703,811,1020,1144,1271,1484,1589,1781,1906,2115,2287,2381,2472",
|
|
||||||
"endColumns": "103,191,123,107,208,123,126,212,104,191,124,208,171,93,90,109",
|
|
||||||
"endOffsets": "386,578,702,810,1019,1143,1270,1483,1588,1780,1905,2114,2286,2380,2471,2581"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "2073,2181,2373,2501,2613,2822,2950,3281,3494,3603,3795,3924,4133,4309,4407,4502",
|
|
||||||
"endColumns": "107,191,127,111,208,127,130,212,108,191,128,208,175,97,94,113",
|
|
||||||
"endOffsets": "2176,2368,2496,2608,2817,2945,3076,3489,3598,3790,3919,4128,4304,4402,4497,4611"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-bs\\values-bs.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,174,282,405,514,621,707,808,930,1012,1093,1179,1282,1387,1485,1590,1701,1806,1926,2023,2107",
|
|
||||||
"endColumns": "118,107,122,108,106,85,100,121,81,80,85,102,104,97,104,110,104,119,96,83,100",
|
|
||||||
"endOffsets": "169,277,400,509,616,702,803,925,1007,1088,1174,1277,1382,1480,1585,1696,1801,1921,2018,2102,2203"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,38,39",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,224,332,455,564,671,757,858,980,1062,1143,1229,1332,1437,1535,1640,1751,1856,1976,4616,4700",
|
|
||||||
"endColumns": "118,107,122,108,106,85,100,121,81,80,85,102,104,97,104,110,104,119,96,83,100",
|
|
||||||
"endOffsets": "219,327,450,559,666,752,853,975,1057,1138,1224,1327,1432,1530,1635,1746,1851,1971,2068,4695,4796"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-bs\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "199",
|
|
||||||
"endOffsets": "484"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "3081",
|
|
||||||
"endColumns": "199",
|
|
||||||
"endOffsets": "3276"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-ca\\values-ca.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-ca\\values-ca.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,173,281,404,510,617,700,808,934,1018,1099,1182,1293,1402,1500,1610,1714,1822,1945,2044,2125",
|
|
||||||
"endColumns": "117,107,122,105,106,82,107,125,83,80,82,110,108,97,109,103,107,122,98,80,100",
|
|
||||||
"endOffsets": "168,276,399,505,612,695,803,929,1013,1094,1177,1288,1397,1495,1605,1709,1817,1940,2039,2120,2221"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,38,39",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,223,331,454,560,667,750,858,984,1068,1149,1232,1343,1452,1550,1660,1764,1872,1995,4722,4803",
|
|
||||||
"endColumns": "117,107,122,105,106,82,107,125,83,80,82,110,108,97,109,103,107,122,98,80,100",
|
|
||||||
"endOffsets": "218,326,449,555,662,745,853,979,1063,1144,1227,1338,1447,1545,1655,1759,1867,1990,2089,4798,4899"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-ca\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "197",
|
|
||||||
"endOffsets": "482"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "3117",
|
|
||||||
"endColumns": "197",
|
|
||||||
"endOffsets": "3310"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-ca\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,386,574,703,810,1022,1151,1286,1523,1630,1824,1957,2185,2372,2463,2557",
|
|
||||||
"endColumns": "102,187,128,106,211,128,134,236,106,193,132,227,186,90,93,111",
|
|
||||||
"endOffsets": "385,573,702,809,1021,1150,1285,1522,1629,1823,1956,2184,2371,2462,2556,2668"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "2094,2201,2389,2522,2633,2845,2978,3315,3552,3663,3857,3994,4222,4413,4508,4606",
|
|
||||||
"endColumns": "106,187,132,110,211,132,138,236,110,193,136,227,190,94,97,115",
|
|
||||||
"endOffsets": "2196,2384,2517,2628,2840,2973,3112,3547,3658,3852,3989,4217,4408,4503,4601,4717"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-cs\\values-cs.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-cs\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "201",
|
|
||||||
"endOffsets": "486"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "3075",
|
|
||||||
"endColumns": "201",
|
|
||||||
"endOffsets": "3272"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-cs\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,387,579,702,810,1022,1147,1273,1507,1616,1811,1937,2157,2338,2432,2525",
|
|
||||||
"endColumns": "103,191,122,107,211,124,125,233,108,194,125,219,180,93,92,110",
|
|
||||||
"endOffsets": "386,578,701,809,1021,1146,1272,1506,1615,1810,1936,2156,2337,2431,2524,2635"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "2065,2173,2365,2492,2604,2816,2945,3277,3511,3624,3819,3949,4169,4354,4452,4549",
|
|
||||||
"endColumns": "107,191,126,111,211,128,129,233,112,194,129,219,184,97,96,114",
|
|
||||||
"endOffsets": "2168,2360,2487,2599,2811,2940,3070,3506,3619,3814,3944,4164,4349,4447,4544,4659"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-cs\\values-cs.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,162,271,395,497,606,692,797,914,995,1076,1160,1264,1373,1472,1578,1688,1795,1917,2015,2097",
|
|
||||||
"endColumns": "106,108,123,101,108,85,104,116,80,80,83,103,108,98,105,109,106,121,97,81,100",
|
|
||||||
"endOffsets": "157,266,390,492,601,687,792,909,990,1071,1155,1259,1368,1467,1573,1683,1790,1912,2010,2092,2193"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,38,39",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,212,321,445,547,656,742,847,964,1045,1126,1210,1314,1423,1522,1628,1738,1845,1967,4664,4746",
|
|
||||||
"endColumns": "106,108,123,101,108,85,104,116,80,80,83,103,108,98,105,109,106,121,97,81,100",
|
|
||||||
"endOffsets": "207,316,440,542,651,737,842,959,1040,1121,1205,1309,1418,1517,1623,1733,1840,1962,2060,4741,4842"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-da\\values-da.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-da\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,387,579,704,811,1013,1136,1266,1481,1585,1778,1903,2107,2311,2403,2491",
|
|
||||||
"endColumns": "103,191,124,106,201,122,129,214,103,192,124,203,203,91,87,102",
|
|
||||||
"endOffsets": "386,578,703,810,1012,1135,1265,1480,1584,1777,1902,2106,2310,2402,2490,2593"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "2022,2130,2322,2451,2562,2764,2891,3211,3426,3534,3727,3856,4060,4268,4364,4456",
|
|
||||||
"endColumns": "107,191,128,110,201,126,133,214,107,192,128,203,207,95,91,106",
|
|
||||||
"endOffsets": "2125,2317,2446,2557,2759,2886,3020,3421,3529,3722,3851,4055,4263,4359,4451,4558"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\src\\main\\res\\values-da\\fpauth-strings.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,2,6,7,8,5,9,3,10,11",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "178,57,303,394,451,256,546,114,617,763",
|
|
||||||
"endColumns": "76,55,89,55,93,45,69,62,144,83",
|
|
||||||
"endOffsets": "250,108,388,445,540,297,611,172,757,842"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "38,39,40,41,42,43,44,45,46,48",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "4563,4640,4696,4786,4842,4936,4982,5052,5115,5339",
|
|
||||||
"endColumns": "76,55,89,55,93,45,69,62,144,83",
|
|
||||||
"endOffsets": "4635,4691,4781,4837,4931,4977,5047,5110,5255,5418"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-da\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "185",
|
|
||||||
"endOffsets": "470"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "3025",
|
|
||||||
"endColumns": "185",
|
|
||||||
"endOffsets": "3206"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-da\\values-da.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,158,266,389,488,600,683,783,896,973,1050,1129,1238,1346,1442,1556,1658,1759,1875,1972,2051",
|
|
||||||
"endColumns": "102,107,122,98,111,82,99,112,76,76,78,108,107,95,113,101,100,115,96,78,100",
|
|
||||||
"endOffsets": "153,261,384,483,595,678,778,891,968,1045,1124,1233,1341,1437,1551,1653,1754,1870,1967,2046,2147"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,47,49",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,208,316,439,538,650,733,833,946,1023,1100,1179,1288,1396,1492,1606,1708,1809,1925,5260,5423",
|
|
||||||
"endColumns": "102,107,122,98,111,82,99,112,76,76,78,108,107,95,113,101,100,115,96,78,100",
|
|
||||||
"endOffsets": "203,311,434,533,645,728,828,941,1018,1095,1174,1283,1391,1487,1601,1703,1804,1920,2017,5334,5519"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-de\\values-de.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-de\\values-de.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,160,268,391,489,601,687,792,907,984,1060,1142,1253,1356,1455,1566,1668,1775,1897,1999,2081",
|
|
||||||
"endColumns": "104,107,122,97,111,85,104,114,76,75,81,110,102,98,110,101,106,121,101,81,100",
|
|
||||||
"endOffsets": "155,263,386,484,596,682,787,902,979,1055,1137,1248,1351,1450,1561,1663,1770,1892,1994,2076,2177"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,47,49",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,210,318,441,539,651,737,842,957,1034,1110,1192,1303,1406,1505,1616,1718,1825,1947,5433,5616",
|
|
||||||
"endColumns": "104,107,122,97,111,85,104,114,76,75,81,110,102,98,110,101,106,121,101,81,100",
|
|
||||||
"endOffsets": "205,313,436,534,646,732,837,952,1029,1105,1187,1298,1401,1500,1611,1713,1820,1942,2044,5510,5712"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-de\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,390,586,712,822,1059,1188,1332,1571,1681,1881,2010,2231,2433,2530,2619",
|
|
||||||
"endColumns": "106,195,125,109,236,128,143,238,109,199,128,220,201,96,88,104",
|
|
||||||
"endOffsets": "389,585,711,821,1058,1187,1331,1570,1680,1880,2009,2230,2432,2529,2618,2723"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "2049,2160,2356,2486,2600,2837,2970,3322,3561,3675,3875,4008,4229,4435,4536,4629",
|
|
||||||
"endColumns": "110,195,129,113,236,132,147,238,113,199,132,220,205,100,92,108",
|
|
||||||
"endOffsets": "2155,2351,2481,2595,2832,2965,3113,3556,3670,3870,4003,4224,4430,4531,4624,4733"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\src\\main\\res\\values-de\\fpauth-strings.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "19,17,21,22,23,20,24,18,25,26",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "827,708,951,1029,1095,904,1204,766,1269,1412",
|
|
||||||
"endColumns": "75,56,76,64,107,45,63,59,141,100",
|
|
||||||
"endOffsets": "898,760,1023,1089,1198,945,1263,821,1406,1508"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "38,39,40,41,42,43,44,45,46,48",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "4738,4814,4871,4948,5013,5121,5167,5231,5291,5515",
|
|
||||||
"endColumns": "75,56,76,64,107,45,63,59,141,100",
|
|
||||||
"endOffsets": "4809,4866,4943,5008,5116,5162,5226,5286,5428,5611"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-de\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "203",
|
|
||||||
"endOffsets": "488"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "3118",
|
|
||||||
"endColumns": "203",
|
|
||||||
"endOffsets": "3317"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,77 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-el\\values-el.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-basement-9.8.0.aar\\d43225e09f8a1e011d502bb1857b431e\\res\\values-el\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4",
|
|
||||||
"startColumns": "0",
|
|
||||||
"startOffsets": "285",
|
|
||||||
"endColumns": "222",
|
|
||||||
"endOffsets": "507"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "28",
|
|
||||||
"startColumns": "4",
|
|
||||||
"startOffsets": "3210",
|
|
||||||
"endColumns": "222",
|
|
||||||
"endOffsets": "3428"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-el\\values-el.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,173,281,404,515,632,717,822,948,1036,1122,1207,1318,1428,1530,1641,1750,1858,1981,2081,2166",
|
|
||||||
"endColumns": "117,107,122,110,116,84,104,125,87,85,84,110,109,101,110,108,107,122,99,84,100",
|
|
||||||
"endOffsets": "168,276,399,510,627,712,817,943,1031,1117,1202,1313,1423,1525,1636,1745,1853,1976,2076,2161,2262"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,47,49",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "105,223,331,454,565,682,767,872,998,1086,1172,1257,1368,1478,1580,1691,1800,1908,2031,5483,5651",
|
|
||||||
"endColumns": "117,107,122,110,116,84,104,125,87,85,84,110,109,101,110,108,107,122,99,84,100",
|
|
||||||
"endOffsets": "218,326,449,560,677,762,867,993,1081,1167,1252,1363,1473,1575,1686,1795,1903,2026,2126,5563,5747"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\src\\main\\res\\values-el\\fpauth-strings.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,2,6,7,8,5,9,3,10,11",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "179,57,306,384,446,259,527,113,592,711",
|
|
||||||
"endColumns": "78,54,76,60,79,45,63,64,117,82",
|
|
||||||
"endOffsets": "253,107,378,440,521,300,586,173,705,789"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "38,39,40,41,42,43,44,45,46,48",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "4838,4917,4972,5049,5110,5190,5236,5300,5365,5568",
|
|
||||||
"endColumns": "78,54,76,60,79,45,63,64,117,82",
|
|
||||||
"endOffsets": "4912,4967,5044,5105,5185,5231,5295,5360,5478,5646"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\play-services-base-9.8.0.aar\\615b82ec9f8fe5a2e42bfc8be6032e11\\res\\values-el\\values.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19",
|
|
||||||
"startColumns": "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
||||||
"startOffsets": "283,392,610,740,849,1089,1212,1342,1590,1696,1897,2024,2261,2432,2527,2615",
|
|
||||||
"endColumns": "108,217,129,108,239,122,129,247,105,200,126,236,170,94,87,107",
|
|
||||||
"endOffsets": "391,609,739,848,1088,1211,1341,1589,1695,1896,2023,2260,2431,2526,2614,2722"
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"startLines": "21,22,23,24,25,26,27,29,30,31,32,33,34,35,36,37",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "2131,2244,2462,2596,2709,2949,3076,3433,3681,3791,3992,4123,4360,4535,4634,4726",
|
|
||||||
"endColumns": "112,217,133,112,239,126,133,247,109,200,130,236,174,98,91,111",
|
|
||||||
"endOffsets": "2239,2457,2591,2704,2944,3071,3205,3676,3786,3987,4118,4355,4530,4629,4721,4833"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"logs": [
|
|
||||||
{
|
|
||||||
"outputFile": "S:\\pd_office\\pd_officer_change\\platforms\\android\\app\\build\\intermediates\\incremental\\mergeDebugResources\\merged.dir\\values-en-rAU\\values-en-rAU.xml",
|
|
||||||
"map": [
|
|
||||||
{
|
|
||||||
"source": "C:\\Users\\Venba1\\.gradle\\caches\\transforms-1\\files-1.1\\appcompat-v7-26.1.0.aar\\7570c1d0b1da07e3dde30e732b41229f\\res\\values-en-rAU\\values-en-rAU.xml",
|
|
||||||
"from": {
|
|
||||||
"startLines": "2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22",
|
|
||||||
"startColumns": "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4",
|
|
||||||
"startOffsets": "55,159,267,390,490,598,682,782,897,974,1050,1132,1235,1339,1438,1543,1646,1750,1869,1969,2051",
|
|
||||||
"endColumns": "103,107,122,99,107,83,99,114,76,75,81,102,103,98,104,102,103,118,99,81,100",
|
|
||||||
"endOffsets": "154,262,385,485,593,677,777,892,969,1045,1127,1230,1334,1433,1538,1641,1745,1864,1964,2046,2147"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||