Add inventory use, add code scanning, tweaks

master
Skylar Ittner 8 years ago
parent 5d2cc9e2f5
commit b6733a3f3d

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:gap="http://phonegap.com/ns/1.0" id="com.netsyms.terranquest.TerranQuest" version="1.2">
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:gap="http://phonegap.com/ns/1.0" android-versionCode="103000" id="com.netsyms.terranquest.TerranQuest" version="1.3.0">
<name>TerranQuest</name>
<description>
Augmented Reality fantasy game

@ -9,7 +9,7 @@
# For more information about plugins see http://cordova.apache.org/blog/releases/2013/07/23/cordova-3.html
#
com.phonegap.plugins.barcodescanner=https://github.com/phonegap/phonegap-plugin-barcodescanner.git
phonegap-plugin-barcodescanner=https://github.com/phonegap/phonegap-plugin-barcodescanner.git
cordova-plugin-whitelist=https://github.com/apache/cordova-plugin-whitelist.git
cordova-plugin-splashscreen=https://git-wip-us.apache.org/repos/asf/cordova-plugin-splashscreen.git
cordova-plugin-dialogs=https://git-wip-us.apache.org/repos/asf/cordova-plugin-dialogs.git

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="10200" android:versionName="1.2" package="com.netsyms.terranquest.TerranQuest" xmlns:android="http://schemas.android.com/apk/res/android">
<manifest android:hardwareAccelerated="true" android:versionCode="103000" android:versionName="1.3.0" package="com.netsyms.terranquest.TerranQuest" xmlns:android="http://schemas.android.com/apk/res/android">
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string/app_name" android:supportsRtl="true">
@ -9,6 +9,24 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:clearTaskOnLaunch="true" android:configChanges="orientation|keyboardHidden|screenSize" android:exported="false" android:name="com.google.zxing.client.android.CaptureActivity" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="com.google.zxing.client.android.SCAN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:label="Share" android:name="com.google.zxing.client.android.encode.EncodeActivity">
<intent-filter>
<action android:name="com.phonegap.plugins.barcodescanner.ENCODE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:label="Share" android:name="com.google.zxing.client.android.HelpActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@ -19,4 +37,7 @@
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECORD_VIDEO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
</manifest>

@ -24,12 +24,12 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'com.android.tools.build:gradle:2.1.0'
}
}
apply plugin: 'android-library'
apply plugin: 'com.android.library'
ext {
apply from: 'cordova.gradle'

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/assets"/></dataSet><dataSet config="debug"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/src/debug/assets"/></dataSet></merger>
<merger version="3"><dataSet config="main"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/assets"/><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/build/generated/assets/shaders/debug"/></dataSet><dataSet config="debug"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/src/debug/assets"/></dataSet></merger>

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/src/main/shaders"/></dataSet><dataSet config="debug"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/src/debug/shaders"/></dataSet></merger>

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/assets"/></dataSet><dataSet config="release"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/src/release/assets"/></dataSet></merger>
<merger version="3"><dataSet config="main"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/assets"/><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/build/generated/assets/shaders/release"/></dataSet><dataSet config="release"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/src/release/assets"/></dataSet></merger>

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/src/main/shaders"/></dataSet><dataSet config="release"><source path="/home/skylar/Documents/Projects/Sources/TerranQuest/platforms/android/CordovaLib/src/release/shaders"/></dataSet></merger>

@ -61,7 +61,7 @@ String doFindLatestInstalledBuildTools(String minBuildToolsVersion) {
highestBuildToolsVersion
} else {
throw new RuntimeException(
"No installed build tools found. Please install the Android build tools version " +
"No installed build tools found. Install the Android build tools version " +
minBuildToolsVersion + " or higher.")
}
}

@ -0,0 +1,65 @@
/*
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;
}
}

@ -25,6 +25,7 @@ import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.util.Pair;
import org.json.JSONException;
import org.json.JSONObject;
@ -42,8 +43,8 @@ public class CordovaInterfaceImpl implements CordovaInterface {
protected PluginManager pluginManager;
protected ActivityResultHolder savedResult;
protected CallbackMap permissionResultCallbacks;
protected CordovaPlugin activityResultCallback;
protected CordovaPlugin permissionResultCallback;
protected String initCallbackService;
protected int activityResultRequestCode;
protected boolean activityWasDestroyed = false;
@ -56,6 +57,7 @@ public class CordovaInterfaceImpl implements CordovaInterface {
public CordovaInterfaceImpl(Activity activity, ExecutorService threadPool) {
this.activity = activity;
this.threadPool = threadPool;
this.permissionResultCallbacks = new CallbackMap();
}
@Override
@ -208,24 +210,21 @@ public class CordovaInterfaceImpl implements CordovaInterface {
*/
public void onRequestPermissionResult(int requestCode, String[] permissions,
int[] grantResults) throws JSONException {
if(permissionResultCallback != null)
{
permissionResultCallback.onRequestPermissionResult(requestCode, permissions, grantResults);
permissionResultCallback = null;
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) {
permissionResultCallback = plugin;
String[] permissions = new String [1];
permissions[0] = permission;
getActivity().requestPermissions(permissions, requestCode);
requestPermissions(plugin, requestCode, permissions);
}
public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions)
{
permissionResultCallback = plugin;
getActivity().requestPermissions(permissions, requestCode);
public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions) {
int mappedRequestCode = permissionResultCallbacks.registerCallback(plugin, requestCode);
getActivity().requestPermissions(permissions, mappedRequestCode);
}
public boolean hasPermission(String permission)

@ -31,7 +31,7 @@ import android.webkit.WebChromeClient.CustomViewCallback;
* are not expected to implement it.
*/
public interface CordovaWebView {
public static final String CORDOVA_VERSION = "5.1.1";
public static final String CORDOVA_VERSION = "5.2.1";
void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences);

@ -135,6 +135,7 @@ public class CordovaWebViewImpl implements CordovaWebView {
if (recreatePlugins) {
// Don't re-initialize on first load.
if (loadedUrl != null) {
appPlugin = null;
pluginManager.init();
}
loadedUrl = url;

@ -37,6 +37,9 @@ class SystemCookieManager implements ICordovaCookieManager {
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);
}

@ -47,6 +47,10 @@
{
"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=\"BarcodeScanner\"><param name=\"android-package\" value=\"com.phonegap.plugins.barcodescanner.BarcodeScanner\" /></feature>",
"count": 1
}
]
}
@ -87,8 +91,34 @@
"count": 1
}
],
"/manifest/application": [],
"/manifest": []
"/manifest/application": [
{
"xml": "<activity android:clearTaskOnLaunch=\"true\" android:configChanges=\"orientation|keyboardHidden|screenSize\" android:exported=\"false\" android:name=\"com.google.zxing.client.android.CaptureActivity\" android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\" android:windowSoftInputMode=\"stateAlwaysHidden\"><intent-filter><action android:name=\"com.google.zxing.client.android.SCAN\" /><category android:name=\"android.intent.category.DEFAULT\" /></intent-filter></activity>",
"count": 1
},
{
"xml": "<activity android:label=\"Share\" android:name=\"com.google.zxing.client.android.encode.EncodeActivity\"><intent-filter><action android:name=\"com.phonegap.plugins.barcodescanner.ENCODE\" /><category android:name=\"android.intent.category.DEFAULT\" /></intent-filter></activity>",
"count": 1
},
{
"xml": "<activity android:label=\"Share\" android:name=\"com.google.zxing.client.android.HelpActivity\"><intent-filter><action android:name=\"android.intent.action.VIEW\" /><category android:name=\"android.intent.category.DEFAULT\" /></intent-filter></activity>",
"count": 1
}
],
"/manifest": [
{
"xml": "<uses-permission android:name=\"android.permission.CAMERA\" />",
"count": 1
},
{
"xml": "<uses-permission android:name=\"android.permission.FLASHLIGHT\" />",
"count": 1
},
{
"xml": "<uses-feature android:name=\"android.hardware.camera\" android:required=\"false\" />",
"count": 1
}
]
}
}
}
@ -129,6 +159,9 @@
},
"cordova-plugin-whitelist": {
"PACKAGE_NAME": "com.netsyms.terranquest.TerranQuest"
},
"phonegap-plugin-barcodescanner": {
"PACKAGE_NAME": "com.netsyms.terranquest.TerranQuest"
}
},
"dependent_plugins": {},
@ -434,6 +467,14 @@
"file": "plugins/cordova-plugin-whitelist/whitelist.js",
"id": "cordova-plugin-whitelist.whitelist",
"runs": true
},
{
"id": "phonegap-plugin-barcodescanner.BarcodeScanner",
"file": "plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js",
"pluginId": "phonegap-plugin-barcodescanner",
"clobbers": [
"cordova.plugins.barcodeScanner"
]
}
],
"plugin_metadata": {
@ -448,6 +489,7 @@
"cordova-plugin-media-capture": "1.2.1-dev",
"cordova-plugin-network-information": "1.2.1-dev",
"cordova-plugin-splashscreen": "3.2.2-dev",
"cordova-plugin-whitelist": "1.2.1"
"cordova-plugin-whitelist": "1.2.1",
"phonegap-plugin-barcodescanner": "6.0.1"
}
}

