diff --git a/.gitignore b/.gitignore
index d6ef6fa6c..21dea94db 100644
--- a/.gitignore
+++ b/.gitignore
@@ -118,3 +118,7 @@ cordova/ios/splash/
cordova/ios/icons/
cordova/project/
+## Firebase
+GoogleService-Info.plist
+google-services.json
+
diff --git a/app-template/bitpay/appConfig.json b/app-template/bitpay/appConfig.json
index 03a14ea5c..5c3b9d67d 100644
--- a/app-template/bitpay/appConfig.json
+++ b/app-template/bitpay/appConfig.json
@@ -1,6 +1,7 @@
{
"packageName": "bitpay",
"packageDescription": "Secure Bitcoin Wallet",
+ "packageNameId": "com.bitpay.wallet",
"userVisibleName": "BitPay",
"purposeLine": "Secure Bitcoin Wallet",
"bundleName": "wallet",
diff --git a/app-template/config-template.xml b/app-template/config-template.xml
index 1f179776b..e984f2e8d 100644
--- a/app-template/config-template.xml
+++ b/app-template/config-template.xml
@@ -61,12 +61,11 @@
-
-
-
+
+
diff --git a/app-template/copay/appConfig.json b/app-template/copay/appConfig.json
index 037713a3f..dacdf9c65 100644
--- a/app-template/copay/appConfig.json
+++ b/app-template/copay/appConfig.json
@@ -1,6 +1,7 @@
{
"packageName": "copay",
"packageDescription": "Copay Bitcoin Wallet",
+ "packageNameId": "com.bitpay.copay",
"userVisibleName": "Copay",
"purposeLine": "Copay Bitcoin Wallet",
"bundleName": "copay",
diff --git a/src/js/controllers/advancedSettings.js b/src/js/controllers/advancedSettings.js
index 0664a0804..c5cd65103 100644
--- a/src/js/controllers/advancedSettings.js
+++ b/src/js/controllers/advancedSettings.js
@@ -1,6 +1,6 @@
'use strict';
-angular.module('copayApp.controllers').controller('advancedSettingsController', function($scope, $rootScope, $log, $window, lodash, configService, uxLanguage, platformInfo, pushNotificationsService, profileService, feeService, storageService, $ionicHistory, $timeout, $ionicScrollDelegate) {
+angular.module('copayApp.controllers').controller('advancedSettingsController', function($scope, $rootScope, $log, $window, lodash, configService, uxLanguage, platformInfo, profileService, feeService, storageService, $ionicHistory, $timeout, $ionicScrollDelegate) {
var updateConfig = function() {
var config = configService.getSync();
diff --git a/src/js/controllers/onboarding/collectEmail.js b/src/js/controllers/onboarding/collectEmail.js
index be1cafd24..7a23da915 100644
--- a/src/js/controllers/onboarding/collectEmail.js
+++ b/src/js/controllers/onboarding/collectEmail.js
@@ -1,6 +1,6 @@
'use strict';
-angular.module('copayApp.controllers').controller('collectEmailController', function($scope, $state, $timeout, $stateParams, $ionicConfig, profileService, configService, walletService, platformInfo) {
+angular.module('copayApp.controllers').controller('collectEmailController', function($scope, $state, $timeout, $stateParams, $ionicConfig, profileService, configService, walletService, platformInfo, pushNotificationsService) {
$scope.$on("$ionicView.beforeLeave", function() {
$ionicConfig.views.swipeBackEnabled(true);
@@ -46,7 +46,7 @@ angular.module('copayApp.controllers').controller('collectEmailController', func
walletId: walletId
});
} else {
- profileService.pushNotificationsInit();
+ pushNotificationsService.init();
$state.go('onboarding.backupRequest', {
walletId: walletId
});
diff --git a/src/js/controllers/onboarding/notifications.js b/src/js/controllers/onboarding/notifications.js
index e42d37ac1..c4554c84b 100644
--- a/src/js/controllers/onboarding/notifications.js
+++ b/src/js/controllers/onboarding/notifications.js
@@ -1,6 +1,6 @@
'use strict';
-angular.module('copayApp.controllers').controller('notificationsController', function($scope, $state, $timeout, $stateParams, $ionicConfig, profileService, configService, $interval) {
+angular.module('copayApp.controllers').controller('notificationsController', function($scope, $state, $timeout, $stateParams, $ionicConfig, profileService, configService, $interval, pushNotificationsService) {
$scope.$on("$ionicView.enter", function() {
$ionicConfig.views.swipeBackEnabled(false);
@@ -15,7 +15,7 @@ angular.module('copayApp.controllers').controller('notificationsController', fun
$scope.allowNotif = function() {
$scope.notificationDialogOpen = true;
$timeout(function() {
- profileService.pushNotificationsInit();
+ pushNotificationsService.init();
});
$scope.notificationPromise = $interval(function() {
PushNotification.hasPermission(function(data) {
diff --git a/src/js/controllers/preferencesDelete.js b/src/js/controllers/preferencesDelete.js
index 442cb7b0d..21c1d1c64 100644
--- a/src/js/controllers/preferencesDelete.js
+++ b/src/js/controllers/preferencesDelete.js
@@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('preferencesDeleteWalletController',
- function($scope, $ionicHistory, gettextCatalog, lodash, profileService, $state, ongoingProcess, popupService) {
+ function($scope, $ionicHistory, gettextCatalog, lodash, profileService, $state, ongoingProcess, popupService, pushNotificationsService) {
$scope.$on("$ionicView.beforeEnter", function(event, data) {
if (!data.stateParams || !data.stateParams.walletId) {
@@ -36,6 +36,7 @@ angular.module('copayApp.controllers').controller('preferencesDeleteWalletContro
if (err) {
popupService.showAlert(gettextCatalog.getString('Error'), err.message || err);
} else {
+ pushNotificationsService.unsubscribe($scope.wallet);
$ionicHistory.nextViewOptions({
disableAnimate: true,
historyRoot: true
diff --git a/src/js/controllers/preferencesNotifications.js b/src/js/controllers/preferencesNotifications.js
index 219ad82cd..c2726cbae 100644
--- a/src/js/controllers/preferencesNotifications.js
+++ b/src/js/controllers/preferencesNotifications.js
@@ -9,7 +9,7 @@ angular.module('copayApp.controllers').controller('preferencesNotificationsContr
$scope.isIOSApp = platformInfo.isIOS && platformInfo.isCordova;
$scope.pushNotifications = {
- value: config.pushNotifications.enabled
+ value: config.pushNotificationsEnabled
};
$scope.latestEmail = {
@@ -31,16 +31,14 @@ angular.module('copayApp.controllers').controller('preferencesNotificationsContr
$scope.pushNotificationsChange = function() {
if (!$scope.pushNotifications) return;
var opts = {
- pushNotifications: {
- enabled: $scope.pushNotifications.value
- }
+ pushNotificationsEnabled: $scope.pushNotifications.value
};
configService.set(opts, function(err) {
- if (opts.pushNotifications.enabled)
- profileService.pushNotificationsInit();
- else
- pushNotificationsService.disableNotifications(profileService.getWallets());
if (err) $log.debug(err);
+ if (opts.pushNotificationsEnabled)
+ pushNotificationsService.init();
+ else
+ pushNotificationsService.disable();
});
};
diff --git a/src/js/controllers/tab-home.js b/src/js/controllers/tab-home.js
index d3d6e9610..7a3fd83f8 100644
--- a/src/js/controllers/tab-home.js
+++ b/src/js/controllers/tab-home.js
@@ -1,7 +1,7 @@
'use strict';
angular.module('copayApp.controllers').controller('tabHomeController',
- function($rootScope, $timeout, $scope, $state, $stateParams, $ionicModal, $ionicScrollDelegate, $window, gettextCatalog, lodash, popupService, ongoingProcess, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, storageService, txpModalService, appConfigService, startupService, addressbookService, feedbackService, bwcError, nextStepsService, buyAndSellService, homeIntegrationsService, bitpayCardService) {
+ function($rootScope, $timeout, $scope, $state, $stateParams, $ionicModal, $ionicScrollDelegate, $window, gettextCatalog, lodash, popupService, ongoingProcess, externalLinkService, latestReleaseService, profileService, walletService, configService, $log, platformInfo, storageService, txpModalService, appConfigService, startupService, addressbookService, feedbackService, bwcError, nextStepsService, buyAndSellService, homeIntegrationsService, bitpayCardService, pushNotificationsService) {
var wallet;
var listeners = [];
var notifications = [];
@@ -105,8 +105,7 @@ angular.module('copayApp.controllers').controller('tabHomeController',
$scope.bitpayCardItems = cards;
});
- configService.whenAvailable(function() {
- var config = configService.getSync();
+ configService.whenAvailable(function(config) {
$scope.recentTransactionsEnabled = config.recentTransactions.enabled;
if ($scope.recentTransactionsEnabled) getNotifications();
@@ -116,6 +115,8 @@ angular.module('copayApp.controllers').controller('tabHomeController',
$scope.nextStepsItems = nextStepsService.get();
}
+ pushNotificationsService.init();
+
$timeout(function() {
$ionicScrollDelegate.resize();
$scope.$apply();
diff --git a/src/js/services/configService.js b/src/js/services/configService.js
index 9e447f7b9..cfc6ad4ac 100644
--- a/src/js/services/configService.js
+++ b/src/js/services/configService.js
@@ -59,22 +59,7 @@ angular.module('copayApp.services').factory('configService', function(storageSer
url: 'https://api.github.com/repos/bitpay/copay/releases/latest'
},
- pushNotifications: {
- enabled: true,
- config: {
- android: {
- senderID: '1036948132229',
- icon: 'push',
- iconColor: '#2F4053'
- },
- ios: {
- alert: 'true',
- badge: 'true',
- sound: 'true',
- },
- windows: {},
- }
- },
+ pushNotificationsEnabled: true,
emailNotifications: {
enabled: false,
diff --git a/src/js/services/profileService.js b/src/js/services/profileService.js
index d6ddc45c3..ae2d970b2 100644
--- a/src/js/services/profileService.js
+++ b/src/js/services/profileService.js
@@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.services')
- .factory('profileService', function profileServiceFactory($rootScope, $timeout, $filter, $log, sjcl, lodash, storageService, bwcService, configService, pushNotificationsService, gettextCatalog, bwcError, uxLanguage, platformInfo, txFormatService, $state) {
+ .factory('profileService', function profileServiceFactory($rootScope, $timeout, $filter, $log, sjcl, lodash, storageService, bwcService, configService, gettextCatalog, bwcError, uxLanguage, platformInfo, txFormatService, $state) {
var isChromeApp = platformInfo.isChromeApp;
@@ -274,9 +274,6 @@ angular.module('copayApp.services')
if (!val) {
return cb(new Error('NONAGREEDDISCLAIMER: Non agreed disclaimer'));
}
- var config = configService.getSync();
- if (config.pushNotifications.enabled && usePushNotifications)
- root.pushNotificationsInit();
return cb();
});
});
@@ -292,35 +289,6 @@ angular.module('copayApp.services')
return cb();
};
- root.pushNotificationsInit = function() {
- var defaults = configService.getDefaults();
- var push = pushNotificationsService.init(root.wallet);
-
- if (!push) return;
-
- push.on('notification', function(data) {
- if (!data.additionalData.foreground) {
- $log.debug('Push notification event: ', data.message);
-
- $timeout(function() {
- var wallets = root.getWallets();
- var walletToFind = data.additionalData.walletId;
-
- var walletFound = lodash.find(wallets, function(w) {
- return (lodash.isEqual(walletToFind, sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(w.id))));
- });
-
- if (!walletFound) return $log.debug('Wallet not found');
- }, 100);
- }
- });
-
- push.on('error', function(e) {
- $log.warn('Error with push notifications:' + e.message);
- });
-
- };
-
root.loadAndBindProfile = function(cb) {
storageService.getProfile(function(err, profile) {
if (err) {
@@ -481,11 +449,6 @@ angular.module('copayApp.services')
var walletId = client.credentials.walletId;
var config = configService.getSync();
- if (config.pushNotifications.enabled)
- pushNotificationsService.unsubscribe(root.getWallet(walletId), function(err) {
- if (err) $log.warn('Unsubscription error: ' + err.message);
- else $log.debug('Unsubscribed from push notifications service');
- });
$log.debug('Deleting Wallet:', client.credentials.walletName);
client.removeAllListeners();
@@ -556,9 +519,6 @@ angular.module('copayApp.services')
saveBwsUrl(function() {
storageService.storeProfile(root.profile, function(err) {
- var config = configService.getSync();
- if (config.pushNotifications.enabled)
- pushNotificationsService.enableNotifications(root.wallet);
return cb(err, client);
});
});
diff --git a/src/js/services/pushNotificationsService.js b/src/js/services/pushNotificationsService.js
index 904ae4246..63090faae 100644
--- a/src/js/services/pushNotificationsService.js
+++ b/src/js/services/pushNotificationsService.js
@@ -1,87 +1,123 @@
'use strict';
-angular.module('copayApp.services')
- .factory('pushNotificationsService', function($log, platformInfo, storageService, configService, lodash) {
- var root = {};
- var isCordova = platformInfo.isCordova;
- var isWP = platformInfo.isWP;
- var isIOS = platformInfo.isIOS;
- var isAndroid = platformInfo.isAndroid;
+angular.module('copayApp.services').factory('pushNotificationsService', function pushNotificationsService($log, $state, $ionicHistory, platformInfo, lodash, appConfigService, profileService, configService) {
+ var root = {};
+ var isIOS = platformInfo.isIOS;
+ var isAndroid = platformInfo.isAndroid;
+ var usePushNotifications = platformInfo.isCordova && !platformInfo.isWP;
- var usePushNotifications = isCordova && !isWP;
+ var _token = null;
- root.init = function(walletsClients) {
- var defaults = configService.getDefaults();
- try {
- var push = PushNotification.init(defaults.pushNotifications.config);
- } catch(e) {
- $log.error(e);
- return;
- };
+ root.init = function() {
+ if (!usePushNotifications || _token) return;
+ configService.whenAvailable(function(config) {
+ if (!config.pushNotificationsEnabled) return;
+
+ $log.debug('Starting push notification registration...');
- push.on('registration', function(data) {
- $log.debug('Starting push notification registration');
- root.token = data.registrationId;
- var config = configService.getSync();
- if (config.pushNotifications.enabled) root.enableNotifications(walletsClients);
- });
+ //Keep in mind the function will return null if the token has not been established yet.
+ FCMPlugin.getToken(function(token) {
+ $log.debug('Get token for push notifications...');
+ _token = token;
+ root.enable();
+ });
+ });
+ };
- return push;
+ root.enable = function() {
+ if (!_token) {
+ $log.warn('No token available for this device. Cannot set push notifications. Needs registration.');
+ return;
}
- root.enableNotifications = function(walletsClients) {
- if (!usePushNotifications) return;
+ var wallets = profileService.getWallets();
+ lodash.forEach(wallets, function(walletClient) {
+ _subscribe(walletClient);
+ });
+ };
- var config = configService.getSync();
- if (!config.pushNotifications.enabled) return;
+ root.disable = function() {
+ if (!_token) {
+ $log.warn('No token available for this device. Cannot disable push notifications.');
+ return;
+ }
- if (!root.token) {
- $log.warn('No token available for this device. Cannot set push notifications. Needs registration.');
- return;
+ var wallets = profileService.getWallets();
+ lodash.forEach(wallets, function(walletClient) {
+ _unsubscribe(walletClient);
+ });
+ _token = null;
+ };
+
+ root.unsubscribe = function(walletClient) {
+ if (!_token) return;
+ _unsubscribe(walletClient);
+ };
+
+ var _subscribe = function(walletClient) {
+ var opts = {
+ token : _token,
+ platform: isIOS ? 'ios' : isAndroid ? 'android' : null,
+ packageName : appConfigService.packageNameId
+ };
+ walletClient.pushNotificationsSubscribe(opts, function(err) {
+ if (err) $log.error(walletClient.name + ': Subscription Push Notifications error. ', JSON.stringify(err));
+ else $log.debug(walletClient.name + ': Subscription Push Notifications success.');
+ });
+ };
+
+ var _unsubscribe = function(walletClient, cb) {
+ walletClient.pushNotificationsUnsubscribe(_token, function(err) {
+ if (err) $log.error(walletClient.name + ': Unsubscription Push Notifications error. ', JSON.stringify(err));
+ else $log.debug(walletClient.name + ': Unsubscription Push Notifications Success.');
+ });
+ };
+
+ var _openWallet = function(walletId) {
+ var wallet = profileService.getWallet(walletId);
+ if (!wallet) return;
+ if (!wallet.isComplete()) {
+ return $state.go('tabs.copayers', {
+ walletId: walletId
+ });
+ }
+
+ $state.go('tabs.wallet', {
+ walletId: walletId
+ });
+ };
+
+ if (usePushNotifications) {
+
+ FCMPlugin.onTokenRefresh(function(token) {
+ if (!_token) return;
+ $log.debug('Refresh and update token for push notifications...');
+ _token = token;
+ root.enable();
+ });
+
+ FCMPlugin.onNotification(function(data) {
+ if (!_token) return;
+ $log.debug('New Event Push onNotification: ' + JSON.stringify(data));
+ var walletId, copayerId;
+ if(data.wasTapped) {
+ // Notification was received on device tray and tapped by the user.
+ var walletId = data ? data.walletId : null;
+ if (!walletId) return;
+ $ionicHistory.nextViewOptions({
+ disableAnimate: true,
+ historyRoot: true
+ });
+ $ionicHistory.clearHistory();
+ $state.go('tabs.home').then(function() {
+ _openWallet(walletId);
+ });
+ } else {
+ // TODO
+ // Notification was received in foreground. Maybe the user needs to be notified.
}
+ });
+ }
- lodash.forEach(walletsClients, function(walletClient) {
- var opts = {};
- opts.type = isIOS ? "ios" : isAndroid ? "android" : null;
- opts.token = root.token;
- root.subscribe(opts, walletClient, function(err, response) {
- if (err) $log.warn('Subscription error: ' + err.message + ': ' + JSON.stringify(opts));
- else $log.debug('Subscribed to push notifications service: ' + JSON.stringify(response));
- });
- });
- }
+ return root;
- root.disableNotifications = function(walletsClients) {
- if (!usePushNotifications) return;
-
- lodash.forEach(walletsClients, function(walletClient) {
- root.unsubscribe(walletClient, function(err) {
- if (err) $log.warn('Unsubscription error: ' + err.message);
- else $log.debug('Unsubscribed from push notifications service');
- });
- });
- }
-
- root.subscribe = function(opts, walletClient, cb) {
- if (!usePushNotifications) return cb();
-
- var config = configService.getSync();
- if (!config.pushNotifications.enabled) return;
-
- walletClient.pushNotificationsSubscribe(opts, function(err, resp) {
- if (err) return cb(err);
- return cb(null, resp);
- });
- }
-
- root.unsubscribe = function(walletClient, cb) {
- if (!usePushNotifications) return cb();
-
- walletClient.pushNotificationsUnsubscribe(function(err) {
- if (err) return cb(err);
- return cb(null);
- });
- }
-
- return root;
-
- });
+});