Fix Conflicts:
.gitignore index.html js/controllers/backup.js js/controllers/sidebar.js
|
@ -51,6 +51,14 @@ version.js
|
|||
|
||||
android/package
|
||||
android/*.apk
|
||||
android/*.keystore
|
||||
|
||||
mobile/*.keystore
|
||||
mobile/assets/www
|
||||
mobile/bin/*
|
||||
mobile/gen/*
|
||||
mobile/cordova/*
|
||||
mobile/CordovaLib/*
|
||||
|
||||
coverage/
|
||||
|
||||
|
|
26
README.md
|
@ -106,6 +106,32 @@ One solution is to use Copay with a Python version manager for 2.6.
|
|||
|
||||
# Development
|
||||
|
||||
## Android APK
|
||||
|
||||
System Requirements
|
||||
|
||||
* Download [Android SDK](http://developer.android.com/sdk/index.html)
|
||||
* Download and install [Crosswalk 8](https://crosswalk-project.org/#documentation/getting_started) (Use Linux setup for OSX)
|
||||
|
||||
Add to your ~/.bash_profile or ~/.bashrc
|
||||
|
||||
```
|
||||
export CROSSWALK="<path to Crosswalk directory>"
|
||||
```
|
||||
|
||||
To build the APK run the script:
|
||||
|
||||
```
|
||||
sh android/build.sh [-d]
|
||||
```
|
||||
- The -d flag will package the apk in debug mode, allowing [remote debugging chrome](https://developer.chrome.com/devtools/docs/remote-debugging)
|
||||
- The APK file is in **android/Copay_VERSION_arm.apk**
|
||||
|
||||
To install the APK in your device run:
|
||||
|
||||
```
|
||||
adb install -r Copay_VERSION_arm.apk
|
||||
```
|
||||
|
||||
## Google Chrome Extension
|
||||
|
||||
|
|
27
TODO.md
|
@ -30,33 +30,6 @@ It was developed to be run on OSX. The outputs are copied to the dist directory
|
|||
DMG is created with hdiutil
|
||||
EXE is created with makensis (brew install makensis)
|
||||
|
||||
## Android APK
|
||||
|
||||
System Requirements
|
||||
|
||||
* Download [Android SDK](http://developer.android.com/sdk/index.html)
|
||||
* Download and install [Crosswalk](https://crosswalk-project.org/#documentation/getting_started) (Use Linux setup for OSX)
|
||||
|
||||
Add to your ~/.bash_profile or ~/.bashrc
|
||||
|
||||
```
|
||||
export CROSSWALK="<path to Crosswalk directory>"
|
||||
```
|
||||
|
||||
To build the APK run the script:
|
||||
|
||||
```
|
||||
sh android/build.sh [-d]
|
||||
```
|
||||
- The -d flag will package the apk in debug mode, allowing [remote debugging chrome](https://developer.chrome.com/devtools/docs/remote-debugging)
|
||||
- The APK file is in **android/Copay_VERSION_arm.apk**
|
||||
|
||||
To install the APK in your device run:
|
||||
|
||||
```
|
||||
adb install -r Copay_VERSION_arm.apk
|
||||
```
|
||||
|
||||
|
||||
# Development
|
||||
|
||||
|
|
|
@ -26,6 +26,16 @@ then
|
|||
DEBUG="--enable-remote-debugging"
|
||||
fi
|
||||
|
||||
if [[ $# -eq 1 && ! $1 = "-d" ]]
|
||||
then
|
||||
if [ ! -f $BUILDDIR/copay.keystore ]
|
||||
then
|
||||
echo "${OpenColor}${Red}* Can't build production app without a keystore${CloseColor}"
|
||||
exit 1
|
||||
fi
|
||||
PRODUCTION="--keystore-path=$BUILDDIR/copay.keystore --keystore-alias=copay_play --keystore-passcode=$1"
|
||||
fi
|
||||
|
||||
# Move to the build directory
|
||||
cd $BUILDDIR
|
||||
|
||||
|
@ -48,13 +58,13 @@ checkOK
|
|||
echo "${OpenColor}${Green}* Copying all app files...${CloseColor}"
|
||||
sed "s/APP_VERSION/$VERSION/g" manifest.json > $APPDIR/manifest.json
|
||||
cd $BUILDDIR/..
|
||||
cp -af {css,font,img,js,lib,sound,config.js,version.js,index.html,./android/icon.png} $APPDIR
|
||||
cp -af {css,font,img,js,lib,sound,config.js,version.js,index.html,./android/icon.png,./android/logo.png} $APPDIR
|
||||
checkOK
|
||||
|
||||
# Building the APK
|
||||
echo "${OpenColor}${Green}* Building APK file...${CloseColor}"
|
||||
cd $CROSSWALK
|
||||
python make_apk.py --manifest=$APPDIR/manifest.json --target-dir=$BUILDDIR --arch=arm $DEBUG
|
||||
python make_apk.py --manifest=$APPDIR/manifest.json --package=com.bitpay.copay --arch=arm --target-dir=$BUILDDIR $DEBUG $PRODUCTION
|
||||
checkOK
|
||||
cd $BUILDDIR
|
||||
|
||||
|
|
BIN
android/icon.png
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 7.4 KiB |
|
@ -1,12 +1,21 @@
|
|||
{
|
||||
"name": "Copay",
|
||||
"version": "APP_VERSION",
|
||||
"app": {
|
||||
"launch":{
|
||||
"local_path": "index.html"
|
||||
"start_url": "index.html",
|
||||
"permissions": [
|
||||
"Vibration"
|
||||
],
|
||||
"xwalk_launch_screen": {
|
||||
"ready_when": "complete",
|
||||
"default": {
|
||||
"background_color": "#2C3E50",
|
||||
"image": "logo.png"
|
||||
}
|
||||
},
|
||||
"icons": {
|
||||
"128": "icon.png"
|
||||
}
|
||||
},
|
||||
"xwalk_hosts": [
|
||||
"https://*"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"sjcl": "1.0.0",
|
||||
"file-saver": "*",
|
||||
"qrcode-decoder-js": "*",
|
||||
"bitcore": "0.1.25",
|
||||
"bitcore": "0.1.34",
|
||||
"angular-moment": "~0.7.1",
|
||||
"socket.io-client": ">=1.0.0",
|
||||
"mousetrap": "1.4.6"
|
||||
|
|
After Width: | Height: | Size: 4.1 KiB |
|
@ -33,6 +33,13 @@ var copayApp = window.copayApp = angular.module('copayApp', [
|
|||
'copayApp.directives',
|
||||
]);
|
||||
|
||||
copayApp.config(function($sceDelegateProvider) {
|
||||
$sceDelegateProvider.resourceUrlWhitelist([
|
||||
'self',
|
||||
'mailto:**'
|
||||
]);
|
||||
});
|
||||
|
||||
angular.module('copayApp.filters', []);
|
||||
angular.module('copayApp.services', []);
|
||||
angular.module('copayApp.controllers', []);
|
||||
|
|
|
@ -17,9 +17,9 @@ angular.module('copayApp.controllers').controller('ImportController',
|
|||
updateStatus('Importing wallet - Setting things up...');
|
||||
var w, errMsg;
|
||||
|
||||
// try to import encrypted wallet with passphrase
|
||||
try {
|
||||
w = walletFactory.import(encryptedObj, passphrase);
|
||||
|
||||
} catch (e) {
|
||||
errMsg = e.message;
|
||||
}
|
||||
|
@ -31,12 +31,14 @@ angular.module('copayApp.controllers').controller('ImportController',
|
|||
return;
|
||||
}
|
||||
|
||||
// if wallet was never used, we're done
|
||||
if (!w.isReady()) {
|
||||
$rootScope.wallet = w;
|
||||
controllerUtils.startNetwork($rootScope.wallet, $scope);
|
||||
return;
|
||||
}
|
||||
|
||||
// if it was used, we need to scan for indices
|
||||
w.updateIndexes(function(err) {
|
||||
updateStatus('Importing wallet - We are almost there...');
|
||||
if (err) {
|
||||
|
|
|
@ -32,6 +32,7 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
|
||||
// Detect protocol
|
||||
$scope.isHttp = ($window.location.protocol.indexOf('http') === 0);
|
||||
$scope.isCordova = typeof(window.cordova) != 'undefined';
|
||||
|
||||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
||||
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
||||
|
@ -72,8 +73,8 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
});
|
||||
|
||||
// reset fields
|
||||
$scope.address = $scope.amount = $scope.comment = null;
|
||||
form.address.$pristine = form.amount.$pristine = form.comment.$pristine = true;
|
||||
$scope.address = $scope.amount = $scope.commentText = null;
|
||||
form.address.$pristine = form.amount.$pristine = true;
|
||||
};
|
||||
|
||||
// QR code Scanner
|
||||
|
@ -194,6 +195,25 @@ angular.module('copayApp.controllers').controller('SendController',
|
|||
}, 500);
|
||||
};
|
||||
|
||||
$scope.scannerIntent = function() {
|
||||
cordova.plugins.barcodeScanner.scan(
|
||||
function onSuccess(result) {
|
||||
if (result.cancelled) return;
|
||||
|
||||
var bip21 = copay.Structure.parseBitcoinURI(result.text);
|
||||
$scope.address = bip21.address;
|
||||
|
||||
if (bip21.amount) {
|
||||
$scope.amount = bip21.amount * bitcore.util.COIN * satToUnit;
|
||||
}
|
||||
|
||||
$rootScope.$digest();
|
||||
},
|
||||
function onError(error) {
|
||||
alert('Scanning error');
|
||||
});
|
||||
}
|
||||
|
||||
$scope.toggleAddressBookEntry = function(key) {
|
||||
var w = $rootScope.wallet;
|
||||
w.toggleAddressBookEntry(key);
|
||||
|
|
|
@ -18,7 +18,7 @@ angular.module('copayApp.controllers').controller('SidebarController',
|
|||
'icon': 'fi-arrow-right',
|
||||
'link': 'send'
|
||||
}, {
|
||||
'title': 'More...',
|
||||
'title': 'More',
|
||||
'icon': 'fi-download',
|
||||
'link': 'backup'
|
||||
}];
|
||||
|
|
|
@ -156,63 +156,55 @@ angular.module('copayApp.directives')
|
|||
restrict: 'EACM',
|
||||
require: 'ngModel',
|
||||
link: function(scope, element, attrs) {
|
||||
var strength = {
|
||||
messages: ['very weak', 'weak', 'weak', 'medium', 'strong'],
|
||||
colors: ['#c0392b', '#e74c3c', '#d35400', '#f39c12', '#27ae60'],
|
||||
mesureStrength: function(p) {
|
||||
var force = 0;
|
||||
var regex = /[$-/:-?{-~!"^_`\[\]]/g;
|
||||
var lowerLetters = /[a-z]+/.test(p);
|
||||
var upperLetters = /[A-Z]+/.test(p);
|
||||
var numbers = /[0-9]+/.test(p);
|
||||
var symbols = regex.test(p);
|
||||
var flags = [lowerLetters, upperLetters, numbers, symbols];
|
||||
var passedMatches = flags.filter(function(el) {
|
||||
return !!el;
|
||||
}).length;
|
||||
|
||||
force = 2 * p.length + (p.length >= 10 ? 1 : 0);
|
||||
force += passedMatches * 10;
|
||||
var MIN_LENGTH = 8;
|
||||
var MESSAGES = ['Very Weak', 'Very Weak', 'Weak', 'Medium', 'Strong', 'Very Strong'];
|
||||
var COLOR = ['#dd514c', '#dd514c', '#faa732', '#faa732', '#5eb95e', '#5eb95e'];
|
||||
|
||||
// penality (short password)
|
||||
force = (p.length <= 6) ? Math.min(force, 10) : force;
|
||||
|
||||
// penality (poor variety of characters)
|
||||
force = (passedMatches == 1) ? Math.min(force, 10) : force;
|
||||
force = (passedMatches == 2) ? Math.min(force, 20) : force;
|
||||
force = (passedMatches == 3) ? Math.min(force, 40) : force;
|
||||
return force;
|
||||
},
|
||||
getColor: function(s) {
|
||||
var idx = 0;
|
||||
|
||||
if (s <= 10) {
|
||||
idx = 0;
|
||||
} else if (s <= 20) {
|
||||
idx = 1;
|
||||
} else if (s <= 30) {
|
||||
idx = 2;
|
||||
} else if (s <= 40) {
|
||||
idx = 3;
|
||||
function evaluateMeter(password) {
|
||||
var passwordStrength = 0;
|
||||
var text;
|
||||
if (password.length > 0) passwordStrength = 1;
|
||||
if (password.length >= MIN_LENGTH) {
|
||||
if ((password.match(/[a-z]/)) && (password.match(/[A-Z]/))) {
|
||||
passwordStrength++;
|
||||
} else {
|
||||
idx = 4;
|
||||
text = ', add mixed case';
|
||||
}
|
||||
if (password.match(/\d+/)) {
|
||||
passwordStrength++;
|
||||
} else {
|
||||
if (!text) text = ', add numerals';
|
||||
}
|
||||
if (password.match(/.[!,@,#,$,%,^,&,*,?,_,~,-,(,)]/)) {
|
||||
passwordStrength++;
|
||||
} else {
|
||||
if (!text) text = ', add punctuation';
|
||||
}
|
||||
if (password.length > 12) {
|
||||
passwordStrength++;
|
||||
} else {
|
||||
if (!text) text = ', add characters';
|
||||
}
|
||||
} else {
|
||||
text = ', that\'s short';
|
||||
}
|
||||
if (!text) text = '';
|
||||
|
||||
return {
|
||||
idx: idx + 1,
|
||||
col: this.colors[idx],
|
||||
message: this.messages[idx]
|
||||
};
|
||||
strength: passwordStrength,
|
||||
message: MESSAGES[passwordStrength] + text,
|
||||
color: COLOR[passwordStrength]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scope.$watch(attrs.ngModel, function(newValue, oldValue) {
|
||||
if (newValue && newValue !== '') {
|
||||
var c = strength.getColor(strength.mesureStrength(newValue));
|
||||
var info = evaluateMeter(newValue);
|
||||
element.css({
|
||||
'border-color': c.col
|
||||
'border-color': info.color
|
||||
});
|
||||
scope[attrs.checkStrength] = c.message;
|
||||
scope[attrs.checkStrength] = info.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -20,14 +20,18 @@ angular.module('copayApp.filters', [])
|
|||
.filter('removeEmpty', function() {
|
||||
return function(elements) {
|
||||
elements = elements || [];
|
||||
// Hide empty addresses from other copayers
|
||||
// Hide empty change addresses from other copayers
|
||||
return elements.filter(function(e) {
|
||||
return e.owned || e.balance > 0;
|
||||
return !e.isChange || e.balance > 0;
|
||||
});
|
||||
}
|
||||
})
|
||||
.filter('limitAddress', function() {
|
||||
return function(elements, showAll) {
|
||||
var elements = elements.sort(function(a, b) {
|
||||
return (+b.owned) - (+a.owned);
|
||||
});
|
||||
|
||||
if (elements.length <= 1 || showAll) {
|
||||
return elements;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
'use strict';
|
||||
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var Transaction = bitcore.Transaction;
|
||||
|
||||
function BuilderMockV0 (data) {
|
||||
this.vanilla = data;
|
||||
this.tx = new Transaction();
|
||||
this.tx.parse(new Buffer(data.tx, 'hex'));
|
||||
};
|
||||
|
||||
BuilderMockV0.prototype.build = function() {
|
||||
return this.tx;
|
||||
};
|
||||
|
||||
|
||||
BuilderMockV0.prototype.getSelectedUnspent = function() {
|
||||
return [];
|
||||
};
|
||||
|
||||
BuilderMockV0.prototype.toObj = function() {
|
||||
return this.vanilla;
|
||||
};
|
||||
|
||||
module.exports = BuilderMockV0;
|
|
@ -59,6 +59,8 @@ Structure.parseBitcoinURI = function(uri) {
|
|||
data = splitDots[1];
|
||||
var splitQuestion = data.split('?');
|
||||
ret.address = splitQuestion[0];
|
||||
|
||||
if (splitQuestion.length > 1) {
|
||||
var search = splitQuestion[1];
|
||||
data = JSON.parse('{"' + search.replace(/&/g, '","').replace(/=/g, '":"') + '"}',
|
||||
function(key, value) {
|
||||
|
@ -66,6 +68,7 @@ Structure.parseBitcoinURI = function(uri) {
|
|||
});
|
||||
ret.amount = parseFloat(data.amount);
|
||||
ret.message = data.message;
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
|
|
@ -5,9 +5,11 @@ var imports = require('soop').imports();
|
|||
var bitcore = require('bitcore');
|
||||
var util = bitcore.util;
|
||||
var Transaction = bitcore.Transaction;
|
||||
var Builder = bitcore.TransactionBuilder;
|
||||
var BuilderMockV0 = require('./BuilderMockV0');;
|
||||
var TransactionBuilder = bitcore.TransactionBuilder;
|
||||
var Script = bitcore.Script;
|
||||
var buffertools = bitcore.buffertools;
|
||||
var preconditions = require('preconditions').instance();
|
||||
|
||||
function TxProposal(opts) {
|
||||
this.creator = opts.creator;
|
||||
|
@ -23,8 +25,7 @@ function TxProposal(opts) {
|
|||
}
|
||||
|
||||
TxProposal.prototype.getID = function() {
|
||||
var ntxid = this.builder.build().getNormalizedHash().toString('hex');
|
||||
return ntxid;
|
||||
return this.builder.build().getNormalizedHash().toString('hex');
|
||||
};
|
||||
|
||||
TxProposal.prototype.toObj = function() {
|
||||
|
@ -40,13 +41,41 @@ TxProposal.prototype.setSent = function(sentTxid) {
|
|||
this.sentTs = Date.now();
|
||||
};
|
||||
|
||||
TxProposal.fromObj = function(o) {
|
||||
TxProposal.fromObj = function(o, forceOpts) {
|
||||
var t = new TxProposal(o);
|
||||
var b = new Builder.fromObj(o.builderObj);
|
||||
t.builder = b;
|
||||
|
||||
try {
|
||||
// force opts is requested.
|
||||
for (var k in forceOpts) {
|
||||
o.builderObj.opts[k] = forceOpts[k];
|
||||
}
|
||||
t.builder = TransactionBuilder.fromObj(o.builderObj);
|
||||
|
||||
} catch (e) {
|
||||
if (!o.version) {
|
||||
t.builder = new BuilderMockV0(o.builderObj);
|
||||
t.readonly = 1;
|
||||
};
|
||||
}
|
||||
|
||||
return t;
|
||||
};
|
||||
|
||||
|
||||
TxProposal.prototype.isValid = function() {
|
||||
if (this.builder.signhash && this.builder.signhash !== Transaction.SIGHASH_ALL) {
|
||||
return false;
|
||||
}
|
||||
var tx = this.builder.build();
|
||||
for (var i = 0; i < tx.ins.length; i++) {
|
||||
var hashType = tx.getHashType(i);
|
||||
if (hashType && hashType !== Transaction.SIGHASH_ALL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
TxProposal.getSentTs = function() {
|
||||
return this.sentTs;
|
||||
};
|
||||
|
@ -127,6 +156,17 @@ TxProposal.prototype.mergeMetadata = function(v1, author) {
|
|||
|
||||
};
|
||||
|
||||
//This should be on bitcore / Transaction
|
||||
TxProposal.prototype.countSignatures = function() {
|
||||
var tx = this.builder.build();
|
||||
|
||||
var ret = 0;
|
||||
for (var i in tx.ins) {
|
||||
ret += tx.countInputSignatures(i);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
module.exports = require('soop')(TxProposal);
|
||||
|
||||
|
||||
|
@ -138,15 +178,18 @@ function TxProposals(opts) {
|
|||
this.txps = {};
|
||||
}
|
||||
|
||||
TxProposals.fromObj = function(o) {
|
||||
TxProposals.fromObj = function(o, forceOpts) {
|
||||
var ret = new TxProposals({
|
||||
networkName: o.networkName,
|
||||
walletId: o.walletId,
|
||||
});
|
||||
|
||||
o.txps.forEach(function(o2) {
|
||||
var t = TxProposal.fromObj(o2);
|
||||
var id = t.builder.build().getNormalizedHash().toString('hex');
|
||||
var t = TxProposal.fromObj(o2, forceOpts);
|
||||
if (t.builder) {
|
||||
var id = t.getID();
|
||||
ret.txps[id] = t;
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
@ -198,7 +241,6 @@ TxProposals.prototype.merge = function(inTxp, author) {
|
|||
return ret;
|
||||
};
|
||||
|
||||
var preconditions = require('preconditions').instance();
|
||||
TxProposals.prototype.add = function(data) {
|
||||
preconditions.checkArgument(data.inputChainPaths);
|
||||
preconditions.checkArgument(data.signedBy);
|
||||
|
|
|
@ -35,8 +35,8 @@ function Wallet(opts) {
|
|||
self[k] = opts[k];
|
||||
});
|
||||
if (copayConfig.forceNetwork && this.getNetworkName() !== copayConfig.networkName)
|
||||
throw new Error('Network forced to '+copayConfig.networkName+
|
||||
' and tried to create a Wallet with network '+ this.getNetworkName());
|
||||
throw new Error('Network forced to ' + copayConfig.networkName +
|
||||
' and tried to create a Wallet with network ' + this.getNetworkName());
|
||||
|
||||
this.log('creating ' + opts.requiredCopayers + ' of ' + opts.totalCopayers + ' wallet');
|
||||
|
||||
|
@ -57,6 +57,14 @@ function Wallet(opts) {
|
|||
this.network.setHexNonces(opts.networkNonces);
|
||||
}
|
||||
|
||||
|
||||
Wallet.builderOpts = {
|
||||
lockTime: null,
|
||||
signhash: bitcore.Transaction.SIGNHASH_ALL,
|
||||
fee: null,
|
||||
feeSat: null,
|
||||
};
|
||||
|
||||
Wallet.parent = EventEmitter;
|
||||
Wallet.prototype.log = function() {
|
||||
if (!this.verbose) return;
|
||||
|
@ -121,11 +129,20 @@ Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) {
|
|||
};
|
||||
|
||||
|
||||
Wallet.prototype._handleTxProposal = function(senderId, data) {
|
||||
preconditions.checkArgument(senderId);
|
||||
this.log('RECV TXPROPOSAL:', data);
|
||||
|
||||
var inTxp = TxProposals.TxProposal.fromObj(data.txProposal);
|
||||
Wallet.prototype._handleTxProposal = function(senderId, data) {
|
||||
this.log('RECV TXPROPOSAL: ', data);
|
||||
|
||||
var inTxp = TxProposals.TxProposal.fromObj(data.txProposal, Wallet.builderOpts);
|
||||
var valid = inTxp.isValid();
|
||||
if (!valid) {
|
||||
var corruptEvent = {
|
||||
type: 'corrupt',
|
||||
cId: inTxp.creator
|
||||
};
|
||||
this.emit('txProposalEvent', corruptEvent);
|
||||
return;
|
||||
}
|
||||
var mergeInfo = this.txProposals.merge(inTxp, senderId);
|
||||
var added = this.addSeenToTxProposals();
|
||||
|
||||
|
@ -370,7 +387,7 @@ Wallet.fromObj = function(o, storage, network, blockchain) {
|
|||
opts.addressBook = o.addressBook;
|
||||
|
||||
opts.publicKeyRing = PublicKeyRing.fromObj(o.publicKeyRing);
|
||||
opts.txProposals = TxProposals.fromObj(o.txProposals);
|
||||
opts.txProposals = TxProposals.fromObj(o.txProposals, Wallet.builderOpts);
|
||||
opts.privateKey = PrivateKey.fromObj(o.privateKey);
|
||||
|
||||
opts.storage = storage;
|
||||
|
@ -489,8 +506,10 @@ Wallet.prototype.getTxProposals = function() {
|
|||
txp.finallyRejected = true;
|
||||
}
|
||||
|
||||
if (txp.readonly && !txp.finallyRejected && !txp.sentTs) {} else {
|
||||
ret.push(txp);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
@ -509,6 +528,7 @@ Wallet.prototype.reject = function(ntxid) {
|
|||
};
|
||||
|
||||
|
||||
|
||||
Wallet.prototype.sign = function(ntxid, cb) {
|
||||
preconditions.checkState(typeof this.getMyCopayerId() !== 'undefined');
|
||||
var self = this;
|
||||
|
@ -522,11 +542,11 @@ Wallet.prototype.sign = function(ntxid, cb) {
|
|||
var keys = self.privateKey.getForPaths(txp.inputChainPaths);
|
||||
|
||||
var b = txp.builder;
|
||||
var before = b.signaturesAdded;
|
||||
var before = txp.countSignatures();
|
||||
b.sign(keys);
|
||||
|
||||
var ret = false;
|
||||
if (b.signaturesAdded > before) {
|
||||
if (txp.countSignatures() > before) {
|
||||
txp.signedBy[myId] = Date.now();
|
||||
self.sendTxProposal(ntxid);
|
||||
self.store();
|
||||
|
@ -697,15 +717,9 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, comment, utxos
|
|||
var priv = this.privateKey;
|
||||
opts = opts || {};
|
||||
|
||||
var amountSat = bignum(amountSatStr);
|
||||
preconditions.checkArgument(new Address(toAddress).network().name === this.getNetworkName());
|
||||
if (!pkr.isComplete()) {
|
||||
throw new Error('publicKeyRing is not complete');
|
||||
}
|
||||
|
||||
if (comment && comment.length > 100) {
|
||||
throw new Error("comment can't be longer that 100 characters");
|
||||
}
|
||||
preconditions.checkState(pkr.isComplete());
|
||||
if (comment) preconditions.checkArgument(comment.length <= 100);
|
||||
|
||||
if (!opts.remainderOut) {
|
||||
opts.remainderOut = {
|
||||
|
@ -713,11 +727,15 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, comment, utxos
|
|||
};
|
||||
}
|
||||
|
||||
for (var k in Wallet.builderOpts){
|
||||
opts[k] = Wallet.builderOpts[k];
|
||||
}
|
||||
|
||||
var b = new Builder(opts)
|
||||
.setUnspent(utxos)
|
||||
.setOutputs([{
|
||||
address: toAddress,
|
||||
amountSat: amountSat
|
||||
amountSatStr: amountSatStr,
|
||||
}]);
|
||||
|
||||
var selectedUtxos = b.getSelectedUnspent();
|
||||
|
@ -735,7 +753,9 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, comment, utxos
|
|||
var now = Date.now();
|
||||
|
||||
var me = {};
|
||||
if (priv && b.signaturesAdded) me[myId] = now;
|
||||
|
||||
var tx = b.build();
|
||||
if (priv && tx.countInputSignatures(0)) me[myId] = now;
|
||||
|
||||
var meSeen = {};
|
||||
if (priv) meSeen[myId] = now;
|
||||
|
|
|
@ -28,6 +28,18 @@ BackupService.prototype.download = function(wallet) {
|
|||
wallet: ew
|
||||
});
|
||||
}
|
||||
|
||||
// throw an email intent if we are in the mobile version
|
||||
if (window.cordova) {
|
||||
var name = wallet.name ? wallet.name + ' ' : '';
|
||||
var partial = partial ? 'Partial ' : '';
|
||||
return window.plugin.email.open({
|
||||
subject: 'Copay - ' + name + 'Wallet ' + partial + 'Backup',
|
||||
body: 'Here is the encrypted backup of the wallet ' + wallet.id,
|
||||
attachments: ['base64:' + filename + '//' + btoa(ew)]
|
||||
});
|
||||
}
|
||||
|
||||
// otherwise lean on the browser implementation
|
||||
saveAs(blob, filename);
|
||||
};
|
||||
|
|
|
@ -149,15 +149,17 @@ angular.module('copayApp.services')
|
|||
}, 3000);
|
||||
});
|
||||
w.on('txProposalEvent', function(e) {
|
||||
var user = w.publicKeyRing.nicknameForCopayer(e.cId);
|
||||
switch (e.type) {
|
||||
case 'signed':
|
||||
var user = w.publicKeyRing.nicknameForCopayer(e.cId);
|
||||
notification.info('Transaction Update', 'A transaction was signed by ' + user);
|
||||
break;
|
||||
case 'rejected':
|
||||
var user = w.publicKeyRing.nicknameForCopayer(e.cId);
|
||||
notification.info('Transaction Update', 'A transaction was rejected by ' + user);
|
||||
break;
|
||||
case 'corrupt':
|
||||
notification.error('Transaction Error', 'Received corrupt transaction from '+user);
|
||||
break;
|
||||
}
|
||||
});
|
||||
w.on('addressBookUpdated', function(dontDigest) {
|
||||
|
|
|
@ -198,7 +198,12 @@ factory('notification', ['$timeout',
|
|||
$timeout(function removeFromQueueTimeout() {
|
||||
queue.splice(queue.indexOf(notification), 1);
|
||||
}, settings[type].duration);
|
||||
}
|
||||
|
||||
// Movile notification
|
||||
window.navigator.vibrate([200,100,200]);
|
||||
if (document.hidden && (type == 'info' || type == 'funds')) {
|
||||
new window.Notification(title, {body: content, icon:'img/notification.png'});
|
||||
}
|
||||
|
||||
this.save();
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<manifest android:hardwareAccelerated="true" android:versionCode="3" android:versionName="0.4.1" android:windowSoftInputMode="adjustPan" package="com.bitpay.copay" 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.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<application android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string/app_name">
|
||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/app_name" android:launchMode="singleTop" android:name="Copay" android:theme="@android:style/Theme.Black.NoTitleBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:clearTaskOnLaunch="true" android:configChanges="orientation|keyboardHidden" android:exported="false" android:name="com.google.zxing.client.android.CaptureActivity" android:screenOrientation="landscape" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:windowSoftInputMode="stateAlwaysHidden">
|
||||
<intent-filter>
|
||||
<action android:name="com.phonegap.plugins.barcodescanner.SCAN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:label="@string/share_name" 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="@string/share_name" 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>
|
||||
<provider android:authorities="com.bitpay.copay.plugin.emailcomposer.attachmentprovider" android:name="de.appplant.cordova.plugin.emailcomposer.AttachmentProvider" />
|
||||
</application>
|
||||
<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<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>
|
|
@ -0,0 +1,76 @@
|
|||
#! /bin/bash
|
||||
|
||||
# Description: This script compiles and copy the needed files to later package the application for Android
|
||||
|
||||
OpenColor="\033["
|
||||
Red="1;31m"
|
||||
Yellow="1;33m"
|
||||
Green="1;32m"
|
||||
CloseColor="\033[0m"
|
||||
|
||||
# Check function OK
|
||||
checkOK() {
|
||||
if [ $? != 0 ]; then
|
||||
echo "${OpenColor}${Red}* ERROR. Exiting...${CloseColor}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Configs
|
||||
BUILDDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
APPDIR="$BUILDDIR/assets/www"
|
||||
VERSION=`cut -d '"' -f2 $BUILDDIR/../version.js`
|
||||
RELEASE=false
|
||||
RUN=false
|
||||
|
||||
if [[ $1 = "--release" ]]
|
||||
then
|
||||
RELEASE=true
|
||||
fi
|
||||
|
||||
if [[ $1 = "-r" ]]
|
||||
then
|
||||
RUN=true
|
||||
fi
|
||||
|
||||
# Move to the build directory
|
||||
cd $BUILDDIR
|
||||
|
||||
[ -z "$CROSSWALK" ] && { echo "${OpenColor}${Red}* Need to set CROSSWALK environment variable${CloseColor}"; exit 1; }
|
||||
|
||||
# Create/Clean temp dir
|
||||
echo "${OpenColor}${Green}* Checking temp dir...${CloseColor}"
|
||||
if [ -d $APPDIR ]; then
|
||||
rm -rf $APPDIR
|
||||
fi
|
||||
|
||||
mkdir -p $APPDIR
|
||||
|
||||
# Re-compile copayBundle.js
|
||||
echo "${OpenColor}${Green}* Generating copay bundle...${CloseColor}"
|
||||
grunt --target=dev shell
|
||||
checkOK
|
||||
|
||||
# Copy all app files
|
||||
echo "${OpenColor}${Green}* Copying all app files...${CloseColor}"
|
||||
cd $BUILDDIR/..
|
||||
cp -af {css,font,img,js,lib,sound,config.js,version.js,$BUILDDIR/cordova.js,$BUILDDIR/cordova_plugins.js,$BUILDDIR/plugins} $APPDIR
|
||||
checkOK
|
||||
sed "s/<\!-- PLACEHOLDER: CORDOVA SRIPT -->/<script type='text\/javascript' charset='utf-8' src='cordova.js'><\/script>/g" index.html > $APPDIR/index.html
|
||||
checkOK
|
||||
|
||||
# Building the APK
|
||||
echo "${OpenColor}${Green}* Building APK file...${CloseColor}"
|
||||
cd $BUILDDIR
|
||||
if [[ $RUN == true ]]
|
||||
then
|
||||
./cordova/run
|
||||
elif [[ $RELEASE == true ]]
|
||||
then
|
||||
./cordova/build --release
|
||||
else
|
||||
./cordova/build
|
||||
fi
|
||||
checkOK
|
||||
|
||||
echo "${OpenColor}${Yellow}\nAwesome! We have a brand new APK, enjoy it!${CloseColor}"
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="Copay" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
This is the place to change some Ant specific build properties.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
For other overridable properties, look at the beginning of the rules
|
||||
files in the SDK, at tools/ant/build.xml
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- if sdk.dir was not set from one of the property file, then
|
||||
get it from the ANDROID_HOME env var.
|
||||
This must be done before we load project.properties since
|
||||
the proguard config can use sdk.dir -->
|
||||
<property environment="env" />
|
||||
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||
<isset property="env.ANDROID_HOME" />
|
||||
</condition>
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
This contains project specific properties such as project target, and library
|
||||
dependencies. Lower level build properties are stored in ant.properties
|
||||
(or in .classpath for Eclipse projects).
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Import per project custom build rules if present at the root of the project.
|
||||
This is the place to put custom intermediary targets such as:
|
||||
-pre-build
|
||||
-pre-compile
|
||||
-post-compile (This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||
-post-package
|
||||
-post-build
|
||||
-pre-clean
|
||||
-->
|
||||
<import file="custom_rules.xml" optional="true" />
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<import> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole content of build.xml
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, replacing the <import> task.
|
||||
- customize to your needs.
|
||||
|
||||
***********************
|
||||
****** IMPORTANT ******
|
||||
***********************
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: 1 -->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
</project>
|
|
@ -0,0 +1,33 @@
|
|||
cordova.define('cordova/plugin_list', function(require, exports, module) {
|
||||
module.exports = [
|
||||
{
|
||||
"file": "plugins/de.appplant.cordova.plugin.email-composer/www/email_composer.js",
|
||||
"id": "de.appplant.cordova.plugin.email-composer.EmailComposer",
|
||||
"clobbers": [
|
||||
"plugin.email"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "plugins/com.phonegap.plugins.barcodescanner/www/barcodescanner.js",
|
||||
"id": "com.phonegap.plugins.barcodescanner.BarcodeScanner",
|
||||
"clobbers": [
|
||||
"cordova.plugins.barcodeScanner"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": "plugins/org.apache.cordova.splashscreen/www/splashscreen.js",
|
||||
"id": "org.apache.cordova.splashscreen.SplashScreen",
|
||||
"clobbers": [
|
||||
"navigator.splashscreen"
|
||||
]
|
||||
}
|
||||
];
|
||||
module.exports.metadata =
|
||||
// TOP OF METADATA
|
||||
{
|
||||
"de.appplant.cordova.plugin.email-composer": "0.8.2dev",
|
||||
"com.phonegap.plugins.barcodescanner": "1.0.1",
|
||||
"org.apache.cordova.splashscreen": "0.3.0"
|
||||
}
|
||||
// BOTTOM OF METADATA
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must *NOT* be checked into Version Control Systems,
|
||||
# as it contains information specific to your local configuration.
|
||||
|
||||
# location of the SDK. This is only used by Ant
|
||||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
sdk.dir=/Users/yemeljardi/Documents/sdk
|
|
@ -0,0 +1,89 @@
|
|||
cordova.define("com.phonegap.plugins.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");
|
||||
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
BarcodeScanner.prototype.scan = function (successCallback, errorCallback) {
|
||||
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;
|
||||
}
|
||||
|
||||
exec(successCallback, errorCallback, 'BarcodeScanner', 'scan', []);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
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;
|
||||
|
||||
|
||||
});
|
|
@ -0,0 +1,108 @@
|
|||
cordova.define("de.appplant.cordova.plugin.email-composer.EmailComposer", function(require, exports, module) { /*
|
||||
Copyright 2013-2014 appPlant UG
|
||||
|
||||
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 EmailComposer = function () {
|
||||
|
||||
};
|
||||
|
||||
EmailComposer.prototype = {
|
||||
/**
|
||||
* Displays the email composer pre-filled with data.
|
||||
*
|
||||
* @param {Object} options
|
||||
* Different properties of the email like the body, subject
|
||||
* @param {Function} callback
|
||||
* A callback function to be called with the result
|
||||
* @param {Object?} scope
|
||||
* The scope of the callback
|
||||
*/
|
||||
open: function (options, callback, scope) {
|
||||
var callbackFn = this.createCallbackFn(callback, scope),
|
||||
options = options || {};
|
||||
|
||||
var defaults = {
|
||||
subject: null,
|
||||
body: null,
|
||||
to: null,
|
||||
cc: null,
|
||||
bcc: null,
|
||||
attachments: null,
|
||||
isHtml: true
|
||||
}
|
||||
|
||||
for (var key in defaults) {
|
||||
if (options[key] !== undefined) {
|
||||
defaults[key] = options[key];
|
||||
} else {
|
||||
console.log('EmailComposer plugin: unknown property "' + key + '"');
|
||||
}
|
||||
}
|
||||
|
||||
cordova.exec(callbackFn, null, 'EmailComposer', 'open', [options]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Alias für `open()`.
|
||||
*/
|
||||
openDraft: function () {
|
||||
this.open.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Verifies if sending emails is supported on the device.
|
||||
*
|
||||
* @param {Function} callback
|
||||
* A callback function to be called with the result
|
||||
* @param {Object} scope
|
||||
* The scope of the callback
|
||||
*/
|
||||
isServiceAvailable: function (callback, scope) {
|
||||
var callbackFn = this.createCallbackFn(callback, scope);
|
||||
|
||||
cordova.exec(callbackFn, null, 'EmailComposer', 'isServiceAvailable', []);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*
|
||||
* Creates a callback, which will be executed within a specific scope.
|
||||
*
|
||||
* @param {Function} callbackFn
|
||||
* The callback function
|
||||
* @param {Object} scope
|
||||
* The scope for the function
|
||||
*
|
||||
* @return {Function}
|
||||
* The new callback function
|
||||
*/
|
||||
createCallbackFn: function (callbackFn, scope) {
|
||||
return function () {
|
||||
if (typeof callbackFn == 'function') {
|
||||
callbackFn.apply(scope || this, arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var plugin = new EmailComposer();
|
||||
|
||||
module.exports = plugin;
|
||||
});
|
|
@ -0,0 +1,35 @@
|
|||
cordova.define("org.apache.cordova.splashscreen.SplashScreen", function(require, exports, module) { /*
|
||||
*
|
||||
* 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 exec = require('cordova/exec');
|
||||
|
||||
var splashscreen = {
|
||||
show:function() {
|
||||
exec(null, null, "SplashScreen", "show", []);
|
||||
},
|
||||
hide:function() {
|
||||
exec(null, null, "SplashScreen", "hide", []);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = splashscreen;
|
||||
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
# To enable ProGuard in your project, edit project.properties
|
||||
# to define the proguard.config property as described in that file.
|
||||
#
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
|
@ -0,0 +1,17 @@
|
|||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
android.library.reference.1=CordovaLib
|
||||
# Project target.
|
||||
target=android-19
|
||||
key.store=copay.keystore
|
||||
key.alias=copay_play
|
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:fillViewport="true"
|
||||
android:background="@color/encode_view"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView android:id="@+id/image_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:scaleType="center"/>
|
||||
|
||||
<ScrollView android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView android:id="@+id/contents_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/contents_text"
|
||||
android:paddingRight="8dip"
|
||||
android:paddingTop="8dip"
|
||||
android:paddingBottom="8dip"/>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,90 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dip">
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/msg_share_explanation"
|
||||
android:paddingBottom="12dip"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="12dip">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/share_via_barcode"
|
||||
android:paddingRight="24dip"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button android:id="@+id/share_app_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/button_share_app"/>
|
||||
|
||||
<Button android:id="@+id/share_contact_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/button_share_contact"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button android:id="@+id/share_bookmark_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/button_share_bookmark"/>
|
||||
|
||||
<Button android:id="@+id/share_clipboard_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/button_share_clipboard"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<EditText android:id="@+id/share_text_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/msg_share_text"
|
||||
android:singleLine="true"
|
||||
android:selectAllOnFocus="true"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,219 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<SurfaceView android:id="@+id/preview_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
<com.google.zxing.client.android.ViewfinderView
|
||||
android:id="@+id/viewfinder_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
<LinearLayout android:id="@+id/result_view"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/result_view"
|
||||
android:visibility="gone"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="top"
|
||||
android:padding="@dimen/standard_padding">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:gravity="right">
|
||||
|
||||
<ImageView android:id="@+id/barcode_image_view"
|
||||
android:layout_width="150dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxWidth="150dip"
|
||||
android:maxHeight="150dip"
|
||||
android:layout_marginBottom="@dimen/half_padding"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerInside"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/msg_default_format"
|
||||
android:textColor="@color/result_minor_text"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="@dimen/half_padding"/>
|
||||
|
||||
<TextView android:id="@+id/format_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_minor_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/msg_default_type"
|
||||
android:textColor="@color/result_minor_text"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="@dimen/half_padding"/>
|
||||
|
||||
<TextView android:id="@+id/type_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_minor_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/msg_default_time"
|
||||
android:textColor="@color/result_minor_text"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="@dimen/half_padding"/>
|
||||
|
||||
<TextView android:id="@+id/time_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_minor_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:id="@+id/meta_text_view_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/msg_default_meta"
|
||||
android:textColor="@color/result_minor_text"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="@dimen/half_padding"/>
|
||||
|
||||
<TextView android:id="@+id/meta_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_minor_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:id="@+id/contents_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_text"
|
||||
android:textColorLink="@color/result_text"
|
||||
android:textSize="22sp"
|
||||
android:paddingLeft="12dip"
|
||||
android:autoLink="web"/>
|
||||
|
||||
<TextView android:id="@+id/contents_supplement_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_text"
|
||||
android:textColorLink="@color/result_text"
|
||||
android:paddingLeft="12dip"
|
||||
android:autoLink="web"
|
||||
android:clickable="true"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:id="@+id/result_button_view"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center">
|
||||
|
||||
<Button android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<Button android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<Button android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<Button android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<Button android:id="@+id/shopper_button"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:drawableLeft="@drawable/shopper_icon"
|
||||
android:text="@string/button_google_shopper"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView android:id="@+id/status_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:background="@color/transparent"
|
||||
android:text="@string/msg_default_status"
|
||||
android:textColor="@color/status_text"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/half_padding">
|
||||
|
||||
<TextView android:id="@+id/bookmark_title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"/>
|
||||
|
||||
<TextView android:id="@+id/bookmark_url"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="false"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,218 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<SurfaceView android:id="@+id/preview_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
<com.google.zxing.client.android.ViewfinderView
|
||||
android:id="@+id/viewfinder_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
<LinearLayout android:id="@+id/result_view"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/result_view"
|
||||
android:visibility="gone"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:padding="@dimen/standard_padding">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:gravity="right|center_vertical">
|
||||
|
||||
<ImageView android:id="@+id/barcode_image_view"
|
||||
android:layout_width="160dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxWidth="160dip"
|
||||
android:maxHeight="160dip"
|
||||
android:layout_marginBottom="@dimen/half_padding"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerInside"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/msg_default_format"
|
||||
android:textColor="@color/result_minor_text"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="@dimen/half_padding"/>
|
||||
|
||||
<TextView android:id="@+id/format_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_minor_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/msg_default_type"
|
||||
android:textColor="@color/result_minor_text"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="@dimen/half_padding"/>
|
||||
|
||||
<TextView android:id="@+id/type_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_minor_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/msg_default_time"
|
||||
android:textColor="@color/result_minor_text"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="@dimen/half_padding"/>
|
||||
|
||||
<TextView android:id="@+id/time_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_minor_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:id="@+id/meta_text_view_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/msg_default_meta"
|
||||
android:textColor="@color/result_minor_text"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="@dimen/half_padding"/>
|
||||
|
||||
<TextView android:id="@+id/meta_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_minor_text"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView android:id="@+id/contents_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_text"
|
||||
android:textColorLink="@color/result_text"
|
||||
android:textSize="22sp"
|
||||
android:paddingLeft="12dip"
|
||||
android:autoLink="web"/>
|
||||
|
||||
<TextView android:id="@+id/contents_supplement_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/result_text"
|
||||
android:textColorLink="@color/result_text"
|
||||
android:paddingLeft="12dip"
|
||||
android:autoLink="web"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:id="@+id/result_button_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center">
|
||||
|
||||
<Button android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<Button android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<Button android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<Button android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<Button android:id="@+id/shopper_button"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:drawableLeft="@drawable/shopper_icon"
|
||||
android:text="@string/button_google_shopper"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView android:id="@+id/status_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:background="@color/transparent"
|
||||
android:text="@string/msg_default_status"
|
||||
android:textColor="@color/status_text"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:fillViewport="true"
|
||||
android:background="@color/encode_view"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView android:id="@+id/image_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:scaleType="center"/>
|
||||
|
||||
<ScrollView android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView android:id="@+id/contents_text_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/contents_text"
|
||||
android:paddingBottom="@dimen/standard_padding"
|
||||
android:paddingLeft="@dimen/standard_padding"
|
||||
android:paddingRight="@dimen/standard_padding"/>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<WebView android:id="@+id/help_contents"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:paddingTop="@dimen/half_padding"
|
||||
android:weightSum="1">
|
||||
|
||||
<Button android:id="@+id/back_button"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.5"
|
||||
android:text="@string/button_back"/>
|
||||
|
||||
<Button android:id="@+id/done_button"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.5"
|
||||
android:text="@string/button_done"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/standard_padding">
|
||||
|
||||
<TextView android:id="@+id/history_title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:singleLine="true"/>
|
||||
|
||||
<TextView android:id="@+id/history_detail"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:singleLine="false"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0">
|
||||
|
||||
<EditText android:id="@+id/query_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left|center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:selectAllOnFocus="true"
|
||||
android:inputType="text"/>
|
||||
|
||||
<Button android:id="@+id/query_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:text="@string/button_search_book_contents"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<ListView android:id="@+id/result_list_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="@dimen/standard_padding"
|
||||
android:paddingBottom="@dimen/half_padding"
|
||||
android:enabled="false"
|
||||
android:singleLine="true"/>
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<com.google.zxing.client.android.book.SearchBookContentsListItem
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/standard_padding">
|
||||
|
||||
<TextView android:id="@+id/page_number_view"
|
||||
android:layout_width="75dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left|top"
|
||||
android:layout_marginRight="@dimen/standard_padding"
|
||||
android:singleLine="false"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView android:id="@+id/snippet_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left|top"
|
||||
android:singleLine="false"/>
|
||||
|
||||
</com.google.zxing.client.android.book.SearchBookContentsListItem>
|
|
@ -0,0 +1,96 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- ScrollView wrapper is to accommodate small screens. -->
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center">
|
||||
|
||||
<!-- Must wrap the rest in one layout -->
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/standard_padding">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/msg_share_explanation"
|
||||
android:paddingBottom="@dimen/standard_padding"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/share_via_barcode"
|
||||
android:paddingBottom="@dimen/standard_padding"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="@dimen/standard_padding">
|
||||
|
||||
<Button android:id="@+id/share_app_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/button_share_app"/>
|
||||
|
||||
<Button android:id="@+id/share_bookmark_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/button_share_bookmark"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="@dimen/standard_padding">
|
||||
|
||||
<Button android:id="@+id/share_contact_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/button_share_contact"/>
|
||||
|
||||
<Button android:id="@+id/share_clipboard_button"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/button_share_clipboard"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<EditText android:id="@+id/share_text_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/msg_share_text"
|
||||
android:singleLine="true"
|
||||
android:selectAllOnFocus="true"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2012 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- removed nonfunctional menu - see file history to retrieve -->
|
||||
</menu>
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2012 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- removed nonfunctional menu - see file history to retrieve -->
|
||||
</menu>
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2012 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/menu_history_send"
|
||||
android:title="@string/history_send"
|
||||
android:icon="@android:drawable/ic_menu_share"
|
||||
android:orderInCategory="1"/>
|
||||
<item android:id="@+id/menu_history_clear_text"
|
||||
android:title="@string/history_clear_text"
|
||||
android:icon="@android:drawable/ic_menu_delete"
|
||||
android:orderInCategory="2"/>
|
||||
</menu>
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<string-array name="country_codes">
|
||||
<item>-</item>
|
||||
<item>AR</item>
|
||||
<item>AU</item>
|
||||
<item>BR</item>
|
||||
<item>BG</item>
|
||||
<item>CA</item>
|
||||
<item>CN</item>
|
||||
<item>CZ</item>
|
||||
<item>DE</item>
|
||||
<item>DK</item>
|
||||
<item>ES</item>
|
||||
<item>FI</item>
|
||||
<item>FR</item>
|
||||
<item>GB</item>
|
||||
<item>GR</item>
|
||||
<item>HU</item>
|
||||
<item>ID</item>
|
||||
<item>IT</item>
|
||||
<item>JP</item>
|
||||
<item>KR</item>
|
||||
<item>NL</item>
|
||||
<item>PL</item>
|
||||
<item>PT</item>
|
||||
<item>RU</item>
|
||||
<item>SE</item>
|
||||
<item>SK</item>
|
||||
<item>SI</item>
|
||||
<item>TR</item>
|
||||
<item>TW</item>
|
||||
<item>US</item>
|
||||
</string-array>
|
||||
</resources>
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<resources>
|
||||
<color name="contents_text">#ff000000</color>
|
||||
<color name="encode_view">#ffffffff</color>
|
||||
<color name="possible_result_points">#c0ffbd21</color> <!-- Android standard ICS color -->
|
||||
<color name="result_minor_text">#ffc0c0c0</color>
|
||||
<color name="result_points">#c099cc00</color> <!-- Android standard ICS color -->
|
||||
<color name="result_text">#ffffffff</color>
|
||||
<color name="result_view">#b0000000</color>
|
||||
<color name="status_text">#ffffffff</color>
|
||||
<color name="transparent">#00000000</color>
|
||||
<color name="viewfinder_laser">#ffcc0000</color> <!-- Android standard ICS color -->
|
||||
<color name="viewfinder_mask">#60000000</color>
|
||||
</resources>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<dimen name="standard_padding">8dip</dimen>
|
||||
<dimen name="half_padding">4dip</dimen>
|
||||
</resources>
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<resources>
|
||||
<item type="id" name="decode"/>
|
||||
<item type="id" name="decode_failed"/>
|
||||
<item type="id" name="decode_succeeded"/>
|
||||
<item type="id" name="launch_product_query"/>
|
||||
<item type="id" name="quit"/>
|
||||
<item type="id" name="restart_preview"/>
|
||||
<item type="id" name="return_scan_result"/>
|
||||
</resources>
|
|
@ -0,0 +1,123 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">Copay</string>
|
||||
<string name="app_picker_name">Applications</string>
|
||||
<string name="bookmark_picker_name">Bookmarks</string>
|
||||
<string name="button_add_calendar">Add to calendar</string>
|
||||
<string name="button_add_contact">Add contact</string>
|
||||
<string name="button_back">Back</string>
|
||||
<string name="button_book_search">Book Search</string>
|
||||
<string name="button_cancel">Cancel</string>
|
||||
<string name="button_custom_product_search">Custom search</string>
|
||||
<string name="button_dial">Dial number</string>
|
||||
<string name="button_done">Done</string>
|
||||
<string name="button_email">Send email</string>
|
||||
<string name="button_get_directions">Get directions</string>
|
||||
<string name="button_google_shopper">Shopper</string>
|
||||
<string name="button_mms">Send MMS</string>
|
||||
<string name="button_ok">OK</string>
|
||||
<string name="button_open_browser">Open browser</string>
|
||||
<string name="button_product_search">Product Search</string>
|
||||
<string name="button_search_book_contents">Search contents</string>
|
||||
<string name="button_share_app">Application</string>
|
||||
<string name="button_share_bookmark">Bookmark</string>
|
||||
<string name="button_share_by_email">Share via email</string>
|
||||
<string name="button_share_by_sms">Share via SMS</string>
|
||||
<string name="button_share_clipboard">Clipboard</string>
|
||||
<string name="button_share_contact">Contact</string>
|
||||
<string name="button_show_map">Show map</string>
|
||||
<string name="button_sms">Send SMS</string>
|
||||
<string name="button_web_search">Web search</string>
|
||||
<string name="button_wifi">Connect to Network</string>
|
||||
<string name="contents_contact">Contact info</string>
|
||||
<string name="contents_email">Email address</string>
|
||||
<string name="contents_location">Geographic coordinates</string>
|
||||
<string name="contents_phone">Phone number</string>
|
||||
<string name="contents_sms">SMS address</string>
|
||||
<string name="contents_text">Plain text</string>
|
||||
<string name="history_clear_text">Clear history</string>
|
||||
<string name="history_clear_one_history_text">Clear</string>
|
||||
<string name="history_email_title">Barcode Scanner history</string>
|
||||
<string name="history_empty">Empty</string>
|
||||
<string name="history_empty_detail">No barcode scans have been recorded</string>
|
||||
<string name="history_send">Send history</string>
|
||||
<string name="history_title">History</string>
|
||||
<string name="menu_encode_mecard">Use MECARD</string>
|
||||
<string name="menu_encode_vcard">Use vCard</string>
|
||||
<string name="menu_help">Help</string>
|
||||
<string name="menu_history">History</string>
|
||||
<string name="menu_share">Share</string>
|
||||
<string name="msg_bulk_mode_scanned">Bulk mode: barcode scanned and saved</string>
|
||||
<string name="msg_camera_framework_bug">Sorry, the Android camera encountered a problem. You may need to restart the device.</string>
|
||||
<string name="msg_default_format">Format</string>
|
||||
<string name="msg_default_meta">Metadata</string>
|
||||
<string name="msg_default_mms_subject">Hi</string>
|
||||
<string name="msg_default_status">Place a barcode inside the viewfinder rectangle to scan it.</string>
|
||||
<string name="msg_default_time">Time</string>
|
||||
<string name="msg_default_type">Type</string>
|
||||
<string name="msg_encode_contents_failed">Could not encode a barcode from the data provided.</string>
|
||||
<string name="msg_google_books">Google Books</string>
|
||||
<string name="msg_google_product">Google Product Search</string>
|
||||
<string name="msg_google_shopper_missing">Google Shopper is not installed</string>
|
||||
<string name="msg_install_google_shopper">Google Shopper combines barcode scanning with online and local prices, reviews and more without opening the browser. Would you like to try it?</string>
|
||||
<string name="msg_intent_failed">Sorry, the requested application could not be launched. The barcode contents may be invalid.</string>
|
||||
<string name="msg_redirect">Redirect</string>
|
||||
<string name="msg_sbc_book_not_searchable">Sorry, this book is not searchable.</string>
|
||||
<string name="msg_sbc_failed">Sorry, the search encountered a problem.</string>
|
||||
<string name="msg_sbc_no_page_returned">No page returned</string>
|
||||
<string name="msg_sbc_page">Page</string>
|
||||
<string name="msg_sbc_results">Results</string>
|
||||
<string name="msg_sbc_searching_book">Searching book\u2026</string>
|
||||
<string name="msg_sbc_snippet_unavailable">Snippet not available</string>
|
||||
<string name="msg_sbc_unknown_page">Unknown page</string>
|
||||
<string name="msg_share_explanation">You can share data by displaying a barcode on your screen and scanning it with another phone.</string>
|
||||
<string name="msg_share_subject_line">Here are the contents of a barcode I scanned</string>
|
||||
<string name="msg_share_text">Or type some text and press Enter</string>
|
||||
<string name="msg_sure">Are you sure?</string>
|
||||
<string name="msg_unmount_usb">Sorry, the SD card is not accessible.</string>
|
||||
<string name="preferences_actions_title">When a barcode is found\u2026</string>
|
||||
<string name="preferences_auto_focus_title">Use auto focus</string>
|
||||
<string name="preferences_bulk_mode_summary">Scan and save many barcodes continuously</string>
|
||||
<string name="preferences_bulk_mode_title">Bulk scan mode</string>
|
||||
<string name="preferences_copy_to_clipboard_title">Copy to clipboard</string>
|
||||
<string formatted="false" name="preferences_custom_product_search_summary">Substitutions: %s = contents, %f = format, %t = type</string>
|
||||
<string name="preferences_custom_product_search_title">Custom search URL</string>
|
||||
<string name="preferences_decode_1D_title">1D barcodes</string>
|
||||
<string name="preferences_decode_Data_Matrix_title">Data Matrix</string>
|
||||
<string name="preferences_decode_QR_title">QR Codes</string>
|
||||
<string name="preferences_device_bug_workarounds_title">Device Bug Workarounds</string>
|
||||
<string name="preferences_disable_continuous_focus_summary">Use only standard focus mode</string>
|
||||
<string name="preferences_disable_continuous_focus_title">No continuous focus</string>
|
||||
<string name="preferences_disable_exposure_title">No exposure</string>
|
||||
<string name="preferences_front_light_summary">Improves scanning in low light on some phones, but may cause glare. Does not work on all phones.</string>
|
||||
<string name="preferences_front_light_title">Use front light</string>
|
||||
<string name="preferences_general_title">General settings</string>
|
||||
<string name="preferences_name">Settings</string>
|
||||
<string name="preferences_play_beep_title">Beep</string>
|
||||
<string name="preferences_remember_duplicates_summary">Store multiple scans of the same barcode in History</string>
|
||||
<string name="preferences_remember_duplicates_title">Remember duplicates</string>
|
||||
<string name="preferences_result_title">Result settings</string>
|
||||
<string name="preferences_scanning_title">When scanning for barcodes, decode\u2026</string>
|
||||
<string name="preferences_search_country">Search country</string>
|
||||
<string name="preferences_try_bsplus">Try Barcode Scanner+</string>
|
||||
<string name="preferences_try_bsplus_summary">Enhanced with new features and interface</string>
|
||||
<string name="preferences_supplemental_summary">Try to retrieve more information about the barcode contents</string>
|
||||
<string name="preferences_supplemental_title">Retrieve more info</string>
|
||||
<string name="preferences_vibrate_title">Vibrate</string>
|
||||
<string name="result_address_book">Found contact info</string>
|
||||
<string name="result_calendar">Found calendar event</string>
|
||||
<string name="result_email_address">Found email address</string>
|
||||
<string name="result_geo">Found geographic coordinates</string>
|
||||
<string name="result_isbn">Found book</string>
|
||||
<string name="result_product">Found product</string>
|
||||
<string name="result_sms">Found SMS address</string>
|
||||
<string name="result_tel">Found phone number</string>
|
||||
<string name="result_text">Found plain text</string>
|
||||
<string name="result_uri">Found URL</string>
|
||||
<string name="result_wifi">Found WLAN Configuration</string>
|
||||
<string name="sbc_name">Google Book Search</string>
|
||||
<string name="share_name">Share via barcode</string>
|
||||
<string name="wifi_changing_network">Requesting connection to network\u2026</string>
|
||||
<string name="wifi_ssid_label">Network Name</string>
|
||||
<string name="wifi_type_label">Type</string>
|
||||
</resources>
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<widget id="com.bitpay.copay" version="2.0.0" xmlns="http://www.w3.org/ns/widgets">
|
||||
<name>Copay</name>
|
||||
<description>
|
||||
A secure bitcoin wallet for friends and companies
|
||||
</description>
|
||||
<author email="support@bitpay.com" href="http://copay.io">
|
||||
Bitpay Inc.
|
||||
</author>
|
||||
<access origin="*" />
|
||||
<content src="index.html" />
|
||||
<preference name="loglevel" value="DEBUG" />
|
||||
<preference name="splashscreen" value="screen" />
|
||||
<preference name="splashScreenDelay" value="10000" />
|
||||
<preference name="backgroundColor" value="0x2C3E50" />
|
||||
<feature name="App">
|
||||
<param name="android-package" value="com.bitpay.copay" />
|
||||
</feature>
|
||||
<feature name="Vibration">
|
||||
<param name="android-package" value="org.apache.cordova.vibration.Vibration" />
|
||||
</feature>
|
||||
<feature name="BarcodeScanner">
|
||||
<param name="android-package" value="com.phonegap.plugins.barcodescanner.BarcodeScanner" />
|
||||
</feature>
|
||||
<feature name="EmailComposer">
|
||||
<param name="android-package" value="de.appplant.cordova.plugin.emailcomposer.EmailComposer" />
|
||||
</feature>
|
||||
<feature name="SplashScreen">
|
||||
<param name="android-package" value="org.apache.cordova.splashscreen.SplashScreen" />
|
||||
</feature>
|
||||
</widget>
|
|
@ -0,0 +1,102 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 ZXing authors
|
||||
|
||||
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.
|
||||
-->
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory android:title="@string/preferences_scanning_title">
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_decode_1D"
|
||||
android:defaultValue="true"
|
||||
android:title="@string/preferences_decode_1D_title"/>
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_decode_QR"
|
||||
android:defaultValue="true"
|
||||
android:title="@string/preferences_decode_QR_title"/>
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_decode_Data_Matrix"
|
||||
android:defaultValue="true"
|
||||
android:title="@string/preferences_decode_Data_Matrix_title"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/preferences_actions_title">
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_play_beep"
|
||||
android:defaultValue="true"
|
||||
android:title="@string/preferences_play_beep_title"/>
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_vibrate"
|
||||
android:defaultValue="false"
|
||||
android:title="@string/preferences_vibrate_title"/>
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_copy_to_clipboard"
|
||||
android:defaultValue="true"
|
||||
android:title="@string/preferences_copy_to_clipboard_title"/>
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_remember_duplicates"
|
||||
android:defaultValue="false"
|
||||
android:title="@string/preferences_remember_duplicates_title"
|
||||
android:summary="@string/preferences_remember_duplicates_summary"/>
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_supplemental"
|
||||
android:defaultValue="true"
|
||||
android:title="@string/preferences_supplemental_title"
|
||||
android:summary="@string/preferences_supplemental_summary"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/preferences_result_title">
|
||||
<EditTextPreference
|
||||
android:key="preferences_custom_product_search"
|
||||
android:title="@string/preferences_custom_product_search_title"
|
||||
android:summary="@string/preferences_custom_product_search_summary"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/preferences_general_title">
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_front_light"
|
||||
android:defaultValue="false"
|
||||
android:title="@string/preferences_front_light_title"
|
||||
android:summary="@string/preferences_front_light_summary"/>
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_auto_focus"
|
||||
android:defaultValue="true"
|
||||
android:title="@string/preferences_auto_focus_title"/>
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_bulk_mode"
|
||||
android:defaultValue="false"
|
||||
android:title="@string/preferences_bulk_mode_title"
|
||||
android:summary="@string/preferences_bulk_mode_summary"/>
|
||||
<ListPreference
|
||||
android:key="preferences_search_country"
|
||||
android:defaultValue="-"
|
||||
android:entries="@array/country_codes"
|
||||
android:entryValues="@array/country_codes"
|
||||
android:title="@string/preferences_search_country"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/preferences_device_bug_workarounds_title">
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_disable_continuous_focus"
|
||||
android:defaultValue="true"
|
||||
android:title="@string/preferences_disable_continuous_focus_title"
|
||||
android:summary="@string/preferences_disable_continuous_focus_summary"/>
|
||||
<!--
|
||||
<CheckBoxPreference
|
||||
android:key="preferences_disable_exposure"
|
||||
android:defaultValue="false"
|
||||
android:title="@string/preferences_disable_exposure_title"/>
|
||||
-->
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory android:title="@string/preferences_try_bsplus">
|
||||
<com.google.zxing.client.android.pref.BSPlusPreference
|
||||
android:title="@string/preferences_try_bsplus"
|
||||
android:summary="@string/preferences_try_bsplus_summary"/>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
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 com.bitpay.copay;
|
||||
|
||||
import android.os.Bundle;
|
||||
import org.apache.cordova.*;
|
||||
|
||||
public class Copay extends CordovaActivity
|
||||
{
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
super.init();
|
||||
// Set by <content src="index.html" /> in config.xml
|
||||
super.loadUrl(Config.getStartUrl());
|
||||
//super.loadUrl("file:///android_asset/www/index.html");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
/**
|
||||
* PhoneGap 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
|
||||
* Copyright (c) 2013, Maciej Nux Jaros
|
||||
*/
|
||||
package com.phonegap.plugins.barcodescanner;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.apache.cordova.CallbackContext;
|
||||
import org.apache.cordova.PluginResult;
|
||||
|
||||
/**
|
||||
* This calls out to the ZXing barcode reader and returns the result.
|
||||
*
|
||||
* @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java
|
||||
*/
|
||||
public class BarcodeScanner extends CordovaPlugin {
|
||||
public static final int REQUEST_CODE = 0x0ba7c0de;
|
||||
|
||||
private static final String SCAN = "scan";
|
||||
private static final String ENCODE = "encode";
|
||||
private static final String CANCELLED = "cancelled";
|
||||
private static final String FORMAT = "format";
|
||||
private static final String TEXT = "text";
|
||||
private static final String DATA = "data";
|
||||
private static final String TYPE = "type";
|
||||
private static final String SCAN_INTENT = "com.phonegap.plugins.barcodescanner.SCAN";
|
||||
private static final String ENCODE_DATA = "ENCODE_DATA";
|
||||
private static final String ENCODE_TYPE = "ENCODE_TYPE";
|
||||
private static final String ENCODE_INTENT = "com.phonegap.plugins.barcodescanner.ENCODE";
|
||||
private static final String TEXT_TYPE = "TEXT_TYPE";
|
||||
private static final String EMAIL_TYPE = "EMAIL_TYPE";
|
||||
private static final String PHONE_TYPE = "PHONE_TYPE";
|
||||
private static final String SMS_TYPE = "SMS_TYPE";
|
||||
|
||||
private static final String LOG_TAG = "BarcodeScanner";
|
||||
|
||||
private CallbackContext callbackContext;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public BarcodeScanner() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @sa https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java
|
||||
*/
|
||||
@Override
|
||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
|
||||
this.callbackContext = callbackContext;
|
||||
|
||||
if (action.equals(ENCODE)) {
|
||||
JSONObject obj = args.optJSONObject(0);
|
||||
if (obj != null) {
|
||||
String type = obj.optString(TYPE);
|
||||
String data = obj.optString(DATA);
|
||||
|
||||
// If the type is null then force the type to text
|
||||
if (type == null) {
|
||||
type = TEXT_TYPE;
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
callbackContext.error("User did not specify data to encode");
|
||||
return true;
|
||||
}
|
||||
|
||||
encode(type, data);
|
||||
} else {
|
||||
callbackContext.error("User did not specify data to encode");
|
||||
return true;
|
||||
}
|
||||
} else if (action.equals(SCAN)) {
|
||||
scan();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an intent to scan and decode a barcode.
|
||||
*/
|
||||
public void scan() {
|
||||
Intent intentScan = new Intent(SCAN_INTENT);
|
||||
intentScan.addCategory(Intent.CATEGORY_DEFAULT);
|
||||
|
||||
this.cordova.startActivityForResult((CordovaPlugin) this, intentScan, REQUEST_CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the barcode scanner intent completes.
|
||||
*
|
||||
* @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
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
if (requestCode == REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
JSONObject obj = new JSONObject();
|
||||
try {
|
||||
obj.put(TEXT, intent.getStringExtra("SCAN_RESULT"));
|
||||
obj.put(FORMAT, intent.getStringExtra("SCAN_RESULT_FORMAT"));
|
||||
obj.put(CANCELLED, false);
|
||||
} catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "This should never happen");
|
||||
}
|
||||
//this.success(new PluginResult(PluginResult.Status.OK, obj), this.callback);
|
||||
this.callbackContext.success(obj);
|
||||
} else if (resultCode == Activity.RESULT_CANCELED) {
|
||||
JSONObject obj = new JSONObject();
|
||||
try {
|
||||
obj.put(TEXT, "");
|
||||
obj.put(FORMAT, "");
|
||||
obj.put(CANCELLED, true);
|
||||
} catch (JSONException e) {
|
||||
Log.d(LOG_TAG, "This should never happen");
|
||||
}
|
||||
//this.success(new PluginResult(PluginResult.Status.OK, obj), this.callback);
|
||||
this.callbackContext.success(obj);
|
||||
} else {
|
||||
//this.error(new PluginResult(PluginResult.Status.ERROR), this.callback);
|
||||
this.callbackContext.error("Unexpected error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a barcode encode.
|
||||
*
|
||||
* @param type Endoiding type.
|
||||
* @param data The data to encode in the bar code.
|
||||
*/
|
||||
public void encode(String type, String data) {
|
||||
Intent intentEncode = new Intent(ENCODE_INTENT);
|
||||
intentEncode.putExtra(ENCODE_TYPE, type);
|
||||
intentEncode.putExtra(ENCODE_DATA, data);
|
||||
|
||||
this.cordova.getActivity().startActivity(intentEncode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Copyright 2013-2014 appPlant UG
|
||||
|
||||
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 de.appplant.cordova.plugin.emailcomposer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.provider.MediaStore;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
public class AttachmentProvider extends ContentProvider {
|
||||
|
||||
public static final String AUTHORITY = ".plugin.emailcomposer.attachmentprovider";
|
||||
|
||||
private UriMatcher uriMatcher;
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
String pkgName = this.getContext().getPackageName();
|
||||
|
||||
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
|
||||
uriMatcher.addURI(pkgName + AUTHORITY, "*", 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
|
||||
switch(uriMatcher.match(uri)) {
|
||||
case 1:
|
||||
String storage = getContext().getCacheDir() + EmailComposer.STORAGE_FOLDER;
|
||||
String path = storage + File.separator + uri.getLastPathSegment();
|
||||
|
||||
File file = new File(path);
|
||||
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
|
||||
|
||||
return pfd;
|
||||
default:
|
||||
throw new FileNotFoundException("Unsupported uri: " + uri.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri arg0, String arg1, String[] arg2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri arg0, ContentValues arg1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri arg0) {
|
||||
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(arg0.getPath());
|
||||
String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileExtension);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
MatrixCursor result = new MatrixCursor(projection);
|
||||
Object[] row = new Object[projection.length];
|
||||
long fileSize = 0;
|
||||
|
||||
String fileLocation = getContext().getCacheDir() + File.separator + uri.getLastPathSegment();
|
||||
File tempFile = new File(fileLocation);
|
||||
fileSize = tempFile.length();
|
||||
|
||||
for (int i=0; i<projection.length; i++) {
|
||||
if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.DISPLAY_NAME) == 0) {
|
||||
row[i] = uri.getLastPathSegment();
|
||||
} else if (projection[i].compareToIgnoreCase(MediaStore.MediaColumns.SIZE) == 0) {
|
||||
row[i] = fileSize;
|
||||
}
|
||||
}
|
||||
|
||||
result.addRow(row);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,413 @@
|
|||
/*
|
||||
Copyright 2013-2014 appPlant UG
|
||||
|
||||
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 de.appplant.cordova.plugin.emailcomposer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.text.Html;
|
||||
import android.util.Base64;
|
||||
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.apache.cordova.CallbackContext;
|
||||
import org.apache.cordova.PluginResult;
|
||||
|
||||
public class EmailComposer extends CordovaPlugin {
|
||||
|
||||
static protected final String STORAGE_FOLDER = File.separator + "email_composer";
|
||||
|
||||
private CallbackContext command;
|
||||
|
||||
@Override
|
||||
public boolean execute (String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||
|
||||
this.command = callbackContext;
|
||||
|
||||
// Eine E-Mail soll versendet werden
|
||||
if ("open".equals(action)) {
|
||||
open(args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Es soll überprüft werden, ob ein Dienst zum Versenden der E-Mail zur Verfügung steht
|
||||
if ("isServiceAvailable".equals(action)) {
|
||||
isServiceAvailable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returning false results in a "MethodNotFound" error.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Überprüft, ob Emails versendet werden können.
|
||||
*/
|
||||
private void isServiceAvailable () {
|
||||
Boolean available = isEmailAccountConfigured();
|
||||
PluginResult result = new PluginResult(PluginResult.Status.OK, available);
|
||||
|
||||
command.sendPluginResult(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Öffnet den Email-Kontroller mit vorausgefüllten Daten.
|
||||
*/
|
||||
private void open (JSONArray args) throws JSONException {
|
||||
JSONObject properties = args.getJSONObject(0);
|
||||
Intent draft = getDraftWithProperties(properties);
|
||||
|
||||
openDraft(draft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt den ViewController für Mails und fügt die übergebenen Eigenschaften ein.
|
||||
*
|
||||
* @param {JSONObject} params (Subject, Body, Recipients, ...)
|
||||
*/
|
||||
private Intent getDraftWithProperties (JSONObject params) throws JSONException {
|
||||
Intent mail = new Intent(android.content.Intent.ACTION_SEND_MULTIPLE);
|
||||
|
||||
if (params.has("subject"))
|
||||
setSubject(params.getString("subject"), mail);
|
||||
if (params.has("body"))
|
||||
setBody(params.getString("body"), params.optBoolean("isHtml"), mail);
|
||||
if (params.has("to"))
|
||||
setRecipients(params.getJSONArray("to"), mail);
|
||||
if (params.has("cc"))
|
||||
setCcRecipients(params.getJSONArray("cc"), mail);
|
||||
if (params.has("bcc"))
|
||||
setBccRecipients(params.getJSONArray("bcc"), mail);
|
||||
if (params.has("attachments"))
|
||||
setAttachments(params.getJSONArray("attachments"), mail);
|
||||
|
||||
mail.setType("application/octet-stream");
|
||||
|
||||
return mail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt den ViewController zum Versenden/Bearbeiten der Mail an.
|
||||
*/
|
||||
private void openDraft (final Intent draft) {
|
||||
final EmailComposer plugin = this;
|
||||
|
||||
cordova.getThreadPool().execute( new Runnable() {
|
||||
public void run() {
|
||||
cordova.startActivityForResult(plugin, Intent.createChooser(draft, "Select Email App"), 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt den Subject der Mail.
|
||||
*/
|
||||
private void setSubject (String subject, Intent draft) {
|
||||
draft.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt den Body der Mail.
|
||||
*/
|
||||
private void setBody (String body, Boolean isHTML, Intent draft) {
|
||||
if (isHTML) {
|
||||
draft.putExtra(android.content.Intent.EXTRA_TEXT, Html.fromHtml(body));
|
||||
draft.setType("text/html");
|
||||
} else {
|
||||
draft.putExtra(android.content.Intent.EXTRA_TEXT, body);
|
||||
draft.setType("text/plain");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt die Empfänger der Mail.
|
||||
*/
|
||||
private void setRecipients (JSONArray recipients, Intent draft) throws JSONException {
|
||||
String[] receivers = new String[recipients.length()];
|
||||
|
||||
for (int i = 0; i < recipients.length(); i++) {
|
||||
receivers[i] = recipients.getString(i);
|
||||
}
|
||||
|
||||
draft.putExtra(android.content.Intent.EXTRA_EMAIL, receivers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt die CC-Empfänger der Mail.
|
||||
*/
|
||||
private void setCcRecipients (JSONArray ccRecipients, Intent draft) throws JSONException {
|
||||
String[] receivers = new String[ccRecipients.length()];
|
||||
|
||||
for (int i = 0; i < ccRecipients.length(); i++) {
|
||||
receivers[i] = ccRecipients.getString(i);
|
||||
}
|
||||
|
||||
draft.putExtra(android.content.Intent.EXTRA_CC, receivers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt die BCC-Empfänger der Mail.
|
||||
*/
|
||||
private void setBccRecipients (JSONArray bccRecipients, Intent draft) throws JSONException {
|
||||
String[] receivers = new String[bccRecipients.length()];
|
||||
|
||||
for (int i = 0; i < bccRecipients.length(); i++) {
|
||||
receivers[i] = bccRecipients.getString(i);
|
||||
}
|
||||
|
||||
draft.putExtra(android.content.Intent.EXTRA_BCC, receivers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt die Anhände zur Mail hinzu.
|
||||
*/
|
||||
private void setAttachments (JSONArray attachments, Intent draft) throws JSONException {
|
||||
ArrayList<Uri> attachmentUris = new ArrayList<Uri>();
|
||||
|
||||
for (int i = 0; i < attachments.length(); i++) {
|
||||
Uri attachmentUri = getUriForPath(attachments.getString(i));
|
||||
|
||||
attachmentUris.add(attachmentUri);
|
||||
}
|
||||
|
||||
draft.putParcelableArrayListExtra(Intent.EXTRA_STREAM, attachmentUris);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt an, ob es eine Anwendung gibt, welche E-Mails versenden kann.
|
||||
*/
|
||||
private Boolean isEmailAccountConfigured () {
|
||||
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto","max@mustermann.com", null));
|
||||
Boolean available = cordova.getActivity().getPackageManager().queryIntentActivities(intent, 0).size() > 1;
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URI for an attachment path.
|
||||
*
|
||||
* @param {String} path
|
||||
* The given path to the attachment
|
||||
*
|
||||
* @return The URI pointing to the given path
|
||||
*/
|
||||
private Uri getUriForPath (String path) {
|
||||
if (path.startsWith("res:")) {
|
||||
return getUriForResourcePath(path);
|
||||
} else if (path.startsWith("file:")) {
|
||||
return getUriForAbsolutePath(path);
|
||||
} else if (path.startsWith("www:")) {
|
||||
return getUriForAssetPath(path);
|
||||
} else if (path.startsWith("base64:")) {
|
||||
return getUriForBase64Content(path);
|
||||
}
|
||||
|
||||
return Uri.parse(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* The URI for a file.
|
||||
*
|
||||
* @param {String} path
|
||||
* The given absolute path
|
||||
*
|
||||
* @return The URI pointing to the given path
|
||||
*/
|
||||
private Uri getUriForAbsolutePath (String path) {
|
||||
String absPath = path.replaceFirst("file://", "");
|
||||
File file = new File(absPath);
|
||||
|
||||
if (!file.exists()) {
|
||||
System.err.println("Attachment path not found: " + file.getAbsolutePath());
|
||||
}
|
||||
|
||||
return Uri.fromFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* The URI for an asset.
|
||||
*
|
||||
* @param {String} path
|
||||
* The given asset path
|
||||
*
|
||||
* @return The URI pointing to the given path
|
||||
*/
|
||||
private Uri getUriForAssetPath (String path) {
|
||||
String resPath = path.replaceFirst("www:/", "www");
|
||||
String fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
|
||||
String storage = cordova.getActivity().getExternalCacheDir().toString() + STORAGE_FOLDER;
|
||||
|
||||
File file = new File(storage, fileName);
|
||||
|
||||
new File(storage).mkdir();
|
||||
|
||||
try {
|
||||
AssetManager assets = cordova.getActivity().getAssets();
|
||||
|
||||
FileOutputStream outStream = new FileOutputStream(file);
|
||||
InputStream inputStream = assets.open(resPath);
|
||||
|
||||
copyFile(inputStream, outStream);
|
||||
outStream.flush();
|
||||
outStream.close();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Attachment asset not found: assets/" + resPath);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return Uri.fromFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* The URI for a resource.
|
||||
*
|
||||
* @param {String} path
|
||||
* The given relative path
|
||||
*
|
||||
* @return The URI pointing to the given path
|
||||
*/
|
||||
private Uri getUriForResourcePath (String path) {
|
||||
String resPath = path.replaceFirst("res://", "");
|
||||
String fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
|
||||
String resName = fileName.substring(0, fileName.lastIndexOf('.'));
|
||||
String extension = resPath.substring(resPath.lastIndexOf('.'));
|
||||
String storage = cordova.getActivity().getExternalCacheDir().toString() + STORAGE_FOLDER;
|
||||
|
||||
int resId = getResId(resPath);
|
||||
File file = new File(storage, resName + extension);
|
||||
|
||||
if (resId == 0) {
|
||||
System.err.println("Attachment resource not found: " + resPath);
|
||||
}
|
||||
|
||||
new File(storage).mkdir();
|
||||
|
||||
try {
|
||||
Resources res = cordova.getActivity().getResources();
|
||||
FileOutputStream outStream = new FileOutputStream(file);
|
||||
InputStream inputStream = res.openRawResource(resId);
|
||||
|
||||
copyFile(inputStream, outStream);
|
||||
outStream.flush();
|
||||
outStream.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return Uri.fromFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* The URI for a base64 encoded content.
|
||||
*
|
||||
* @param {String} content
|
||||
* The given base64 encoded content
|
||||
*
|
||||
* @return The URI including the given content
|
||||
*/
|
||||
private Uri getUriForBase64Content (String content) {
|
||||
String resName = content.substring(content.indexOf(":") + 1, content.indexOf("//"));
|
||||
String resData = content.substring(content.indexOf("//") + 2);
|
||||
byte[] bytes = Base64.decode(resData, 0);
|
||||
String storage = this.cordova.getActivity().getCacheDir() + STORAGE_FOLDER;
|
||||
File file = new File(storage, resName);
|
||||
|
||||
new File(storage).mkdir();
|
||||
|
||||
try {
|
||||
FileOutputStream outStream = new FileOutputStream(file);
|
||||
|
||||
outStream.write(bytes);
|
||||
outStream.flush();
|
||||
outStream.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
String pkgName = getPackageName();
|
||||
String uriPath = pkgName + AttachmentProvider.AUTHORITY + "/" + resName;
|
||||
|
||||
return Uri.parse("content://" + uriPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an InputStream to an OutputStream
|
||||
*
|
||||
* @param {InputStream} in
|
||||
* @param {OutputStream} out
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private void copyFile (InputStream in, OutputStream out) throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
|
||||
while((read = in.read(buffer)) != -1){
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* The resource ID for the given resource.
|
||||
*/
|
||||
private int getResId (String resPath) {
|
||||
Resources res = cordova.getActivity().getResources();
|
||||
|
||||
String pkgName = getPackageName();
|
||||
String dirName = resPath.substring(0, resPath.lastIndexOf('/'));
|
||||
String fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
|
||||
String resName = fileName.substring(0, fileName.lastIndexOf('.'));
|
||||
|
||||
int resId = res.getIdentifier(resName, dirName, pkgName);
|
||||
|
||||
return resId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* The name for the package.
|
||||
*/
|
||||
private String getPackageName () {
|
||||
return cordova.getActivity().getPackageName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
super.onActivityResult(requestCode, resultCode, intent);
|
||||
|
||||
command.success();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
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.splashscreen;
|
||||
|
||||
import org.apache.cordova.CallbackContext;
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.json.JSONArray;
|
||||
|
||||
public class SplashScreen extends CordovaPlugin {
|
||||
|
||||
@Override
|
||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
|
||||
if (action.equals("hide")) {
|
||||
this.webView.postMessage("splashscreen", "hide");
|
||||
} else if (action.equals("show")){
|
||||
this.webView.postMessage("splashscreen", "show");
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
callbackContext.success();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
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.vibration;
|
||||
|
||||
import org.apache.cordova.CallbackContext;
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import android.content.Context;
|
||||
import android.os.Vibrator;
|
||||
|
||||
/**
|
||||
* This class provides access to vibration on the device.
|
||||
*/
|
||||
public class Vibration extends CordovaPlugin {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Vibration() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the request and returns PluginResult.
|
||||
*
|
||||
* @param action The action to execute.
|
||||
* @param args JSONArray of arguments for the plugin.
|
||||
* @param callbackContext The callback context used when calling back into JavaScript.
|
||||
* @return True when the action was valid, false otherwise.
|
||||
*/
|
||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||
if (action.equals("vibrate")) {
|
||||
this.vibrate(args.getLong(0));
|
||||
}
|
||||
else if (action.equals("vibrateWithPattern")) {
|
||||
JSONArray pattern = args.getJSONArray(0);
|
||||
int repeat = args.getInt(1);
|
||||
long[] patternArray = new long[pattern.length()];
|
||||
for (int i = 0; i < pattern.length(); i++) {
|
||||
patternArray[i] = pattern.getLong(i);
|
||||
}
|
||||
this.vibrateWithPattern(patternArray, repeat);
|
||||
}
|
||||
else if (action.equals("cancelVibration")) {
|
||||
this.cancelVibration();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only alert and confirm are async.
|
||||
callbackContext.success();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// LOCAL METHODS
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Vibrates the device for a given amount of time.
|
||||
*
|
||||
* @param time Time to vibrate in ms.
|
||||
*/
|
||||
public void vibrate(long time) {
|
||||
// Start the vibration, 0 defaults to half a second.
|
||||
if (time == 0) {
|
||||
time = 500;
|
||||
}
|
||||
Vibrator vibrator = (Vibrator) this.cordova.getActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
vibrator.vibrate(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vibrates the device with a given pattern.
|
||||
*
|
||||
* @param pattern Pattern with which to vibrate the device.
|
||||
* Pass in an array of longs that
|
||||
* are the durations for which to
|
||||
* turn on or off the vibrator in
|
||||
* milliseconds. The first value
|
||||
* indicates the number of milliseconds
|
||||
* to wait before turning the vibrator
|
||||
* on. The next value indicates the
|
||||
* number of milliseconds for which
|
||||
* to keep the vibrator on before
|
||||
* turning it off. Subsequent values
|
||||
* alternate between durations in
|
||||
* milliseconds to turn the vibrator
|
||||
* off or to turn the vibrator on.
|
||||
*
|
||||
* @param repeat Optional index into the pattern array at which
|
||||
* to start repeating, or -1 for no repetition (default).
|
||||
*/
|
||||
public void vibrateWithPattern(long[] pattern, int repeat) {
|
||||
Vibrator vibrator = (Vibrator) this.cordova.getActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
vibrator.vibrate(pattern, repeat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately cancels any currently running vibration.
|
||||
*/
|
||||
public void cancelVibration() {
|
||||
Vibrator vibrator = (Vibrator) this.cordova.getActivity().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
vibrator.cancel();
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
"bugs": {
|
||||
"url": "https://github.com/bitpay/copay/issues"
|
||||
},
|
||||
"version": "0.3.2",
|
||||
"version": "0.4.1",
|
||||
"dependencies": {
|
||||
"preconditions": "^1.0.7",
|
||||
"sinon": "1.9.1",
|
||||
|
@ -48,7 +48,7 @@
|
|||
"github-releases": "0.2.0",
|
||||
"grunt-markdown": "0.5.0",
|
||||
"browser-pack": "2.0.1",
|
||||
"bitcore": "0.1.25",
|
||||
"bitcore": "0.1.34",
|
||||
"node-cryptojs-aes": "0.4.0",
|
||||
"blanket": "1.1.6",
|
||||
"express": "4.0.0",
|
||||
|
|
|
@ -9,7 +9,7 @@ var WalletKey = bitcore.WalletKey;
|
|||
var Key = bitcore.Key;
|
||||
var bignum = bitcore.Bignum;
|
||||
var Script = bitcore.Script;
|
||||
var Builder = bitcore.TransactionBuilder;
|
||||
var TransactionBuilder = bitcore.TransactionBuilder;
|
||||
var util = bitcore.util;
|
||||
var networks = bitcore.networks;
|
||||
try {
|
||||
|
@ -139,7 +139,6 @@ describe('TxProposals model', function() {
|
|||
var createTx = function(toAddress, amountSatStr, utxos, opts, priv, pkr) {
|
||||
opts = opts || {};
|
||||
|
||||
var amountSat = bitcore.Bignum(amountSatStr);
|
||||
var pub = priv.publicHex;
|
||||
|
||||
if (!pkr.isComplete()) {
|
||||
|
@ -152,11 +151,11 @@ describe('TxProposals model', function() {
|
|||
};
|
||||
};
|
||||
|
||||
var b = new Builder(opts)
|
||||
var b = new TransactionBuilder(opts)
|
||||
.setUnspent(utxos)
|
||||
.setOutputs([{
|
||||
address: toAddress,
|
||||
amountSat: amountSat
|
||||
amountSatStr: amountSatStr,
|
||||
}]);
|
||||
var selectedUtxos = b.getSelectedUnspent();
|
||||
var inputChainPaths = selectedUtxos.map(function(utxo) {
|
||||
|
@ -177,11 +176,13 @@ describe('TxProposals model', function() {
|
|||
var me = {};
|
||||
if (priv) me[priv.getId()] = Date.now();
|
||||
|
||||
var tx = b.build();
|
||||
|
||||
return {
|
||||
inputChainPaths: inputChainPaths,
|
||||
creator: priv.getId(),
|
||||
createdTs: new Date(),
|
||||
signedBy: priv && b.signaturesAdded ? me : {},
|
||||
signedBy: priv && tx.countInputSignatures(0) ? me : {},
|
||||
seenBy: priv ? me : {},
|
||||
builder: b,
|
||||
};
|
||||
|
@ -287,6 +288,7 @@ describe('TxProposals model', function() {
|
|||
var ntxid = Object.keys(w.txps)[0];
|
||||
var tx = w.txps[ntxid].builder.build();
|
||||
tx.isComplete().should.equal(false);
|
||||
tx.countInputSignatures(0).should.equal(0);
|
||||
tx.countInputMissingSignatures(0).should.equal(1);
|
||||
|
||||
Object.keys(w.txps[ntxid].signedBy).length.should.equal(0);
|
||||
|
@ -313,7 +315,8 @@ describe('TxProposals model', function() {
|
|||
tx.isComplete().should.equal(false);
|
||||
tx.countInputMissingSignatures(0).should.equal(2);
|
||||
|
||||
(w2.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true);
|
||||
|
||||
(w2.txps[ntxid].signedBy[priv.id] - ts > 0).should.equal(true, 'asdsd');
|
||||
(w2.txps[ntxid].seenBy[priv.id] - ts > 0).should.equal(true);
|
||||
|
||||
var info = w.merge(w2.txps[ntxid], pkr.getCopayerId(0));
|
||||
|
@ -390,7 +393,6 @@ describe('TxProposals model', function() {
|
|||
|
||||
var ntxid = Object.keys(w.txps)[0];
|
||||
txb = w.txps[ntxid].builder;
|
||||
txb.signaturesAdded.should.equal(0);
|
||||
tx = txb.build();
|
||||
|
||||
tx.isComplete().should.equal(false);
|
||||
|
@ -417,7 +419,6 @@ describe('TxProposals model', function() {
|
|||
txb = w2.txps[ntxid].builder;
|
||||
tx = txb.build();
|
||||
|
||||
txb.signaturesAdded.should.equal(1);
|
||||
tx.isComplete().should.equal(false);
|
||||
tx.countInputMissingSignatures(0).should.equal(2);
|
||||
|
||||
|
@ -526,7 +527,6 @@ describe('TxProposals model', function() {
|
|||
(w2.txps[ntxid].signedBy[priv2.id] - ts > 0).should.equal(true);
|
||||
(w2.txps[ntxid].seenBy[priv2.id] - ts > 0).should.equal(true);
|
||||
|
||||
|
||||
var w3 = new TxProposals({
|
||||
networkName: config.networkName,
|
||||
});
|
||||
|
@ -573,6 +573,13 @@ describe('TxProposals model', function() {
|
|||
});
|
||||
|
||||
|
||||
it('#fromObj stored (hardcoded) data', function() {
|
||||
var txp = TxProposals.TxProposal.fromObj(txpv1);
|
||||
txp.getID().should.equal('5cae6e225335acd2725856c71ef1ca61c42f118967102c5d0ed6710343e4a19f');
|
||||
var tx = txp.builder.build();
|
||||
tx.countInputSignatures(0).should.equal(2);
|
||||
tx.countInputMissingSignatures(0).should.equal(0);
|
||||
});
|
||||
|
||||
it('#toObj #fromObj roundtrip', function() {
|
||||
|
||||
|
@ -605,16 +612,17 @@ describe('TxProposals model', function() {
|
|||
var o = w.toObj();
|
||||
should.exist(o);
|
||||
o.txps.length.should.equal(1);
|
||||
|
||||
should.exist(o.txps[0]);
|
||||
should.exist(o.txps[0].signedBy);
|
||||
should.exist(o.txps[0].seenBy);
|
||||
should.exist(o.txps[0].builderObj);
|
||||
should.exist(o.txps[0].builderObj.valueInSat);
|
||||
should.exist(o.txps[0].signedBy[priv.id]);
|
||||
|
||||
var o2 = JSON.parse(JSON.stringify(o));
|
||||
var w2 = TxProposals.fromObj(o2);
|
||||
w2.walletId.should.equal(w.walletId);
|
||||
|
||||
var tx2 = w2.txps[ntxid].builder.build();
|
||||
tx2.isComplete().should.equal(false);
|
||||
tx2.countInputMissingSignatures(0).should.equal(2);
|
||||
|
@ -627,5 +635,93 @@ describe('TxProposals model', function() {
|
|||
Object.keys(w2.txps).length.should.equal(1);
|
||||
});
|
||||
|
||||
describe('TxProposal model', function() {
|
||||
var createMockTxp = function(raw) {
|
||||
var tx = new Transaction();
|
||||
tx.parse(new Buffer(raw, 'hex'));
|
||||
var txb = new TransactionBuilder();
|
||||
var txp = new TxProposals.TxProposal({
|
||||
builder: txb
|
||||
});
|
||||
txb.build = function() {
|
||||
return tx;
|
||||
};
|
||||
return txp;
|
||||
};
|
||||
|
||||
it('should validate for no signatures yet in tx', function() {
|
||||
// taken from https://gist.github.com/gavinandresen/3966071
|
||||
var raw = '010000000189632848f99722915727c5c75da8db2dbf194342a0429828f66ff88fab2af7d60000000000ffffffff0140420f000000000017a914f815b036d9bbbce5e9f2a00abd1bf3dc91e955108700000000';
|
||||
var txp = createMockTxp(raw);
|
||||
txp.isValid().should.equal(true);
|
||||
});
|
||||
it('should validate for no signatures yet in copay generated tx', function() {
|
||||
// taken from copay incomplete tx proposal
|
||||
var raw = '0100000001e205297fd05e4504d72761dc7a16e5cc9f4ab89877f28aee97c1cc66b3f07d690100000000ffffffff01706f9800000000001976a91473707e88f79c9c616b44bc766a25efcb9f49346688ac00000000';
|
||||
var txp = createMockTxp(raw);
|
||||
txp.isValid().should.equal(true);
|
||||
});
|
||||
it('should validate for a SIGHASH_NONE tx in builder', function() {
|
||||
var raw = '010000000145c3bf51ced6cefaea8c6578a645316270dbf8600f46969d31136e1e06829598000000007000483045022100877c715e0f3bd6377086c96d4757b2c983682a1934d9e3f894941f4f1e18d4710220272ed81758d7a391ee4c15a29246f3fe75efbddeaf1118e4c0d3bb14f57cdba601255121022f58491a833933a9bea80d8e820e66bee91bd8c71bfa972fe70482360b48129951aeffffffff01706f9800000000001976a91408328947f0caf8728729d740cbecdfe3c2327db588ac00000000';
|
||||
var txp = createMockTxp(raw);
|
||||
txp.isValid().should.equal(true);
|
||||
});
|
||||
it('should not validate for a non SIGHASH_NONE tx in builder with 1 input', function() {
|
||||
var raw = '0100000001eaf08f93f895127fbf000128ac74f6e8c7f003854e5ee1f02a5fd820cb689beb00000000fdfe00004730440220778f3174393e9ee6b0bfa876b4150db6f12a4da9715044ead5e345c2781ceee002203aab31f1e1d3dcf77ca780d9af798139719891917c9a09123dba54483ef462bc02493046022100dd93b64b30580029605dbba09d7fa34194d9ff38fda0c4fa187c52bf7f79ae98022100dd7b056762087b9aa8ccfde328d7067fa1753b78c0ee25577122569ff9de1d57024c695221039f847c24f09d7299c10bba4e41b24dc78e47bbb05fd7c1d209c994899d6881062103d363476e634fc5cdc11e9330c05a141c1e0c7f8b616817bdb83e7579bbf870942103fb2072953ceab87c6da450ac661685a881ddb661002d2ec1d60bfd33e3ec807d53aeffffffff01d06bf5050000000017a914db682f579cf6ca483880460fcf4ab63e223dc07e8700000000';
|
||||
var txp = createMockTxp(raw);
|
||||
txp.isValid().should.equal(false);
|
||||
});
|
||||
it('should not validate for a non SIGHASH_NONE tx in builder with 1 input', function() {
|
||||
var raw = '0100000002d903852d223b3100fcc01e0b02d73a76a0787cdff7d000e9cba0e931917f407501000000fdfe0000493046022100b232e994fdca7fd61fcf8ffe4a7f746ff8f8baf2667ac80841de0250f521c402022100862c0783ca7eafcbd2786b9444ed6e83ae941dcc2248bea4db12b7815d15de050247304402200189fe0cde9d1dd192553f4dddb6764df3eb643f9f71be8aa015f41f2d4fd11f02205513b8ca985c3b5b936f814c7eba92e2e2985c83927ca06c41081d264c0be7a7024c695221026fa1a3ed0c820c1053c8ba101f3c96f85c55624a902a82cf6b2896ed5f9b3d1521035a3383c13dd346a5784adfe3ec3026ab31d519fdfae2740497b10bdfb994e6442103c7477a6668d5bc250fe727e358d951b9e05f1d7c02059bf59ecbb335f1eeec7953aeffffffffd903852d223b3100fcc01e0b02d73a76a0787cdff7d000e9cba0e931917f407500000000fdfd0000483045022100bdb9d14569af66d84af63416d77296ace24a96f1720d30e74bc6e316a4b3727502206ed54d532467393488889d72edbb667d075de491a89e8e496fee8791b943fa37024730440220379c30c884a21a949d8ec32d6934ffa9faf86add4d839de0f5fbd2b90f8ef1e802204048df2ec0035ce5e4bf01e9d70fd93a45a41ce2630100d692cd908cdaa61fc0024c69522102203938ef947327edce2cf2997c55b433be3d3ffcf3284c10d6fcdf4b01c6221f21033b60c3363a226ce9b850af655c6e1470d9a0936d7f56ea4a07ab84005f91cd1b210385755bc813fe7f92577b93bf689bf0d9b2118e6bbb7fee5d3d16976f4f7271af53aeffffffff01c02d9a3b0000000017a914db682f579cf6ca483880460fcf4ab63e223dc07e8700000000';
|
||||
var txp = createMockTxp(raw);
|
||||
txp.isValid().should.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
var txpv1 = {
|
||||
"creator": "0361fb4252367715405a0d27f99cc74a671133292e8d725e009536d7257c8c01b0",
|
||||
"createdTs": 1406310417996,
|
||||
"seenBy": {
|
||||
"0361fb4252367715405a0d27f99cc74a671133292e8d725e009536d7257c8c01b0": 1406310417996,
|
||||
"02ba1599c64da4d80e25985be46c50e944b65f02e2b48c930528ce763d6710158f": 1406310418162
|
||||
},
|
||||
"signedBy": {
|
||||
"0361fb4252367715405a0d27f99cc74a671133292e8d725e009536d7257c8c01b0": 1406310417996,
|
||||
"02ba1599c64da4d80e25985be46c50e944b65f02e2b48c930528ce763d6710158f": 1406310645549
|
||||
},
|
||||
"rejectedBy": {},
|
||||
"sentTs": 1406310645873,
|
||||
"sentTxid": "87296c50e8601437d63d556afb27c3b8e3819214be0a9d756d401a8286c0ec43",
|
||||
"inputChainPaths": ["m/45'/0/1/1"],
|
||||
"comment": "test 6",
|
||||
"builderObj": {
|
||||
"version": 1,
|
||||
"outs": [{
|
||||
"address": "mph66bnLvcn9KUSMrpikUBUZZkN2C1Z5tg",
|
||||
"amountSatStr": 100
|
||||
}],
|
||||
"utxos": [{
|
||||
"address": "2NEodmgBa4SH3VwE2asgW34vMYe8VThBZNo",
|
||||
"txid": "8f8deda12dad6248e655054632a27f6891ebb37e8d2b3dd1bff87e71fd451ac7",
|
||||
"vout": 1,
|
||||
"ts": 1406312717,
|
||||
"scriptPubKey": "a914ec7bce12d0e82a7d2b5431f6d89ca70af317f5a187",
|
||||
"amount": 0.009798,
|
||||
"confirmations": 0,
|
||||
"confirmationsFromCache": false
|
||||
}],
|
||||
"opts": {
|
||||
"spendUnconfirmed": true,
|
||||
"remainderOut": {
|
||||
"address": "2N74XAozMH3JB3XgeBkRvRw1J8TtfLTtvny"
|
||||
}
|
||||
},
|
||||
"scriptSig": ["00483045022100f167ad33b8bef4c65af8d19c1a849d1770cc8d1e35bffebe6b5459dcbe655c7802207b37370b308ba668fe19f8e8bc462c9fbdc6c67f79900670758d228d83ea96da014730440220038ad3f4cc7b0738b593454ec189913ae4b442bc83da153d68d9a0077bd1b09102202b5728a08f302e97de61ea37280b48ccdd575f0d235c22f5e0ecac6a4ab0f46401475221024739614847d5233a46913482c17c6860194ad78abb3bf47de46223047d8a0b5821024c6dc65a52c5eaaa080b96888091544f8ab8712caa7e0b69ea4b45f6f059557452ae"],
|
||||
"hashToScriptMap": {
|
||||
"2NEodmgBa4SH3VwE2asgW34vMYe8VThBZNo": "5221024739614847d5233a46913482c17c6860194ad78abb3bf47de46223047d8a0b5821024c6dc65a52c5eaaa080b96888091544f8ab8712caa7e0b69ea4b45f6f059557452ae"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -16,6 +16,8 @@ var Network = require('./mocks/FakeNetwork');
|
|||
var Blockchain = require('./mocks/FakeBlockchain');
|
||||
var bitcore = bitcore || require('bitcore');
|
||||
var TransactionBuilder = bitcore.TransactionBuilder;
|
||||
var Transaction = bitcore.Transaction;
|
||||
var Address = bitcore.Address;
|
||||
|
||||
var addCopayers = function(w) {
|
||||
for (var i = 0; i < 4; i++) {
|
||||
|
@ -424,46 +426,46 @@ describe('Wallet model', function() {
|
|||
var w = createW();
|
||||
var txp = {
|
||||
'txProposal': {
|
||||
"seenBy": {
|
||||
"undefined": 1402337282806
|
||||
creator: '02c643ef43c14481fa8e81e61438c2cbc39a59024663f8cab575d28a248fe53d96',
|
||||
createdTs: '2014-07-24T23:54:26.682Z',
|
||||
seenBy: {
|
||||
'02c643ef43c14481fa8e81e61438c2cbc39a59024663f8cab575d28a248fe53d96': 1406246066682
|
||||
},
|
||||
"signedBy": {
|
||||
"undefined": 1402337282841
|
||||
signedBy: {
|
||||
'02c643ef43c14481fa8e81e61438c2cbc39a59024663f8cab575d28a248fe53d96': 1406246066682
|
||||
},
|
||||
"rejectedBy": {},
|
||||
"sentTs": null,
|
||||
"sentTxid": null,
|
||||
"inputChainPaths": [],
|
||||
"builderObj": {
|
||||
"valueInSat": "1000000000",
|
||||
"valueOutSat": "123456789",
|
||||
"feeSat": "10000",
|
||||
"remainderSat": "876533211",
|
||||
"hashToScriptMap": {
|
||||
"3QjgeBsNeiDkoVQxDAw4sSEe9BVaqhmpnd": "5321025c2951a7e94e39f2c3210fb2d71b7d79044f7daa6b007556a6feb4b2059091e921026c56eea4ef632b24c4efe9d5391ea0e15e306450e5b7db26cd1a7a33d9d4e82821026d06e532385186793121633fb365fa2f0c7246b30590db78cba795641c94734521035051d2b742263bc5257c5a4461e1a6fa32c3f1965f5ab5e8b0f0f80c9e28bc702103ddb0d39c1cd88295e7b81050dcab11ca4419bf64fba3ef9d9130ea64d6604ab055ae",
|
||||
"365dPtmHPAdUUNvPBcnfidYt2Snyaka7AH": "5321020faaf739abda51e822621d42062470c5743a127186369a67fd3303f71727fb1d210237063d3b27c21767054dad203298bfed90cb08dca371950a08b88aa979c33bd22102a3780cb275b6dcb8b379514679387d4578068745f08c5799e4ee1a90aa3a70922102f4fea0cd5bc2418892278f480682690857f4d963deeb95d88febfa255e4ce0b821035d53fa74fee26873c3f5a4acf4dce53ff9d50db59e1ca4acddb82168dd429a3355ae",
|
||||
"372DueknmmjVR3zcWfEfADp8FwJ3ARhGaN": "532102666c2873c9e6f58ca594cd6c8327a1515db32ebadbaff4fe75e63b917560b7d021031ca2d159ae8868a5eef6d67a5a8a5bcc6fb2e8b711669f1c1e8b05327236a3cf2103798a4ce34929cb450bf88557dd90cae538c67f9d0c76314ae18679200be9c17021039624dec23dc1bb628cea55e949ea26225949a3349346a0732fef9def6f1f75292103d1edaadb8555012b752dd7a5c6672c379ce827e4bc0d4e992ee1ab3488b445b255ae",
|
||||
"3GLJbHv7RqPeFk2SqWapqJ3XibVibiKi8f": "5321021a33d48b9f5d3adc41004709313277d4c6969268cf41e3f5b695a934c676829a21031b87321307db7a0f6ea22847a538505188f1a2231eba68867e17c5f0e4434c0721035dee0a6e1df66a6c9c7592ef03aa02bba9b06742134d27bd08f356e33f21259c2103768a109d682a76c09f865912e9e64a8689b03c1a231c613d87ec9bd535fd74c22103911038638b9fc52b2d375ce207c8388bd5ee7f2d54ab9b4148bd406c6d7dcad355ae",
|
||||
"3E1d1z7gJSFeZM2d3k12MJ1jGwrBRy1YTw": "5321027da98ce0407138461f4ad803a1fb67afa4246f06ad0e1256a087daeffd82a8642102e7f87f2b094ec322be2fb99d3ca81fd6ac0ab26ce081e51ab18c507f8b6d1d162102ed5d256036e10568c33e0a15021cc1806e04d7d24c8f020aaae23ec2deecb4302103b6f88231bb5a5f4629e4d097492321f86968c6aeb012196a1fe3b217fe4ae0ac2103f6b5e2c1db3124a5058a0e3e83d5d0c412b9a5b50e2ef97e2b7e1c0af57ab3e355ae",
|
||||
"3QYueyPXq2QDRQCDo7agTimz9673NKV25E": "5321021543292c2942708ccc83354ebf507044b310ed0d33a19e2327a49be53e0f314221024a1a83f8c50f6cad7c134b9cded509dabf196ae49eca157a39ad95798943dc95210292698fbb97e8f6e67296b22b36367ba85c8101fcbc27bb4b00b43623639212ac2102d86980796027a00ba7aa9b53671762c908962654f969f5dec340071bb30e8d7621038fb3fa5e77dafd24c09d819dbdc7c11dca55b350511bf3bc499c09316a89286e55ae",
|
||||
"372BzC1GGjziT8zGYbryja3kF2KaTeobRK": "53210214ec25e5cb42e51883d4e615316748feefe91133fcfc0f93f0b5a24a55e0a347210262336210b3173aa4ca90d292990f463e42bdeb2e73112925dc712c5a2e749bcb210277517855f512564f225e63c650dad7720565aa563901d50743be4b0f0267dcc72102d2777a9faf5d2e2b2363e1270d61021bc2e36e8cb19ca9d29dedbba9a0348b532103a57db80b6ae573e5cef2115e36e73e5ef41f8a099bfb5087d80320c04a7db72e55ae"
|
||||
},
|
||||
"selectedUtxos": [{
|
||||
"address": "3E1d1z7gJSFeZM2d3k12MJ1jGwrBRy1YTw",
|
||||
"scriptPubKey": "a91487264aa41e3df76f3156c7fa587fd7d5b1f7b96b87",
|
||||
"txid": "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1",
|
||||
"vout": 1,
|
||||
"amount": 10,
|
||||
"confirmations": 7
|
||||
rejectedBy: {},
|
||||
sentTs: null,
|
||||
sentTxid: null,
|
||||
inputChainPaths: ['m/45\'/2/0/0'],
|
||||
comment: null,
|
||||
builderObj: {
|
||||
version: 1,
|
||||
outs: [{
|
||||
address: '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||
amountSatStr: '123456789'
|
||||
}],
|
||||
"inputsSigned": 0,
|
||||
"signaturesAdded": 1,
|
||||
"signhash": 1,
|
||||
"spendUnconfirmed": false,
|
||||
"tx": "0100000001c1cf12ab89729d19d3cdec8ae531b5038d56c741006a105d532b3a7afa65c12a01000000fd40010047304402201aad0ea92f929be21d60afb741b76bfcf2aa9614079cb9da76b15b3a1210f07b02205bc5c1895105da3ee682e532d2d49dfd1214fa6123fb9c9d552336f135c77eff0147304402203f02f15bb4ad4bc7d0ca4612fd9e9ae05a1331f3d62f302cf08dba56695f5dcf0220700110562fe228ebba324b120de64a7bbaddf049d67a313f749e9b32ee88787d014cad5321027da98ce0407138461f4ad803a1fb67afa4246f06ad0e1256a087daeffd82a8642102e7f87f2b094ec322be2fb99d3ca81fd6ac0ab26ce081e51ab18c507f8b6d1d162102ed5d256036e10568c33e0a15021cc1806e04d7d24c8f020aaae23ec2deecb4302103b6f88231bb5a5f4629e4d097492321f86968c6aeb012196a1fe3b217fe4ae0ac2103f6b5e2c1db3124a5058a0e3e83d5d0c412b9a5b50e2ef97e2b7e1c0af57ab3e355aeffffffff0215cd5b07000000001976a91434f8e0c5be216025a52addf18a987543cad23f7a88acdbd53e340000000017a914a09f10bc42b61ecf9d3d09550765c228f1cb808a8700000000"
|
||||
utxos: [{
|
||||
address: '2N6fdPg2QL7V36XKe7a8wkkA5HCy7fNYmZF',
|
||||
scriptPubKey: 'a91493372782bab70f4eefdefefea8ece0df44f9596887',
|
||||
txid: '2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1',
|
||||
vout: 1,
|
||||
amount: 10,
|
||||
confirmations: 7
|
||||
}],
|
||||
opts: {
|
||||
remainderOut: {
|
||||
address: '2N7BLvdrxJ4YzDtb3hfgt6CMY5rrw5kNT1H'
|
||||
}
|
||||
},
|
||||
scriptSig: ['00493046022100b8249a4fc326c4c33882e9d5468a1c6faa01e8c6cef0a24970122e804abdd860022100dbf6ee3b07d3aad8f73997e62ad20654a08aa63a7609792d02f3d5d088e69ad9014cad5321027445ab3a935dce7aee1dadb0d103ed6147a0f83deb80474a04538b2c5bc4d5092102ab32ba51402a139873aeb919c738f5a945f3956f8f8c6ba296677bd29e85d7e821036f119b72e09f76c11ebe2cf754d64eac2cb42c9e623455d54aaa89d70c11f9c82103bcbd3f8ab2c849ea9eae434733cee8b75120d26233def56011b3682ca12081d72103f37f81dc534163b9f73ecf36b91e6c3fb8ae370c24618f91bb1d972e86ceeee255ae'],
|
||||
hashToScriptMap: {
|
||||
'2N6fdPg2QL7V36XKe7a8wkkA5HCy7fNYmZF': '5321027445ab3a935dce7aee1dadb0d103ed6147a0f83deb80474a04538b2c5bc4d5092102ab32ba51402a139873aeb919c738f5a945f3956f8f8c6ba296677bd29e85d7e821036f119b72e09f76c11ebe2cf754d64eac2cb42c9e623455d54aaa89d70c11f9c82103bcbd3f8ab2c849ea9eae434733cee8b75120d26233def56011b3682ca12081d72103f37f81dc534163b9f73ecf36b91e6c3fb8ae370c24618f91bb1d972e86ceeee255ae'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
w._handleTxProposal('senderID', txp, true);
|
||||
Object.keys(w.txProposals.txps).length.should.equal(1);
|
||||
w.getTxProposals().length.should.equal(1);
|
||||
|
@ -702,7 +704,7 @@ describe('Wallet model', function() {
|
|||
});
|
||||
|
||||
describe('#send', function() {
|
||||
it('should call this.network.send', function () {
|
||||
it('should call this.network.send', function() {
|
||||
var w = cachedCreateW2();
|
||||
var save = w.network.send;
|
||||
w.network.send = sinon.spy();
|
||||
|
@ -778,12 +780,14 @@ describe('Wallet model', function() {
|
|||
return index <= 14 && index % 2 == 0;
|
||||
});
|
||||
|
||||
var updateIndex = sinon.stub(w, 'updateIndex', function(i, cb) { cb(); });
|
||||
var updateIndex = sinon.stub(w, 'updateIndex', function(i, cb) {
|
||||
cb();
|
||||
});
|
||||
|
||||
w.updateIndexes(function(err) {
|
||||
// check updated all indexes
|
||||
var cosignersChecked = []
|
||||
updateIndex.args.forEach(function(i){
|
||||
updateIndex.args.forEach(function(i) {
|
||||
cosignersChecked.indexOf(i[0].cosigner).should.equal(-1);
|
||||
cosignersChecked.push(i[0].cosigner);
|
||||
});
|
||||
|
@ -800,7 +804,9 @@ describe('Wallet model', function() {
|
|||
});
|
||||
|
||||
|
||||
var indexDiscovery = sinon.stub(w, 'indexDiscovery', function(a, b, c, d, cb) { cb(null, 8); });
|
||||
var indexDiscovery = sinon.stub(w, 'indexDiscovery', function(a, b, c, d, cb) {
|
||||
cb(null, 8);
|
||||
});
|
||||
var index = {
|
||||
changeIndex: 1,
|
||||
receiveIndex: 2,
|
||||
|
@ -820,7 +826,9 @@ describe('Wallet model', function() {
|
|||
mockFakeActivity(function(index) {
|
||||
return index <= 14 && index % 2 == 0;
|
||||
});
|
||||
var indexDiscovery = sinon.stub(w, 'indexDiscovery', function(a, b, c, d, cb) { cb(null, 8); });
|
||||
var indexDiscovery = sinon.stub(w, 'indexDiscovery', function(a, b, c, d, cb) {
|
||||
cb(null, 8);
|
||||
});
|
||||
var spyStore = sinon.spy(w, 'store');
|
||||
w.updateIndexes(function(err) {
|
||||
sinon.assert.callCount(spyStore, 1);
|
||||
|
@ -886,7 +894,7 @@ describe('Wallet model', function() {
|
|||
var data = {
|
||||
type: "addressbook",
|
||||
addressBook: {
|
||||
"3Ae1ieAYNXznm7NkowoFTu5MkzgrTfDz8Z" : {
|
||||
"3Ae1ieAYNXznm7NkowoFTu5MkzgrTfDz8Z": {
|
||||
copayerId: "03baa45498fee1045fa8f91a2913f638dc3979b455498924d3cf1a11303c679cdb",
|
||||
createdTs: 1404769393509,
|
||||
hidden: false,
|
||||
|
@ -1005,4 +1013,80 @@ describe('Wallet model', function() {
|
|||
copayConfig.forceNetwork = backup;
|
||||
});
|
||||
});
|
||||
|
||||
describe('validate txProposals', function() {
|
||||
var a1 = 'n1pKARYYUnZwxBuGj3y7WqVDu6VLN7n971';
|
||||
var a2 = 'mtxYYJXZJmQc2iJRHQ4RZkfxU5K7TE2qMJ';
|
||||
var utxos = [{
|
||||
address: a1,
|
||||
txid: '2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1',
|
||||
vout: 1,
|
||||
scriptPubKey: Address.getScriptPubKeyFor(a1).serialize().toString('hex'),
|
||||
amount: 0.5,
|
||||
confirmations: 200
|
||||
}, {
|
||||
address: a2,
|
||||
txid: '88c4520ffd97ea565578afe0b40919120be704b36561c71ba4e450e83cb3c9fd',
|
||||
vout: 1,
|
||||
scriptPubKey: Address.getScriptPubKeyFor(a2).serialize().toString('hex'),
|
||||
amount: 0.5001,
|
||||
confirmations: 200
|
||||
}];
|
||||
var destAddress = 'myuAQcCc1REUgXGsCTiYhZvPPc3XxZ36G1';
|
||||
var outs = [{
|
||||
address: destAddress,
|
||||
amount: 1.0
|
||||
}];
|
||||
|
||||
var testValidate = function(signhash, result, done) {
|
||||
var w = cachedCreateW();
|
||||
var spy = sinon.spy();
|
||||
w.on('txProposalEvent', spy);
|
||||
w.on('txProposalEvent', function(e) {
|
||||
e.type.should.equal(result);
|
||||
done();
|
||||
});
|
||||
var opts = {};
|
||||
opts.signhash = signhash;
|
||||
var txb = new TransactionBuilder(opts)
|
||||
.setUnspent(utxos)
|
||||
.setOutputs(outs)
|
||||
.sign(['cVBtNonMyTydnS3NnZyipbduXo9KZfF1aUZ3uQHcvJB6UARZbiWG',
|
||||
'cRVF68hhZp1PUQCdjr2k6aVYb2cn6uabbySDPBizAJ3PXF7vDXTL'
|
||||
]);
|
||||
var txp = {
|
||||
'txProposal': {
|
||||
'builderObj': txb.toObj()
|
||||
}
|
||||
};
|
||||
w._handleTxProposal('senderID', txp, true);
|
||||
spy.callCount.should.equal(1);
|
||||
};
|
||||
|
||||
it('should validate for undefined', function(done) {
|
||||
var result = 'new';
|
||||
var signhash;
|
||||
testValidate(signhash, result, done);
|
||||
});
|
||||
it('should validate for SIGHASH_ALL', function(done) {
|
||||
var result = 'new';
|
||||
var signhash = Transaction.SIGHASH_ALL;
|
||||
testValidate(signhash, result, done);
|
||||
});
|
||||
it('should not validate for different SIGHASH_NONE', function(done) {
|
||||
var result = 'corrupt';
|
||||
var signhash = Transaction.SIGHASH_NONE;
|
||||
testValidate(signhash, result, done);
|
||||
});
|
||||
it('should not validate for different SIGHASH_SINGLE', function(done) {
|
||||
var result = 'corrupt';
|
||||
var signhash = Transaction.SIGHASH_SINGLE;
|
||||
testValidate(signhash, result, done);
|
||||
});
|
||||
it('should not validate for different SIGHASH_ANYONECANPAY', function(done) {
|
||||
var result = 'corrupt';
|
||||
var signhash = Transaction.SIGHASH_ANYONECANPAY;
|
||||
testValidate(signhash, result, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -180,25 +180,25 @@ describe("Unit: Testing Directives", function() {
|
|||
it('should check very weak password', function() {
|
||||
$scope.password = 'asd';
|
||||
$scope.$digest();
|
||||
expect($scope.passwordStrength).to.equal('very weak');
|
||||
expect($scope.passwordStrength).to.equal('Very Weak, that\'s short');
|
||||
});
|
||||
|
||||
it('should check weak password', function() {
|
||||
$scope.password = 'asdasdASDASD';
|
||||
$scope.$digest();
|
||||
expect($scope.passwordStrength).to.equal('weak');
|
||||
expect($scope.passwordStrength).to.equal('Weak, add numerals');
|
||||
});
|
||||
|
||||
it('should check medium password', function() {
|
||||
$scope.password = 'asdasdASDASD1';
|
||||
$scope.password = 'asdasdA1';
|
||||
$scope.$digest();
|
||||
expect($scope.passwordStrength).to.equal('medium');
|
||||
expect($scope.passwordStrength).to.equal('Medium, add punctuation');
|
||||
});
|
||||
|
||||
it('should check strong password', function() {
|
||||
$scope.password = 'asdasdASDASD1{';
|
||||
$scope.$digest();
|
||||
expect($scope.passwordStrength).to.equal('strong');
|
||||
expect($scope.passwordStrength).to.equal('Strong, add punctuation');
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -80,26 +80,26 @@ describe('Unit: Testing Filters', function() {
|
|||
expect(removeEmpty(undefined).length).to.equal(0);
|
||||
}));
|
||||
|
||||
it('should filter empty addresses from other copayers', inject(function($filter) {
|
||||
it('should filter empty change addresses from other copayers', inject(function($filter) {
|
||||
var removeEmpty = $filter('removeEmpty');
|
||||
var addresses = [{
|
||||
owned: true,
|
||||
isChange: false,
|
||||
balance: 0
|
||||
}, {
|
||||
owned: false,
|
||||
isChange: false,
|
||||
balance: 0
|
||||
}, {
|
||||
owned: true,
|
||||
isChange: true,
|
||||
balance: 0
|
||||
}, {
|
||||
owned: false,
|
||||
isChange: true,
|
||||
balance: 0
|
||||
}];
|
||||
expect(removeEmpty(addresses).length).to.equal(2);
|
||||
addresses[1].owned = true;
|
||||
expect(removeEmpty(addresses).length).to.equal(3);
|
||||
addresses[3].balance = 10;
|
||||
expect(removeEmpty(addresses).length).to.equal(4);
|
||||
}));
|
||||
});
|
||||
|
||||
|
|