@ -0,0 +1 @@
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M576 1152v128h-128v-128h128zm0-768v128h-128v-128h128zm768 0v128h-128v-128h128zm-1024 1023h384v-383h-384v383zm0-767h384v-384h-384v384zm768 0h384v-384h-384v384zm-256 256v640h-640v-640h640zm512 512v128h-128v-128h128zm256 0v128h-128v-128h128zm0-512v384h-384v-128h-128v384h-128v-640h384v128h128v-128h128zm-768-768v640h-640v-640h640zm768 0v640h-640v-640h640z"/></svg>

After

Width:  |  Height:  |  Size: 461 B

@ -1,5 +1,5 @@
// Platform: android
// c517ca811b4948b630e0b74dbae6c9637939da24
// 2fd4bcb84048415922d13d80d35b8d1668e8e150
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@ -19,7 +19,7 @@
under the License.
*/
;(function() {
var PLATFORM_VERSION_BUILD_LABEL = '5.1.1';
var PLATFORM_VERSION_BUILD_LABEL = '5.2.1';
// file: src/scripts/require.js
/*jshint -W079 */
@ -330,7 +330,7 @@ module.exports = cordova;
});
// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/android/nativeapiprovider.js
// file: D:/cordova/cordova-android/cordova-js-src/android/nativeapiprovider.js
define("cordova/android/nativeapiprovider", function(require, exports, module) {
/**
@ -353,7 +353,7 @@ module.exports = {
});
// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/android/promptbasednativeapi.js
// file: D:/cordova/cordova-android/cordova-js-src/android/promptbasednativeapi.js
define("cordova/android/promptbasednativeapi", function(require, exports, module) {
/**
@ -862,7 +862,7 @@ module.exports = channel;
});
// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/exec.js
// file: D:/cordova/cordova-android/cordova-js-src/exec.js
define("cordova/exec", function(require, exports, module) {
/**
@ -1611,7 +1611,7 @@ exports.reset();
});
// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/platform.js
// file: D:/cordova/cordova-android/cordova-js-src/platform.js
define("cordova/platform", function(require, exports, module) {
// The last resume event that was received that had the result of a plugin call.
@ -1721,7 +1721,7 @@ function onMessageFromNative(msg) {
});
// file: /Users/steveng/repo/cordova/cordova-android/cordova-js-src/plugin/android/app.js
// file: D:/cordova/cordova-android/cordova-js-src/plugin/android/app.js
define("cordova/plugin/android/app", function(require, exports, module) {
var exec = require('cordova/exec');

@ -301,6 +301,14 @@ module.exports = [
"file": "plugins/cordova-plugin-whitelist/whitelist.js",
"id": "cordova-plugin-whitelist.whitelist",
"runs": true
},
{
"id": "phonegap-plugin-barcodescanner.BarcodeScanner",
"file": "plugins/phonegap-plugin-barcodescanner/www/barcodescanner.js",
"pluginId": "phonegap-plugin-barcodescanner",
"clobbers": [
"cordova.plugins.barcodeScanner"
]
}
];
module.exports.metadata =
@ -317,7 +325,8 @@ module.exports.metadata =
"cordova-plugin-media-capture": "1.2.1-dev",
"cordova-plugin-network-information": "1.2.1-dev",
"cordova-plugin-splashscreen": "3.2.2-dev",
"cordova-plugin-whitelist": "1.2.1"
"cordova-plugin-whitelist": "1.2.1",
"phonegap-plugin-barcodescanner": "6.0.1"
};
// BOTTOM OF METADATA
});

@ -226,12 +226,13 @@ body {
box-shadow: 0 0 5px grey;
width: 60px;
height: 60px;
margin-bottom: 20px;
}
#buttons .circlebutton img {
position: absolute;
top: 15px;
left: 15px;
position: static;
margin-top: 14px;
margin-left: 14px;
width: 30px;
height: 30px;
}

@ -18,28 +18,36 @@ function askLogout() {
}
function logout() {
localStorage.setItem("username", '');
localStorage.setItem("password", '');
username = null;
password = null;
$('#content-zone').load("screens/login.html");
$.getJSON(mkApiUrl('deletesession', 'gs'), {}, function (data) {
if (data.status === 'OK') {
localStorage.setItem("username", '');
localStorage.setItem("password", '');
username = null;
password = null;
$('#content-zone').load("screens/login.html");
} else {
navigator.notification.alert("Server did not properly acknowledge logout. You might have problems for the next few hours if you switch accounts.", null, "Error", 'Dismiss');
}
}).fail(function () {
navigator.notification.alert("Cannot connect to authentication server. Check your Internet connection and try again. If that fails, clear the app data or reinstall TerranQuest.", null, "Error", 'Dismiss');
});
}
function checkUserHasTeamOpenChooserIfNot(username) {
$.getJSON(mkApiUrl('getstats', 'gs'), {
user: username
}, function (data) {
if (data.status === 'OK' && data.stats.teamid !== null && data.stats.teamid > 0) {
// We're all good.
userteamid = data.stats.teamid;
openscreen("home");
} else {
// Open the team intro thingy
openscreen('chooseteam');
}
}).fail(function () {
});
user: username
}, function (data) {
if (data.status === 'OK' && data.stats.teamid !== null && data.stats.teamid > 0) {
// We're all good.
userteamid = data.stats.teamid;
openscreen("home");
} else {
// Open the team intro thingy
openscreen('chooseteam');
}
}).fail(function () {
});
}
function dosignup() {
@ -71,21 +79,21 @@ function dosignup() {
name: $('#nameBox').val(),
email: $('#emailBox').val()
},
function (data) {
if (data === 'OK') {
username = $('#usernameBox').val().toLowerCase();
password = $('#passwordBox').val();
localStorage.setItem("username", username);
localStorage.setItem("password", password);
checkUserHasTeamOpenChooserIfNot(username);
} else {
$('#signupBtn').html('<i class="fa fa-user-plus"></i> Sign Up');
$('#signupBtn').attr('disabled', false);
$('#errormsg').text("Error: " + data);
$('#errorbase').css('display', 'block');
}
authOpInProgress = false;
}).fail(function () {
function (data) {
if (data === 'OK') {
username = $('#usernameBox').val().toLowerCase();
password = $('#passwordBox').val();
localStorage.setItem("username", username);
localStorage.setItem("password", password);
checkUserHasTeamOpenChooserIfNot(username);
} else {
$('#signupBtn').html('<i class="fa fa-user-plus"></i> Sign Up');
$('#signupBtn').attr('disabled', false);
$('#errormsg').text("Error: " + data);
$('#errorbase').css('display', 'block');
}
authOpInProgress = false;
}).fail(function () {
$('#signupBtn').html('<i class="fa fa-user-plus"></i> Sign Up');
$('#signupBtn').attr('disabled', false);
$('#errormsg').text("Error: Network failure.");
@ -111,42 +119,42 @@ function dologin() {
$('#loginBtn').html('<i class="fa fa-cog fa-spin fa-fw"></i> Logging in...');
$.post("https://sso.netsyms.com/api/simpleauth.php",
{user: $('#usernameBox').val(), pass: $('#passwordBox').val()},
function (data) {
if (data === 'OK') {
// Now that auth is OK, ping the game server
$.getJSON(mkApiUrl('pinglogin') + "?user=" + $('#usernameBox').val(), function (out) {
if (out.status === 'OK') {
username = $('#usernameBox').val().toLowerCase();
password = $('#passwordBox').val();
localStorage.setItem("username", username);
localStorage.setItem("password", password);
navigator.splashscreen.hide();
checkUserHasTeamOpenChooserIfNot(username);
function (data) {
if (data === 'OK') {
// Now that auth is OK, ping the game server
$.getJSON(mkApiUrl('pinglogin') + "?user=" + $('#usernameBox').val(), function (out) {
if (out.status === 'OK') {
username = $('#usernameBox').val().toLowerCase();
password = $('#passwordBox').val();
localStorage.setItem("username", username);
localStorage.setItem("password", password);
navigator.splashscreen.hide();
checkUserHasTeamOpenChooserIfNot(username);
} else {
$('#loginBtn').html('<i class="fa fa-sign-in"></i> Login');
$('#loginBtn').attr('disabled', false);
$('#errormsg').text("Error: " + out.message);
$('#errorbase').css('display', 'block');
$('#loading').css('display', 'none');
authOpInProgress = false;
}
}).fail(function (err) {
$('#loginBtn').html('<i class="fa fa-sign-in"></i> Login');
$('#loginBtn').attr('disabled', false);
$('#errormsg').text("Error: Login OK, but cannot connect to game server. Try again later.");
$('#errorbase').css('display', 'block');
$('#loading').css('display', 'none');
authOpInProgress = false;
});
} else {
$('#loginBtn').html('<i class="fa fa-sign-in"></i> Login');
$('#loginBtn').attr('disabled', false);
$('#errormsg').text("Error: " + out.message);
$('#errormsg').text(data);
$('#errorbase').css('display', 'block');
$('#loading').css('display', 'none');
authOpInProgress = false;
}
}).fail(function (err) {
$('#loginBtn').html('<i class="fa fa-sign-in"></i> Login');
$('#loginBtn').attr('disabled', false);
$('#errormsg').text("Error: Login OK, but cannot connect to game server. Try again later.");
$('#errorbase').css('display', 'block');
$('#loading').css('display', 'none');
authOpInProgress = false;
});
} else {
$('#loginBtn').html('<i class="fa fa-sign-in"></i> Login');
$('#loginBtn').attr('disabled', false);
$('#errormsg').text(data);
$('#errorbase').css('display', 'block');
$('#loading').css('display', 'none');
}
authOpInProgress = false;
}).fail(function () {
}).fail(function () {
$('#loginBtn').html('<i class="fa fa-sign-in"></i> Login');
$('#loginBtn').attr('disabled', false);
$('#errormsg').text("Error: Network failure.");

@ -83,7 +83,18 @@ function scanCode() {
cordova.plugins.barcodeScanner.scan(
function (result) {
if (!result.cancelled) {
navigator.notification.alert("Scanned code: " + result.text, null, "OK", 'Dismiss');
$.getJSON(mkApiUrl('code2item', 'gs'), {
code: result.text
}, function (data) {
if (data.status === 'OK') {
navigator.notification.alert("Found one " + data.message, null, "Found an item!", 'OK');
} else {
navigator.notification.alert(data.message, null, "Huh?", 'OK');
}
}).fail(function () {
navigator.notification.alert("Nothing happened!", null, "Huh?", 'OK');
});
//navigator.notification.alert("Scanned code: " + result.text, null, "OK", 'Dismiss');
}
},
function (error) {
@ -91,7 +102,7 @@ function scanCode() {
}
);
} catch (ex) {
alert(ex.message);
navigator.notification.alert(ex.message, null, "Error", 'Dismiss');
}
}

@ -11,7 +11,7 @@
* Syncs the user's stats with the server and calls refreshStats().
*/
function syncStats() {
$.getJSON(mkApiUrl('getstats'), {
$.getJSON(mkApiUrl('getstats', 'gs'), {
user: username
}, function (data) {
if (data.status === 'OK') {

@ -0,0 +1,150 @@
cordova.define("phonegap-plugin-barcodescanner.BarcodeScanner", function(require, exports, module) {
/**
* cordova is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) Matt Kane 2010
* Copyright (c) 2011, IBM Corporation
*/
var exec = require("cordova/exec");
var scanInProgress = false;
/**
* Constructor.
*
* @returns {BarcodeScanner}
*/
function BarcodeScanner() {
/**
* Encoding constants.
*
* @type Object
*/
this.Encode = {
TEXT_TYPE: "TEXT_TYPE",
EMAIL_TYPE: "EMAIL_TYPE",
PHONE_TYPE: "PHONE_TYPE",
SMS_TYPE: "SMS_TYPE"
// CONTACT_TYPE: "CONTACT_TYPE", // TODO: not implemented, requires passing a Bundle class from Javascript to Java
// LOCATION_TYPE: "LOCATION_TYPE" // TODO: not implemented, requires passing a Bundle class from Javascript to Java
};
/**
* Barcode format constants, defined in ZXing library.
*
* @type Object
*/
this.format = {
"all_1D": 61918,
"aztec": 1,
"codabar": 2,
"code_128": 16,
"code_39": 4,
"code_93": 8,
"data_MATRIX": 32,
"ean_13": 128,
"ean_8": 64,
"itf": 256,
"maxicode": 512,
"msi": 131072,
"pdf_417": 1024,
"plessey": 262144,
"qr_CODE": 2048,
"rss_14": 4096,
"rss_EXPANDED": 8192,
"upc_A": 16384,
"upc_E": 32768,
"upc_EAN_EXTENSION": 65536
};
}
/**
* Read code from scanner.
*
* @param {Function} successCallback This function will recieve a result object: {
* text : '12345-mock', // The code that was scanned.
* format : 'FORMAT_NAME', // Code format.
* cancelled : true/false, // Was canceled.
* }
* @param {Function} errorCallback
* @param config
*/
BarcodeScanner.prototype.scan = function (successCallback, errorCallback, config) {
if (config instanceof Array) {
// do nothing
} else {
if (typeof(config) === 'object') {
config = [ config ];
} else {
config = [];
}
}
if (errorCallback == null) {
errorCallback = function () {
};
}
if (typeof errorCallback != "function") {
console.log("BarcodeScanner.scan failure: failure parameter not a function");
return;
}
if (typeof successCallback != "function") {
console.log("BarcodeScanner.scan failure: success callback parameter must be a function");
return;
}
if (scanInProgress) {
errorCallback('Scan is already in progress');
return;
}
scanInProgress = true;
exec(
function(result) {
scanInProgress = false;
successCallback(result);
},
function(error) {
scanInProgress = false;
errorCallback(error);
},
'BarcodeScanner',
'scan',
config
);
};
//-------------------------------------------------------------------
BarcodeScanner.prototype.encode = function (type, data, successCallback, errorCallback, options) {
if (errorCallback == null) {
errorCallback = function () {
};
}
if (typeof errorCallback != "function") {
console.log("BarcodeScanner.encode failure: failure parameter not a function");
return;
}
if (typeof successCallback != "function") {
console.log("BarcodeScanner.encode failure: success callback parameter must be a function");
return;
}
exec(successCallback, errorCallback, 'BarcodeScanner', 'encode', [
{"type": type, "data": data, "options": options}
]);
};
var barcodeScanner = new BarcodeScanner();
module.exports = barcodeScanner;
});

@ -32,7 +32,7 @@
function setTeam() {
//alert($('input[name=teamChooser]:checked').val());
var team = $('input[name=teamChooser]:checked').val();
$.getJSON(mkApiUrl('setteam', 'gs'), {
$.getJSON(mkApiUrl('setteam', 'gs'), {
teamid: team
}, function (data) {
if (data.status === 'OK') {
@ -40,7 +40,7 @@
openscreen("home");
} else {
// Error?
alert("Error: " + data.message);
navigator.notification.alert(data.message, null, "Error", 'OK');
}
}).fail(function () {
alert("Something bad happened, try again later.");

@ -36,6 +36,9 @@
<div class="circlebutton" onclick="openMenu()">
<img src="assets/bars.svg" alt="Menu" />
</div>
<div class="circlebutton" onclick="scanCode()">
<img src="assets/qrcode.svg" alt="Scan Code" />
</div>
</div>
<div id="chatbox">

@ -7,15 +7,36 @@
</div>
<script>
function useitem(uuid) {
$.getJSON(mkApiUrl('useitem', 'gs'), {
itemuuid: uuid
}, function (data) {
if (data.status === 'OK') {
loadinventory();
syncStats();
} else {
navigator.notification.alert(data.message, null, "Error", 'OK');
}
}).fail(function () {
navigator.notification.alert("Cannot use item. Try again.", null, "Error", 'OK');
});
}
function getitemhtmlfromjson(item) {
return "\
var itemhtml = "\
<div class='list-group-item inventory-item' id='item-" + item.itemuuid + "'>\
<h4 class='itemname'>" + item.itemname + "</h4>\
<p class='itemdesc'>" + item.itemdesc + "</p>\
<span class='itemid' style='display: none;'>" + item.itemid + "</span>\
<p class='itemdesc'>" + item.itemdesc + "</p>";
if (item.classname == "healmagic") {
itemhtml += "<span class='btn btn-success' onclick=\"useitem('" + item.itemuuid + "')\">\
Use Item\
</span>";
}
itemhtml += "<span class='itemid' style='display: none;'>" + item.itemid + "</span>\
<span class='itemclassid' style='display: none;'>" + item.classid + "</span>\
<span class='itemjson' style='display: none;'>" + item.itemjson + "</span>\
</div>";
return itemhtml;
}
function loadinventory() {
@ -34,6 +55,6 @@
$('#inventory-list').html(content);
});
}
loadinventory();
</script>

@ -10,9 +10,11 @@
<script>
var thisplace = null;
var placeteam = 0;
var capturebtndisabled = false;
function resetcapturebtn() {
capturebtndisabled = false;
$('#capturebtn').removeClass('btn-warning');
$('#capturebtn').addClass('btn-primary');
$('#capturebtn').removeClass('disabled');
@ -64,6 +66,7 @@
}
function attemptcapture() {
capturebtndisabled = true;
$('#capturebtn').prop('disabled', true);
$('#capturebtn').addClass('disabled');
$.getJSON(mkApiUrl('attackplace', 'gs'), {
@ -88,6 +91,7 @@
}
function attemptclaim() {
capturebtndisabled = true;
$('#capturebtn').prop('disabled', true);
$('#capturebtn').addClass('disabled');
$.getJSON(mkApiUrl('claimplace', 'gs'), {
@ -111,6 +115,9 @@
}
function attempttake() {
if (capturebtndisabled) {
return;
}
if (placeteam == 0) {
attemptclaim();
} else if (placeteam == userteamid) {

@ -17,13 +17,12 @@
under the License.
*/
// GENERATED FILE! DO NOT EDIT!
apply plugin: 'android'
apply plugin: 'com.android.application'
buildscript {
repositories {
mavenCentral()
jcenter()
}
// Switch the Android Gradle plugin version requirement depending on the
@ -31,17 +30,20 @@ buildscript {
// http://tools.android.com/tech-docs/new-build-system/version-compatibility
// and https://issues.apache.org/jira/browse/CB-8143
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'com.android.tools.build:gradle:2.1.0'
}
}
}
// Allow plugins to declare Maven dependencies via build-extras.gradle.
repositories {
mavenCentral()
allprojects {
repositories {
mavenCentral();
jcenter()
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.8'
gradleVersion = '2.13'
}
// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.
@ -86,6 +88,7 @@ ext {
}
// PLUGIN GRADLE EXTENSIONS START
apply from: "phonegap-plugin-barcodescanner/TerranQuest-barcodescanner.gradle"
// PLUGIN GRADLE EXTENSIONS END
def hasBuildExtras = file('build-extras.gradle').exists()
@ -162,7 +165,7 @@ android {
}
defaultConfig {
versionCode cdvVersionCode ?: Integer.parseInt("" + privateHelpers.extractIntFromManifest("versionCode") + "0")
versionCode cdvVersionCode ?: Integer.parseInt("" + privateHelpers.extractIntFromManifest("versionCode"))
applicationId privateHelpers.extractStringFromManifest("package")
if (cdvMinSdkVersion != null) {
@ -180,13 +183,13 @@ android {
if (Boolean.valueOf(cdvBuildMultipleApks)) {
productFlavors {
armv7 {
versionCode defaultConfig.versionCode + 2
versionCode defaultConfig.versionCode*10 + 2
ndk {
abiFilters "armeabi-v7a", ""
}
}
x86 {
versionCode defaultConfig.versionCode + 4
versionCode defaultConfig.versionCode*10 + 4
ndk {
abiFilters "x86", ""
}
@ -197,7 +200,12 @@ android {
}
}
}
} else if (!cdvVersionCode) {
}
/*
ELSE NOTHING! DON'T MESS WITH THE VERSION CODE IF YOU DON'T HAVE TO!
else if (!cdvVersionCode) {
def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest("minSdkVersion")
// Vary versionCode by the two most common API levels:
// 14 is ICS, which is the lowest API level for many apps.
@ -208,6 +216,7 @@ android {
defaultConfig.versionCode += 8
}
}
*/
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_6

@ -17,23 +17,29 @@
under the License.
*/
var Q = require('q');
var fs = require('fs');
var path = require('path');
var shell = require('shelljs');
var CordovaError = require('cordova-common').CordovaError;
var PlatformJson = require('cordova-common').PlatformJson;
var ActionStack = require('cordova-common').ActionStack;
var AndroidProject = require('./lib/AndroidProject');
var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
var PluginManager = require('cordova-common').PluginManager;
var ConsoleLogger = require('./lib/ConsoleLogger');
var pluginHandlers = require('./lib/pluginHandlers');
var CordovaLogger = require('cordova-common').CordovaLogger;
var selfEvents = require('cordova-common').events;
var PLATFORM = 'android';
function setupEvents(externalEventEmitter) {
if (externalEventEmitter) {
// This will make the platform internal events visible outside
selfEvents.forwardEventsTo(externalEventEmitter);
return externalEventEmitter;
}
// There is no logger if external emitter is not present,
// so attach a console logger
CordovaLogger.get().subscribe(selfEvents);
return selfEvents;
}
/**
* Class, that acts as abstraction over particular platform. Encapsulates the
* platform's properties and methods.
@ -48,13 +54,8 @@ var PLATFORM = 'android';
function Api(platform, platformRootDir, events) {
this.platform = PLATFORM;
this.root = path.resolve(__dirname, '..');
this.events = events || ConsoleLogger.get();
// NOTE: trick to share one EventEmitter instance across all js code
require('cordova-common').events = this.events;
this._platformJson = PlatformJson.load(this.root, platform);
this._pluginInfoProvider = new PluginInfoProvider();
this._munger = new PlatformMunger(this.platform, this.root, this._platformJson, this._pluginInfoProvider);
setupEvents(events);
var self = this;
@ -91,8 +92,10 @@ function Api(platform, platformRootDir, events) {
* instance or rejected with CordovaError.
*/
Api.createPlatform = function (destination, config, options, events) {
events = setupEvents(events);
return require('../../lib/create')
.create(destination, config, options, events || ConsoleLogger.get())
.create(destination, config, options, events)
.then(function (destination) {
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
return new PlatformApi(PLATFORM, destination, events);
@ -116,8 +119,10 @@ Api.createPlatform = function (destination, config, options, events) {
* instance or rejected with CordovaError.
*/
Api.updatePlatform = function (destination, options, events) {
events = setupEvents(events);
return require('../../lib/create')
.update(destination, options, events || ConsoleLogger.get())
.update(destination, options, events)
.then(function (destination) {
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
return new PlatformApi('android', destination, events);
@ -155,8 +160,8 @@ Api.prototype.getPlatformInfo = function () {
* @return {Promise} Return a promise either fulfilled, or rejected with
* CordovaError instance.
*/
Api.prototype.prepare = function (cordovaProject) {
return require('./lib/prepare').prepare.call(this, cordovaProject);
Api.prototype.prepare = function (cordovaProject, prepareOptions) {
return require('./lib/prepare').prepare.call(this, cordovaProject, prepareOptions);
};
/**
@ -180,56 +185,25 @@ Api.prototype.prepare = function (cordovaProject) {
* CordovaError instance.
*/
Api.prototype.addPlugin = function (plugin, installOptions) {
if (!plugin || plugin.constructor.name !== 'PluginInfo')
return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
var project = AndroidProject.getProjectFile(this.root);
installOptions = installOptions || {};
installOptions.variables = installOptions.variables || {};
// Add PACKAGE_NAME variable into vars
if (!installOptions.variables.PACKAGE_NAME) {
installOptions.variables.PACKAGE_NAME = project.getPackageName();
}
var self = this;
var actions = new ActionStack();
var project = AndroidProject.getProjectFile(this.root);
// gather all files needs to be handled during install
plugin.getFilesAndFrameworks(this.platform)
.concat(plugin.getAssets(this.platform))
.concat(plugin.getJsModules(this.platform))
.forEach(function(item) {
actions.push(actions.createAction(
pluginHandlers.getInstaller(item.itemType), [item, plugin, project, installOptions],
pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, installOptions]));
});
// run through the action stack
return actions.process(this.platform)
.then(function () {
if (project) {
project.write();
}
// Add PACKAGE_NAME variable into vars
if (!installOptions.variables.PACKAGE_NAME) {
installOptions.variables.PACKAGE_NAME = project.getPackageName();
}
self._munger
// Ignore passed `is_top_level` option since platform itself doesn't know
// anything about managing dependencies - it's responsibility of caller.
.add_plugin_changes(plugin, installOptions.variables, /*is_top_level=*/true, /*should_increment=*/true)
.save_all();
return PluginManager.get(this.platform, this.locations, project)
.addPlugin(plugin, installOptions)
.then(function () {
if (plugin.getFrameworks(this.platform).length === 0) return;
if (plugin.getFrameworks(self.platform).length > 0) {
self.events.emit('verbose', 'Updating build files since android plugin contained <framework>');
selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();
}
var targetDir = installOptions.usePlatformWww ?
self.locations.platformWww :
self.locations.www;
self._addModulesInfo(plugin, targetDir);
});
}.bind(this))
// CB-11022 Return truthy value to prevent running prepare after
.thenResolve(true);
};
/**
@ -246,48 +220,17 @@ Api.prototype.addPlugin = function (plugin, installOptions) {
* CordovaError instance.
*/
Api.prototype.removePlugin = function (plugin, uninstallOptions) {
if (!plugin || plugin.constructor.name !== 'PluginInfo')
return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
var self = this;
var actions = new ActionStack();
var project = AndroidProject.getProjectFile(this.root);
return PluginManager.get(this.platform, this.locations, project)
.removePlugin(plugin, uninstallOptions)
.then(function () {
if (plugin.getFrameworks(this.platform).length === 0) return;
// queue up plugin files
plugin.getFilesAndFrameworks(this.platform)
.concat(plugin.getAssets(this.platform))
.concat(plugin.getJsModules(this.platform))
.forEach(function(item) {
actions.push(actions.createAction(
pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, uninstallOptions],
pluginHandlers.getInstaller(item.itemType), [item, plugin, project, uninstallOptions]));
});
// run through the action stack
return actions.process(this.platform)
.then(function() {
if (project) {
project.write();
}
self._munger
// Ignore passed `is_top_level` option since platform itself doesn't know
// anything about managing dependencies - it's responsibility of caller.
.remove_plugin_changes(plugin, /*is_top_level=*/true)
.save_all();
if (plugin.getFrameworks(self.platform).length > 0) {
self.events.emit('verbose', 'Updating build files since android plugin contained <framework>');
selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();
}
var targetDir = uninstallOptions.usePlatformWww ?
self.locations.platformWww :
self.locations.www;
self._removeModulesInfo(plugin, targetDir);
});
}.bind(this))
// CB-11022 Return truthy value to prevent running prepare after
.thenResolve(true);
};
/**
@ -385,6 +328,9 @@ Api.prototype.clean = function(cleanOptions) {
return require('./lib/check_reqs').run()
.then(function () {
return require('./lib/build').runClean.call(self, cleanOptions);
})
.then(function () {
return require('./lib/prepare').clean.call(self, cleanOptions);
});
};
@ -401,104 +347,3 @@ Api.prototype.requirements = function() {
};
module.exports = Api;
/**
* Removes the specified modules from list of installed modules and updates
* platform_json and cordova_plugins.js on disk.
*
* @param {PluginInfo} plugin PluginInfo instance for plugin, which modules
* needs to be added.
* @param {String} targetDir The directory, where updated cordova_plugins.js
* should be written to.
*/
Api.prototype._addModulesInfo = function(plugin, targetDir) {
var installedModules = this._platformJson.root.modules || [];
var installedPaths = installedModules.map(function (installedModule) {
return installedModule.file;
});
var modulesToInstall = plugin.getJsModules(this.platform)
.filter(function (moduleToInstall) {
return installedPaths.indexOf(moduleToInstall.file) === -1;
}).map(function (moduleToInstall) {
var moduleName = plugin.id + '.' + ( moduleToInstall.name || moduleToInstall.src.match(/([^\/]+)\.js/)[1] );
var obj = {
file: ['plugins', plugin.id, moduleToInstall.src].join('/'),
id: moduleName
};
if (moduleToInstall.clobbers.length > 0) {
obj.clobbers = moduleToInstall.clobbers.map(function(o) { return o.target; });
}
if (moduleToInstall.merges.length > 0) {
obj.merges = moduleToInstall.merges.map(function(o) { return o.target; });
}
if (moduleToInstall.runs) {
obj.runs = true;
}
return obj;
});
this._platformJson.root.modules = installedModules.concat(modulesToInstall);
if (!this._platformJson.root.plugin_metadata) {
this._platformJson.root.plugin_metadata = {};
}
this._platformJson.root.plugin_metadata[plugin.id] = plugin.version;
this._writePluginModules(targetDir);
this._platformJson.save();
};
/**
* Removes the specified modules from list of installed modules and updates
* platform_json and cordova_plugins.js on disk.
*
* @param {PluginInfo} plugin PluginInfo instance for plugin, which modules
* needs to be removed.
* @param {String} targetDir The directory, where updated cordova_plugins.js
* should be written to.
*/
Api.prototype._removeModulesInfo = function(plugin, targetDir) {
var installedModules = this._platformJson.root.modules || [];
var modulesToRemove = plugin.getJsModules(this.platform)
.map(function (jsModule) {
return ['plugins', plugin.id, jsModule.src].join('/');
});
var updatedModules = installedModules
.filter(function (installedModule) {
return (modulesToRemove.indexOf(installedModule.file) === -1);
});
this._platformJson.root.modules = updatedModules;
if (this._platformJson.root.plugin_metadata) {
delete this._platformJson.root.plugin_metadata[plugin.id];
}
this._writePluginModules(targetDir);
this._platformJson.save();
};
/**
* Fetches all installed modules, generates cordova_plugins contents and writes
* it to file.
*
* @param {String} targetDir Directory, where write cordova_plugins.js to.
* Ususally it is either <platform>/www or <platform>/platform_www
* directories.
*/
Api.prototype._writePluginModules = function (targetDir) {
// Write out moduleObjects as JSON wrapped in a cordova module to cordova_plugins.js
var final_contents = 'cordova.define(\'cordova/plugin_list\', function(require, exports, module) {\n';
final_contents += 'module.exports = ' + JSON.stringify(this._platformJson.root.modules, null, ' ') + ';\n';
final_contents += 'module.exports.metadata = \n';
final_contents += '// TOP OF METADATA\n';
final_contents += JSON.stringify(this._platformJson.root.plugin_metadata, null, 4) + ';\n';
final_contents += '// BOTTOM OF METADATA\n';
final_contents += '});'; // Close cordova.define.
shell.mkdir('-p', targetDir);
fs.writeFileSync(path.join(targetDir, 'cordova_plugins.js'), final_contents, 'utf-8');
};

@ -41,6 +41,8 @@ var buildOpts = nopt({
// Make buildOptions compatible with PlatformApi build method spec
buildOpts.argv = buildOpts.argv.original;
require('./loggingHelper').adjustLoggerLevel(buildOpts);
new Api().build(buildOpts)
.catch(function(err) {
console.error(err.stack);

@ -21,6 +21,7 @@
var Api = require('./Api');
var path = require('path');
var nopt = require('nopt');
// Support basic help commands
if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
@ -29,7 +30,21 @@ if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >=
process.exit(0);
}
new Api().clean({argv: process.argv.slice(2)})
// Do some basic argument parsing
var opts = nopt({
'verbose' : Boolean,
'silent' : Boolean
}, { 'd' : '--verbose' });
// Make buildOptions compatible with PlatformApi clean method spec
opts.argv = opts.argv.original;
// Skip cleaning prepared files when not invoking via cordova CLI.
opts.noPrepare = true;
require('./loggingHelper').adjustLoggerLevel(opts);
new Api().clean(opts)
.catch(function(err) {
console.error(err.stack);
process.exit(2);

@ -56,25 +56,34 @@ Adb.devices = function (opts) {
};
Adb.install = function (target, packagePath, opts) {
events.emit('verbose', 'Installing apk ' + packagePath + ' on ' + target + '...');
events.emit('verbose', 'Installing apk ' + packagePath + ' on target ' + target + '...');
var args = ['-s', target, 'install'];
if (opts && opts.replace) args.push('-r');
return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()})
.then(function(output) {
// 'adb install' seems to always returns no error, even if installation fails
// so we catching output to detect installation failure
if (output.match(/Failure/))
if (output.match(/Failure/)) {
if (output.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {
output += '\n\n' + 'Sign the build using \'-- --keystore\' or \'--buildConfig\'' +
' or sign and deploy the unsigned apk manually using Android tools.';
} else if (output.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {
output += '\n\n' + 'You\'re trying to install apk with a lower versionCode that is already installed.' +
'\nEither uninstall an app or increment the versionCode.';
}
return Q.reject(new CordovaError('Failed to install apk to device: ' + output));
}
});
};
Adb.uninstall = function (target, packageId) {
events.emit('verbose', 'Uninstalling ' + packageId + ' from ' + target + '...');
events.emit('verbose', 'Uninstalling package ' + packageId + ' from target ' + target + '...');
return spawn('adb', ['-s', target, 'uninstall', packageId], {cwd: os.tmpdir()});
};
Adb.shell = function (target, shellCommand) {
events.emit('verbose', 'Running command "' + shellCommand + '" on ' + target + '...');
events.emit('verbose', 'Running adb shell command "' + shellCommand + '" on target ' + target + '...');
var args = ['-s', target, 'shell'];
shellCommand = shellCommand.split(/\s+/);
return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()})
@ -85,7 +94,7 @@ Adb.shell = function (target, shellCommand) {
};
Adb.start = function (target, activityName) {
events.emit('verbose', 'Starting application "' + activityName + '" on ' + target + '...');
events.emit('verbose', 'Starting application "' + activityName + '" on target ' + target + '...');
return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName)
.catch(function (output) {
return Q.reject(new CordovaError('Failed to start application "' +

@ -28,7 +28,7 @@ function AndroidManifest(path) {
this.path = path;
this.doc = xml.parseElementtreeSync(path);
if (this.doc.getroot().tag !== 'manifest') {
throw new Error(path + ' has incorrect root node name (expected "manifest")');
throw new Error('AndroidManifest at ' + path + ' has incorrect root node name (expected "manifest")');
}
}

@ -21,6 +21,7 @@ var fs = require('fs');
var path = require('path');
var properties_parser = require('properties-parser');
var AndroidManifest = require('./AndroidManifest');
var pluginHandlers = require('./pluginHandlers');
var projectFileCache = {};
@ -180,5 +181,13 @@ AndroidProject.prototype._getPropertiesFile = function (filename) {
return this._propertiesEditors[filename];
};
AndroidProject.prototype.getInstaller = function (type) {
return pluginHandlers.getInstaller(type);
};
AndroidProject.prototype.getUninstaller = function (type) {
return pluginHandlers.getUninstaller(type);
};
module.exports = AndroidProject;

@ -1,75 +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.
*/
var loggerInstance;
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var CordovaError = require('cordova-common').CordovaError;
/**
* @class ConsoleLogger
* @extends EventEmitter
*
* Implementing basic logging for platform. Inherits regular NodeJS
* EventEmitter. All events, emitted on this class instance are immediately
* logged to console.
*
* Also attaches handler to process' uncaught exceptions, so these exceptions
* logged to console similar to regular error events.
*/
function ConsoleLogger() {
EventEmitter.call(this);
var isVerbose = process.argv.indexOf('-d') >= 0 || process.argv.indexOf('--verbose') >= 0;
// For CordovaError print only the message without stack trace unless we
// are in a verbose mode.
process.on('uncaughtException', function(err){
if ((err instanceof CordovaError) && isVerbose) {
console.error(err.stack);
} else {
console.error(err.message);
}
process.exit(1);
});
this.on('results', console.log);
this.on('verbose', function () {
if (isVerbose)
console.log.apply(console, arguments);
});
this.on('info', console.log);
this.on('log', console.log);
this.on('warn', console.warn);
}
util.inherits(ConsoleLogger, EventEmitter);
/**
* Returns already instantiated/newly created instance of ConsoleLogger class.
* This method should be used instead of creating ConsoleLogger directly,
* otherwise we'll get multiple handlers attached to process'
* uncaughtException
*
* @return {ConsoleLogger} New or already created instance of ConsoleLogger
*/
ConsoleLogger.get = function () {
loggerInstance = loggerInstance || new ConsoleLogger();
return loggerInstance;
};
module.exports = ConsoleLogger;

@ -39,7 +39,7 @@ function parseOpts(options, resolvedTarget, projectRoot) {
prepenv: Boolean,
versionCode: String,
minSdkVersion: String,
gradleArg: String,
gradleArg: [String, Array],
keystore: path,
alias: String,
storePassword: String,
@ -66,8 +66,9 @@ function parseOpts(options, resolvedTarget, projectRoot) {
if (options.argv.minSdkVersion)
ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion);
if (options.argv.gradleArg)
ret.extraArgs.push(options.argv.gradleArg);
if (options.argv.gradleArg) {
ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg);
}
var packageArgs = {};
@ -89,8 +90,7 @@ function parseOpts(options, resolvedTarget, projectRoot) {
}
events.emit('log', 'Reading build config file: '+ path.resolve(buildConfig));
var buildjson = fs.readFileSync(buildConfig, 'utf8');
//var config = JSON.parse(fs.readFileSync(buildConfig, 'utf8'));
var config = JSON.parse(buildjson);
var config = JSON.parse(buildjson.replace(/^\ufeff/, '')); // Remove BOM
if (config.android && config.android[ret.buildType]) {
var androidInfo = config.android[ret.buildType];
if(androidInfo.keystore && !packageArgs.keystore) {
@ -149,17 +149,16 @@ module.exports.runClean = function(options) {
module.exports.run = function(options, optResolvedTarget) {
var opts = parseOpts(options, optResolvedTarget, this.root);
var builder = builders.getBuilder(opts.buildMethod);
var self = this;
return builder.prepEnv(opts)
.then(function() {
if (opts.prepEnv) {
self.events.emit('verbose', 'Build file successfully prepared.');
events.emit('verbose', 'Build file successfully prepared.');
return;
}
return builder.build(opts)
.then(function() {
var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
self.events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
return {
apkPaths: apkPaths,
buildType: opts.buildType,
@ -189,18 +188,18 @@ module.exports.detectArchitecture = function(target) {
// adb kill-server doesn't seem to do the trick.
// Could probably find a x-platform version of killall, but I'm not actually
// sure that this scenario even happens on non-OSX machines.
events.emit('verbose', 'adb timed out while detecting device/emulator architecture. Killing adb and trying again.');
return spawn('killall', ['adb'])
.then(function() {
events.emit('verbose', 'adb seems hung. retrying.');
return helper()
.then(null, function() {
// The double kill is sadly often necessary, at least on mac.
events.emit('warn', 'Now device not found... restarting adb again.');
events.emit('warn', 'adb timed out a second time while detecting device/emulator architecture. Killing adb and trying again.');
return spawn('killall', ['adb'])
.then(function() {
return helper()
.then(null, function() {
return Q.reject(new CordovaError('USB is flakey. Try unplugging & replugging the device.'));
return Q.reject(new CordovaError('adb timed out a third time while detecting device/emulator architecture. Try unplugging & replugging the device.'));
});
});
});

@ -79,7 +79,7 @@ AntBuilder.prototype.prepEnv = function(opts) {
writeBuildXml(path.join(self.root, subProjects[i]));
}
if (propertiesObj.systemLibs.length > 0) {
throw new CordovaError('Project contains at least one plugin that requires a system library. This is not supported with ANT. Please build using gradle.');
throw new CordovaError('Project contains at least one plugin that requires a system library. This is not supported with ANT. Use gradle instead.');
}
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
@ -107,7 +107,22 @@ AntBuilder.prototype.build = function(opts) {
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
return check_reqs.check_ant()
.then(function() {
return spawn('ant', args, {stdio: 'inherit'});
return spawn('ant', args, {stdio: 'pipe'});
}).progress(function (stdio){
if (stdio.stderr) {
process.stderr.write(stdio.stderr);
} else {
process.stdout.write(stdio.stdout);
}
}).catch(function (error) {
if (error.toString().indexOf('Unable to resolve project target') >= 0) {
return check_reqs.check_android_target(error).then(function() {
// If due to some odd reason - check_android_target succeeds
// we should still fail here.
return Q.reject(error);
});
}
return Q.reject(error);
});
};

@ -93,6 +93,14 @@ GenericBuilder.prototype.extractRealProjectNameFromManifest = function () {
module.exports = GenericBuilder;
function apkSorter(fileA, fileB) {
// De-prioritize unsigned builds
var unsignedRE = /-unsigned/;
if (unsignedRE.exec(fileA)) {
return 1;
} else if (unsignedRE.exec(fileB)) {
return -1;
}
var timeDiff = fs.statSync(fileA).mtime - fs.statSync(fileB).mtime;
return timeDiff === 0 ? fileA.length - fileB.length : timeDiff;
}
@ -128,7 +136,8 @@ function findOutputApksHelper(dir, build_type, arch) {
return !!/-x86|-arm/.exec(path.basename(p)) == archSpecific;
/*jshint +W018 */
});
if (archSpecific && ret.length > 1) {
if (archSpecific && ret.length > 1 && arch) {
ret = ret.filter(function(p) {
return path.basename(p).indexOf('-' + arch) != -1;
});

@ -22,7 +22,6 @@ var fs = require('fs');
var util = require('util');
var path = require('path');
var shell = require('shelljs');
var child_process = require('child_process');
var spawn = require('cordova-common').superspawn.spawn;
var CordovaError = require('cordova-common').CordovaError;
var check_reqs = require('../check_reqs');
@ -162,7 +161,7 @@ GradleBuilder.prototype.prepEnv = function(opts) {
// For some reason, using ^ and $ don't work. This does the job, though.
var distributionUrlRegex = /distributionUrl.*zip/;
/*jshint -W069 */
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'http\\://services.gradle.org/distributions/gradle-2.2.1-all.zip';
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'http\\://services.gradle.org/distributions/gradle-2.13-all.zip';
/*jshint +W069 */
var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
shell.chmod('u+w', gradleWrapperPropertiesPath);
@ -185,7 +184,35 @@ GradleBuilder.prototype.prepEnv = function(opts) {
GradleBuilder.prototype.build = function(opts) {
var wrapper = path.join(this.root, 'gradlew');
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
return spawnAndSuppressJavaOptions(wrapper, args);
return spawn(wrapper, args, {stdio: 'pipe'})
.progress(function (stdio){
if (stdio.stderr) {
/*
* Workaround for the issue with Java printing some unwanted information to
* stderr instead of stdout.
* This function suppresses 'Picked up _JAVA_OPTIONS' message from being
* printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
* explanation.
*/
var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
if (suppressThisLine) {
return;
}
process.stderr.write(stdio.stderr);
} else {
process.stdout.write(stdio.stdout);
}
}).catch(function (error) {
if (error.toString().indexOf('failed to find target with hash string') >= 0) {
return check_reqs.check_android_target(error).then(function() {
// If due to some odd reason - check_android_target succeeds
// we should still fail here.
return Q.reject(error);
});
}
return Q.reject(error);
});
};
GradleBuilder.prototype.clean = function(opts) {
@ -212,64 +239,3 @@ module.exports = GradleBuilder;
function isAutoGenerated(file) {
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
}
/**
* A special superspawn-like implementation, required to workaround the issue
* with Java printing some unwanted information to stderr instead of stdout.
* This function suppresses 'Picked up _JAVA_OPTIONS' message from being
* printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
* explanation.
*
* This function needed because superspawn does not provide a way to get and
* manage spawned process output streams. There is a CB-10052 which describes
* an improvements for superspawn, needed to get rid of this.
* TODO: Once this improvement added to cordova-common, we could remove this functionality.
*
* @param {String} cmd A command to spawn
* @param {String[]} args Command arguments. Note that on Windows arguments
* will be concatenated into string and passed to 'cmd.exe' along with '/s'
* and '/c' switches for proper space-in-path handling
*
* @return {Promise} A promise, rejected with error message if
* underlying command exits with nonzero exit code, fulfilled otherwise
*/
function spawnAndSuppressJavaOptions(cmd, args) {
var opts = { stdio: 'pipe' };
if (process.platform === 'win32') {
// Work around spawn not being able to find .bat files.
var joinedArgs = [cmd]
.concat(args)
.map(function(a){
// Add quotes to arguments which contains whitespaces
if (/^[^"].* .*[^"]/.test(a)) return '"' + a + '"';
return a;
}).join(' ');
args = ['/s', '/c'].concat('"' + joinedArgs + '"');
cmd = 'cmd';
opts.windowsVerbatimArguments = true;
}
return Q.Promise(function (resolve, reject) {
var proc = child_process.spawn(cmd, args, opts);
proc.stdout.on('data', process.stdout.write.bind(process.stdout));
proc.stderr.on('data', function (data) {
var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(data.toString());
if (suppressThisLine) {
return;
}
process.stderr.write(data);
});
proc.on('exit', function(code) {
if (code) {
reject('Error code ' + code + ' for command: ' + cmd + ' with args: ' + args);
} else {
resolve();
}
});
});
}

@ -142,22 +142,20 @@ module.exports.check_java = function() {
}
}
}).then(function() {
var msg =
'Failed to run "java -version", make sure that you have a JDK installed.\n' +
'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n';
if (process.env['JAVA_HOME']) {
msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\n';
}
return tryCommand('java -version', msg)
.then(function() {
var msg =
'Failed to run "javac -version", make sure that you have a JDK installed.\n' +
'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n';
if (process.env['JAVA_HOME']) {
msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\n';
}
// We use tryCommand with catchStderr = true, because
// javac writes version info to stderr instead of stdout
return tryCommand('javac -version', msg, true);
}).then(function (output) {
var match = /javac ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
return match && match[1];
return tryCommand('javac -version', msg, true)
.then(function (output) {
var match = /javac ((?:\d+\.)+(?:\d+))/i.exec(output);
return match && match[1];
});
});
});
};
// Returns a promise.
@ -238,13 +236,13 @@ module.exports.getAbsoluteAndroidCmd = function () {
return cmd.replace(/(\s)/g, '\\$1');
};
module.exports.check_android_target = function(valid_target) {
module.exports.check_android_target = function(originalError) {
// valid_target can look like:
// android-19
// android-L
// Google Inc.:Google APIs:20
// Google Inc.:Glass Development Kit Preview:20
if (!valid_target) valid_target = module.exports.get_target();
var valid_target = module.exports.get_target();
var msg = 'Android SDK not found. Make sure that it is installed. If it is not at the default location, set the ANDROID_HOME environment variable.';
return tryCommand('android list targets --compact', msg)
.then(function(output) {
@ -254,18 +252,22 @@ module.exports.check_android_target = function(valid_target) {
}
var androidCmd = module.exports.getAbsoluteAndroidCmd();
throw new CordovaError('Please install Android target: "' + valid_target + '".\n\n' +
var msg = 'Please install Android target: "' + valid_target + '".\n\n' +
'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
'You will require:\n' +
'1. "SDK Platform" for ' + valid_target + '\n' +
'2. "Android SDK Platform-tools (latest)\n' +
'3. "Android SDK Build-tools" (latest)');
'3. "Android SDK Build-tools" (latest)';
if (originalError) {
msg = originalError + '\n' + msg;
}
throw new CordovaError(msg);
});
};
// Returns a promise.
module.exports.run = function() {
return Q.all([this.check_java(), this.check_android().then(this.check_android_target)])
return Q.all([this.check_java(), this.check_android()])
.then(function() {
console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
console.log('JAVA_HOME=' + process.env['JAVA_HOME']);

@ -89,6 +89,7 @@ module.exports.install = function(target, buildResults) {
var pkgName = manifest.getPackageId();
var launchName = pkgName + '/.' + manifest.getActivity().getName();
events.emit('log', 'Using apk: ' + apk_path);
events.emit('log', 'Package name: ' + pkgName);
return Adb.install(resolvedTarget.target, apk_path, {replace: true})
.catch(function (error) {

@ -62,13 +62,18 @@ module.exports.list_images = function() {
var img_obj = {};
if (response[i].match(/Name:\s/)) {
img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
if (response[i + 1].match(/Device:\s/)) {
i++;
img_obj['device'] = response[i].split('Device: ')[1].replace('\r', '');
}
if (response[i + 1].match(/Path:\s/)) {
i++;
img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
}
if (response[i + 1].match(/\(API\slevel\s/)) {
if (response[i + 1].match(/\(API\slevel\s/) || (response[i + 2] && response[i + 2].match(/\(API\slevel\s/))) {
i++;
img_obj['target'] = response[i].replace('\r', '');
var secondLine = response[i + 1].match(/\(API\slevel\s/) ? response[i + 1] : '';
img_obj['target'] = (response[i] + secondLine).split('Target: ')[1].replace('\r', '');
}
if (response[i + 1].match(/ABI:\s/)) {
i++;
@ -142,6 +147,25 @@ module.exports.list_targets = function() {
});
};
/*
* Gets unused port for android emulator, between 5554 and 5584
* Returns a promise.
*/
module.exports.get_available_port = function () {
var self = this;
return self.list_started()
.then(function (emulators) {
for (var p = 5584; p >= 5554; p-=2) {
if (emulators.indexOf('emulator-' + p) === -1) {
events.emit('verbose', 'Found available port: ' + p);
return p;
}
}
throw new CordovaError('Could not find an available avd port');
});
};
/*
* Starts an emulator with the given ID,
* and returns the started ID of that emulator.
@ -173,23 +197,24 @@ module.exports.start = function(emulator_ID, boot_timeout) {
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
});
}).then(function(emulatorId) {
var uuid = 'cordova_emulator_' + new Date().getTime();
var uuidProp = 'emu.uuid=' + uuid;
var args = ['-avd', emulatorId, '-prop', uuidProp];
// Don't wait for it to finish, since the emulator will probably keep running for a long time.
child_process
.spawn('emulator', args, { stdio: 'inherit', detached: true })
.unref();
// wait for emulator to start
events.emit('log', 'Waiting for emulator...');
return self.wait_for_emulator(uuid);
return self.get_available_port()
.then(function (port) {
var args = ['-avd', emulatorId, '-port', port];
// Don't wait for it to finish, since the emulator will probably keep running for a long time.
child_process
.spawn('emulator', args, { stdio: 'inherit', detached: true })
.unref();
// wait for emulator to start
events.emit('log', 'Waiting for emulator to start...');
return self.wait_for_emulator(port);
});
}).then(function(emulatorId) {
if (!emulatorId)
return Q.reject(new CordovaError('Failed to start emulator'));
//wait for emulator to boot up
process.stdout.write('Booting up emulator (this may take a while)...');
process.stdout.write('Waiting for emulator to boot (this may take a while)...');
return self.wait_for_boot(emulatorId, boot_timeout)
.then(function(success) {
if (success) {
@ -209,29 +234,29 @@ module.exports.start = function(emulator_ID, boot_timeout) {
};
/*
* Waits for an emulator with given uuid to apear on the started-emulator list.
* Returns a promise with this emulator's ID.
* Waits for an emulator to boot on a given port.
* Returns this emulator's ID in a promise.
*/
module.exports.wait_for_emulator = function(uuid) {
module.exports.wait_for_emulator = function(port) {
var self = this;
return self.list_started()
.then(function(new_started) {
var emulator_id = null;
var promises = [];
new_started.forEach(function (emulator) {
promises.push(
Adb.shell(emulator, 'getprop emu.uuid')
.then(function (output) {
if (output.indexOf(uuid) >= 0) {
emulator_id = emulator;
}
})
);
});
return Q.all(promises).then(function () {
return emulator_id || self.wait_for_emulator(uuid);
return Q().then(function() {
var emulator_id = 'emulator-' + port;
return Adb.shell(emulator_id, 'getprop dev.bootcomplete')
.then(function (output) {
if (output.indexOf('1') >= 0) {
return emulator_id;
}
return self.wait_for_emulator(port);
}, function (error) {
if (error && error.message &&
(error.message.indexOf('not found') > -1) ||
error.message.indexOf('device offline') > -1) {
// emulator not yet started, continue waiting
return self.wait_for_emulator(port);
} else {
// something unexpected has happened
throw error;
}
});
});
};
@ -267,7 +292,7 @@ module.exports.wait_for_boot = function(emulator_id, time_remaining) {
* Returns a promise.
*/
module.exports.create_image = function(name, target) {
console.log('Creating avd named ' + name);
console.log('Creating new avd named ' + name);
if (target) {
return spawn('android', ['create', 'avd', '--name', name, '--target', target])
.then(null, function(error) {
@ -281,7 +306,7 @@ module.exports.create_image = function(name, target) {
.then(function() {
// TODO: This seems like another error case, even though it always happens.
console.error('ERROR : Unable to create an avd emulator, no targets found.');
console.error('Please insure you have targets available by running the "android" command');
console.error('Ensure you have targets available by running the "android" command');
return Q.reject();
}, function(error) {
console.error('ERROR : Failed to create emulator image : ');
@ -294,7 +319,7 @@ module.exports.resolveTarget = function(target) {
return this.list_started()
.then(function(emulator_list) {
if (emulator_list.length < 1) {
return Q.reject('No started emulators found, please start an emultor before deploying your project.');
return Q.reject('No running Android emulators found, please start an emulator before deploying your project.');
}
// default emulator
@ -349,6 +374,7 @@ module.exports.install = function(givenTarget, buildResults) {
};
events.emit('log', 'Using apk: ' + apk_path);
events.emit('log', 'Package name: ' + pkgName);
events.emit('verbose', 'Installing app on emulator...');
// A special function to call adb install in specific environment w/ specific options.
@ -363,8 +389,17 @@ module.exports.install = function(givenTarget, buildResults) {
if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr));
// adb does not return an error code even if installation fails. Instead it puts a specific
// message to stdout, so we have to use RegExp matching to detect installation failure.
else if (/Failure/.test(stdout)) reject(new CordovaError('Failed to install apk to emulator: ' + stdout));
else resolve(stdout);
else if (/Failure/.test(stdout)) {
if (stdout.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {
stdout += 'Sign the build using \'-- --keystore\' or \'--buildConfig\'' +
' or sign and deploy the unsigned apk manually using Android tools.';
} else if (stdout.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {
stdout += 'You\'re trying to install apk with a lower versionCode that is already installed.' +
'\nEither uninstall an app or increment the versionCode.';
}
reject(new CordovaError('Failed to install apk to emulator: ' + stdout));
} else resolve(stdout);
});
});
}
@ -377,8 +412,8 @@ module.exports.install = function(givenTarget, buildResults) {
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))
throw error;
events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' +
'installed app already signed with different key');
events.emit('warn', 'Uninstalling app from device and reinstalling it because the ' +
'currently installed app was signed with different key');
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
// or the app doesn't installed at all, so no error catching needed.

Some files were not shown because too many files have changed in this diff Show More