arnaucube
arnaucube/commonroutesAppPublic Self-hosted repository
commonroutesApp/www/lib/ngCordova/dist/ng-cordova-mocks.js
www/lib/ngCordova/dist/ng-cordova-mocks.jsRaw
   1/*!
   2 * ngCordova
   3 * v0.1.27-alpha
   4 * Copyright 2015 Drifty Co. http://drifty.com/
   5 * See LICENSE in this repository for license information
   6 */
   7(function(){
   8var ngCordovaMocks = angular.module('ngCordovaMocks', []);
   9/**
  10 * @ngdoc service
  11 * @name ngCordovaMocks.cordovaActionSheet
  12 *
  13 * @description
  14 * A service for testing action sheet
  15 * in an app build with ngCordova.
  16 **/
  17ngCordovaMocks.factory('$cordovaActionSheet', ['$q', function ($q) {
  18  var throwsError = false;
  19
  20	return {
  21		/**
  22		 * @ngdoc property
  23		 * @name throwsError
  24		 * @propertyOf ngCordovaMocks.cordovaActionSheet
  25		 * @type Boolean
  26		 *
  27		 * @description
  28		 * A flag that signals whether a promise should be rejected.
  29		 * This property should only be used in automated tests
  30		 */
  31		throwsError: throwsError,
  32
  33		show: function () {
  34			var defer = $q.defer();
  35
  36			if (this.throwsError) {
  37				defer.reject('There was an error on showing action sheet');
  38			} else {
  39				defer.resolve();
  40			}
  41
  42			return defer.promise;
  43		}
  44	};
  45}]);
  46
  47ngCordovaMocks.factory('$cordovaAppVersion', ['$q', function ($q) {
  48  var throwsError = false;
  49  return {
  50    throwsError: throwsError,
  51
  52    getAppName: function () {
  53      var q = $q.defer();
  54      q.resolve('mock app name');
  55      return q.promise;
  56    },
  57
  58    getPackageName: function () {
  59      var q = $q.defer();
  60      q.resolve('com.package.mock');
  61      return q.promise;
  62    },
  63
  64    getVersionNumber: function () {
  65      var q = $q.defer();
  66      q.resolve('1.2.3');
  67      return q.promise;
  68    },
  69
  70    getVersionCode: function () {
  71      var q = $q.defer();
  72      q.resolve('4.5.6');
  73      return q.promise;
  74    }
  75  };
  76}]);
  77
  78/**
  79 * @ngdoc service
  80 * @name ngCordovaMocks.cordovaBarcodeScanner
  81 *
  82 * @description
  83 * A service for testing barcode scanner features
  84 * in an app build with ngCordova.
  85 **/
  86ngCordovaMocks.factory('$cordovaBarcodeScanner', ['$q', function ($q) {
  87  var throwsError = false;
  88
  89  var scannedText = '';
  90  var scannedFormat = '';
  91  var wasCancelled = false;
  92
  93  return {
  94    /**
  95     * @ngdoc property
  96     * @name throwsError
  97     * @propertyOf ngCordovaMocks.cordovaBarcodeScanner
  98     *
  99     * @description
 100     * A flag that signals whether a promise should be rejected or not.
 101     * This property should only be used in automated tests.
 102     **/
 103    throwsError: throwsError,
 104
 105    /**
 106     * @ngdoc property
 107     * @name scannedText
 108     * @propertyOf ngCordovaMocks.cordovaBarcodeScanner
 109     *
 110     * @description
 111     * Used to simulate the result.text property of a
 112     * successful scan. For more information, see the text at
 113     * https://github.com/wildabeast/BarcodeScanner/#using-the-plugin
 114     * This property should only be used in automated tests.
 115     **/
 116    scannedText: scannedText,
 117
 118    /**
 119     * @ngdoc property
 120     * @name scannedFormat
 121     * @propertyOf ngCordovaMocks.cordovaBarcodeScanner
 122     * @description
 123     * Used to simulate the result.format property of a
 124     * successful scan. For more information, see the text at
 125     * https://github.com/wildabeast/BarcodeScanner/#using-the-plugin
 126     * This property should only be used in automated tests.
 127     **/
 128    scannedFormat: scannedFormat,
 129
 130    /**
 131     * @ngdoc property
 132     * @name wasCancelled
 133     * @propertyOf ngCordovaMocks.cordovaBarcodeScanner
 134     *
 135     * @description
 136     * Used to simulate the result.cancelled property of a
 137     * successful scan. For more information, see the text at
 138     * https://github.com/wildabeast/BarcodeScanner/#using-the-plugin
 139     * This property should only be used in automated tests.
 140     **/
 141    wasCancelled: wasCancelled,
 142
 143    scan: function () {
 144      var defer = $q.defer();
 145      if (this.throwsError) {
 146        defer.reject('There was an error scanning.');
 147      } else {
 148        defer.resolve({text: this.scannedText, format: this.scannedFormat, cancelled: this.wasCancelled});
 149      }
 150
 151      return defer.promise;
 152    },
 153
 154    encode: function (type, data) {
 155      this.scannedFormat = type;
 156      this.scannedText = data;
 157
 158      var defer = $q.defer();
 159      if (this.throwsError) {
 160        defer.reject('There was an error encoding the data.');
 161      } else {
 162        defer.resolve();
 163      }
 164
 165      return defer.promise;
 166    }
 167  };
 168}]);
 169
 170/**
 171 * @ngdoc service
 172 * @name ngCordovaMocks.cordovaBLE
 173 *
 174 * @description
 175 * A service for ble features
 176 * in an app build with ngCordova.
 177 **/
 178ngCordovaMocks.factory('$cordovaBLE', ['$q', '$timeout', '$interval', '$log', function ($q, $timeout, $interval, $log) {
 179  var deviceScan = {
 180    name: 'Test Device',
 181    id: 'AA:BB:CC:DD:EE:FF',
 182    advertising: [2, 1, 6, 3, 3, 15, 24, 8, 9, 66, 97, 116, 116, 101, 114, 121],
 183    rssi: -55
 184  };
 185
 186  var deviceConnect = {
 187    name: 'Test Device',
 188    id: 'AA:BB:CC:DD:EE:FF',
 189    advertising: [2, 1, 6, 3, 3, 15, 24, 8, 9, 66, 97, 116, 116, 101, 114, 121],
 190    rssi: -55,
 191    services: [
 192      '1800',
 193      '1801',
 194      '180f'
 195    ],
 196    characteristics: [
 197      {
 198        service: '1800',
 199        characteristic: '2a00',
 200        properties: ['Read']
 201      },
 202      {
 203        service: '1800',
 204        characteristic: '2a01',
 205        properties: ['Read']
 206      },
 207      {
 208        service: '1801',
 209        characteristic: '2a05',
 210        properties: ['Read']
 211      },
 212      {
 213        service: '180f',
 214        characteristic: '2a19',
 215        properties: ['Read'],
 216        descriptors: [{'uuid': '2901'}, {'uuid': '2904'}]
 217      }
 218    ]
 219  };
 220
 221  var readData = new ArrayBuffer(8);
 222
 223  return {
 224
 225    scan: function (services, seconds) {
 226      var q = $q.defer();
 227
 228      // first notify about discovered device
 229      $timeout(function () {
 230        q.notify(deviceScan);
 231      }, Math.round(seconds * 1000 * Math.random()));
 232
 233      // end scan
 234      $timeout(function () {
 235        q.resolve();
 236      }, seconds * 1000);
 237
 238      return q.promise;
 239    },
 240
 241    startScan: function (services, callback, errorCallback) {
 242      $timeout(function () {
 243        callback(deviceScan);
 244      }, Math.round(1000 * Math.random()));
 245    },
 246
 247    stopScan: function () {
 248      var q = $q.defer();
 249      $timeout(function () {
 250        q.resolve();
 251      }, 500);
 252      return q.promise;
 253    },
 254
 255    connect: function (deviceID) {
 256      var q = $q.defer();
 257      $timeout(function () {
 258        q.resolve(deviceConnect);
 259      }, 1500);
 260      return q.promise;
 261    },
 262
 263    disconnect: function (deviceID) {
 264      var q = $q.defer();
 265      $timeout(function () {
 266        q.resolve(true);
 267      }, 500);
 268      return q.promise;
 269    },
 270
 271    read: function (deviceID, serviceUUID, characteristicUUID) {
 272      var q = $q.defer();
 273      $timeout(function () {
 274        q.resolve(readData);
 275      }, 100);
 276      return q.promise;
 277    },
 278
 279    write: function (deviceID, serviceUUID, characteristicUUID, data) {
 280      var q = $q.defer();
 281      $timeout(function () {
 282        q.resolve(true);
 283      }, 100);
 284      return q.promise;
 285    },
 286
 287    writeWithoutResponse: function (deviceID, serviceUUID, characteristicUUID, data) {
 288      var q = $q.defer();
 289      $timeout(function () {
 290        q.resolve(true);
 291      }, 100);
 292      return q.promise;
 293    },
 294
 295    writeCommand: function (deviceID, serviceUUID, characteristicUUID, data) {
 296      $log.warning('writeCommand is deprecated, use writeWithoutResponse');
 297      return this.writeWithoutResponse(deviceID, serviceUUID, characteristicUUID, data);
 298    },
 299
 300    startNotification: function (deviceID, serviceUUID, characteristicUUID, callback, errorCallback) {
 301      $interval(function () {
 302        var data = new Uint8Array([Math.round(255 * Math.random())]); // one byte with random number
 303        callback(data);
 304      }, 200, 10); // repeat 10 times with 200 ms delay for each
 305    },
 306
 307    stopNotification: function (deviceID, serviceUUID, characteristicUUID) {
 308      var q = $q.defer();
 309      $timeout(function () {
 310        q.resolve();
 311      }, 100);
 312      return q.promise;
 313    },
 314
 315    isConnected: function (deviceID) {
 316      var q = $q.defer();
 317      q.resolve(true);
 318      return q.promise;
 319    },
 320
 321    enable: function () {
 322      var q = $q.defer();
 323      $timeout(function () {
 324        q.resolve();
 325      }, 1500);
 326      return q.promise;
 327    },
 328
 329    isEnabled: function () {
 330      var q = $q.defer();
 331      q.resolve(true);
 332      return q.promise;
 333    }
 334  };
 335}]);
 336
 337ngCordovaMocks.factory('$cordovaBrightness', ['$q', function ($q) {
 338	var currentBrightness = 100;
 339
 340	return {
 341		get: function () {
 342			var q = $q.defer();
 343			q.resolve(currentBrightness);
 344        	return q.promise;
 345		},
 346
 347		set: function (data) {
 348			var q = $q.defer();
 349			currentBrightness = data;
 350			q.resolve('OK');
 351        	return q.promise;
 352		},
 353
 354		setKeepScreenOn: function (bool) {
 355			var q = $q.defer();
 356			q.resolve('OK');
 357			return q.promise;
 358		}
 359	};
 360}]);
 361/**
 362 * @ngdoc service
 363 * @name ngCordovaMocks.cordovaCamera
 364 *
 365 * @description
 366 * A service for testing camera features
 367 * in an app build with ngCordova.
 368 **/
 369ngCordovaMocks.factory('$cordovaCamera', ['$q', function ($q) {
 370  var throwsError = false;
 371  var imageData = '';
 372
 373  return {
 374
 375    /**
 376     * @ngdoc property
 377     * @name throwsError
 378     * @propertyOf ngCordovaMocks.cordovaCamera
 379     *
 380     * @description
 381     * A flag that signals whether a promise should be rejected or not.
 382     * This property should only be used in automated tests.
 383     **/
 384    throwsError: throwsError,
 385
 386    /**
 387     * @ngdoc property
 388     * @name imageData
 389     * @propertyOf ngCordovaMocks.cordovaCamera
 390     *
 391     * @description
 392     * The imagedata (e.g. an url) which will be returned from the device.
 393     * This property should only be used in automated tests.
 394     **/
 395    imageData: imageData,
 396
 397    getPicture: function (options) {
 398      var defer = $q.defer();
 399      if (this.throwsError) {
 400        defer.reject('There was an error getting the picture.');
 401      } else {
 402        if (options) {
 403          options = options;	// This is just to get by JSHint.
 404        }
 405
 406        defer.resolve(this.imageData);
 407      }
 408
 409      return defer.promise;
 410    }
 411  };
 412}]);
 413
 414/**
 415 * @ngdoc service
 416 * @name ngCordovaMocks.cordovaCapture
 417 *
 418 * @description
 419 * A service for testing media capture
 420 * in an app build with ngCordova.
 421 *
 422 * @example
 423 */
 424ngCordovaMocks.factory('$cordovaCapture', ['$q', function ($q) {
 425  var throwsError = false;
 426
 427  return {
 428    /**
 429     * @ngdoc property
 430     * @name throwsError
 431     * @propertyOf ngCordovaMocks.cordovaCapture
 432     *
 433     * @description
 434     * A flag that signals whether a promise should be rejected or not.
 435     * This property should only be used in automated tests.
 436     **/
 437    throwsError: throwsError,
 438
 439    captureAudio: function () {
 440      var defer = $q.defer();
 441      if (this.throwsError) {
 442        defer.reject('There was an error capturing the audio.');
 443      } else {
 444        defer.resolve();
 445      }
 446
 447      return defer.promise;
 448    },
 449
 450    captureImage: function () {
 451      var defer = $q.defer();
 452      if (this.throwsError) {
 453        defer.reject('There was an error capturing the image.');
 454      } else {
 455        defer.resolve();
 456      }
 457
 458      return defer.promise;
 459    },
 460
 461    captureVideo: function () {
 462      var defer = $q.defer();
 463      if (this.throwsError) {
 464        defer.reject('There was an error capturing the video.');
 465      } else {
 466        defer.resolve();
 467      }
 468
 469      return defer.promise;
 470    }
 471  };
 472}]);
 473
 474/**
 475 * @ngdoc service
 476 * @name ngCordovaMocks.cordovaContacts
 477 *
 478 * @description
 479 * A service for testing features related with contacts
 480 * in an app build with ngCordova.
 481 **/
 482ngCordovaMocks.factory('$cordovaContacts', ['$q', function ($q) {
 483  var throwsError = false;
 484  var contacts = [];
 485
 486  return {
 487    /**
 488     @ngdoc property
 489     @name throwsError
 490     @propertyOf ngCordovaMocks.cordovaContacts
 491
 492     @description
 493     A flag that signals whether a promise should be rejected or not.
 494     This property should only be used in automated tests.
 495     */
 496    throwsError: throwsError,
 497
 498    /**
 499     @ngdoc contacts
 500     @name throwsError
 501     @propertyOf ngCordovaMocks.cordovaContacts
 502
 503     @description
 504     An in-memory collection of contacts.
 505     This property should only be used in automated tests.
 506     */
 507    contacts: contacts,
 508
 509    save: function (contact) {
 510      var defer = $q.defer();
 511      if (this.throwsError) {
 512        defer.reject('There was an error saving the contact.');
 513      } else {
 514        var existingIndex = null;
 515        for (var i = 0; i < this.contacts.length; i++) {
 516          // The actual implementation relies on the entire object match.
 517          // we're gong to rely on the ID.
 518          if (this.contacts[i].id === contact.id) {
 519            existingIndex = i;
 520            break;
 521          }
 522        }
 523
 524        if (existingIndex === null) {
 525          this.contacts.push(contact);
 526          defer.resolve();
 527        } else {
 528          defer.reject('Contact already exists.');
 529        }
 530      }
 531
 532      return defer.promise;
 533    },
 534
 535    remove: function (contact) {
 536      var defer = $q.defer();
 537      if (this.throwsError) {
 538        defer.reject('There was an error saving the contact.');
 539      } else {
 540        var toRemove = null;
 541        for (var i = 0; i < this.contacts.length; i++) {
 542          // The actual implementation relies on the entire object match.
 543          // we're gong to rely on the ID.
 544          if (this.contacts[i].id === contact.id) {
 545            toRemove = i;
 546            break;
 547          }
 548        }
 549
 550        if (toRemove === null) {
 551          defer.reject('Unable to find contact.');
 552        } else {
 553          this.contacts.splice(toRemove, 1);
 554          defer.resolve();
 555        }
 556      }
 557
 558      return defer.promise;
 559    },
 560
 561    find: function (options) {
 562      var defer = $q.defer();
 563      if (this.throwsError) {
 564        defer.reject('There was an error finding the contact.');
 565      } else {
 566        var fields = options.fields || ['id', 'displayName'];
 567        delete options.fields;
 568
 569        if (!fields) {
 570          defer.reject('ContactError.INVALID_ARGUMENT_ERROR');
 571        } else {
 572          if (fields === '*') {
 573            defer.resolve(this.contacts);
 574          } else {
 575            // Implement a very rudimentary search approach for testing purposes.
 576            // This is NOT exhaustive.
 577            var results = [];
 578            for (var i = 0; i < this.contacts.length; i++) {
 579              for (var key in this.contacts[i]) {
 580                var propertyValue = this.contacts[i][key];
 581              }
 582            }
 583
 584            // TODO: Search by individual fields
 585            defer.resolve(results);
 586          }
 587        }
 588      }
 589
 590      return defer.promise;
 591    }
 592  };
 593}]);
 594
 595/**
 596 * @ngdoc service
 597 * @name ngCordovaMocks.cordovaDatePicker
 598 *
 599 * @description
 600 * A service for testing datepicker features
 601 * in an app build with ngCordova.
 602 */
 603ngCordovaMocks.factory('$cordovaDatePicker', ['$q', function ($q) {
 604  return {
 605    show: function (options) {
 606      var q = $q.defer();
 607      options = options || {date: new Date(), mode: 'date'};
 608      q.resolve(options.date);
 609      return q.promise;
 610    }
 611  };
 612}]);
 613
 614/**
 615 * @ngdoc service
 616 * @name ngCordovaMocks.cordovaDevice
 617 *
 618 * @description
 619 * A service for testing device information
 620 * in an app build with ngCordova.
 621 **/
 622ngCordovaMocks.factory('$cordovaDevice', function () {
 623  var device = '';
 624  var cordova = '';
 625  var model = '';
 626  var platform = '';
 627  var uuid = '';
 628  var version = '';
 629
 630  return {
 631    /**
 632     @ngdoc property
 633     @name device
 634     @propertyOf ngCordovaMocks.cordovaDevice
 635
 636     @description
 637     The name of the 'device'.
 638     This property should only be used in automated tests.
 639     */
 640    device: device,
 641
 642    /**
 643     @ngdoc property
 644     @name cordova
 645     @propertyOf ngCordovaMocks.cordovaDevice
 646
 647     @description
 648     The version of cordova in use.
 649     This property should only be used in automated tests.
 650     */
 651    cordova: cordova,
 652
 653    /**
 654     @ngdoc property
 655     @name model
 656     @propertyOf ngCordovaMocks.cordovaDevice
 657
 658     @description
 659     The model of the device using the app.
 660     This property should only be used in automated tests.
 661     */
 662    model: model,
 663
 664    /**
 665     @ngdoc property
 666     @name platform
 667     @propertyOf ngCordovaMocks.cordovaDevice
 668
 669     @description
 670     The name of the operating system in use.
 671     This property should only be used in automated tests.
 672     */
 673    platform: platform,
 674
 675    /**
 676     @ngdoc property
 677     @name uuid
 678     @propertyOf ngCordovaMocks.cordovaDevice
 679
 680     @description
 681     The unique identifier of a device.
 682     This property should only be used in automated tests.
 683     */
 684    uuid: uuid,
 685
 686    /**
 687     @ngdoc property
 688     @name version
 689     @propertyOf ngCordovaMocks.cordovaDevice
 690
 691     @description
 692     The version of the operating system.
 693     This property should only be used in automated tests.
 694     */
 695    version: version,
 696
 697    /**
 698     @ngdoc property
 699     @name manufacturer
 700     @propertyOf ngCordovaMocks.cordovaDevice
 701
 702     @description
 703     The manufacturer of the device.
 704     This property should only be used in automated tests.
 705     */
 706    version: version,
 707
 708    getDevice: function () {
 709      return this.device;
 710    },
 711
 712    getCordova: function () {
 713      return this.cordova;
 714    },
 715
 716    getModel: function () {
 717      return this.model;
 718    },
 719
 720    getPlatform: function () {
 721      return this.platform;
 722    },
 723
 724    getUUID: function () {
 725      return this.uuid;
 726    },
 727
 728    getVersion: function () {
 729      return this.version;
 730    },
 731
 732    getManufacturer: function () {
 733      return this.manufacturer;
 734    }
 735  };
 736});
 737
 738/**
 739 * @ngdoc service
 740 * @name ngCordovaMocks.cordovaDeviceMotion
 741 *
 742 * @description
 743 * A service for mocking the accelerometer
 744 * in an app build with ngCordova.
 745 **/
 746ngCordovaMocks.factory('$cordovaDeviceMotion', ['$interval', '$q', function ($interval, $q) {
 747  var currentAcceleration = null;
 748  var throwsError = false;
 749  var positions = [];
 750  var watchIntervals = [];
 751
 752  return {
 753    /**
 754     * @ngdoc property
 755     * @name currentAcceleration
 756     * @propertyOf ngCordovaMocks.cordovaDeviceMotion
 757     *
 758     * @description
 759     * The current acceleration.
 760     * This property should only be used in automated tests.
 761     **/
 762    currentAcceleration: currentAcceleration,
 763
 764    /**
 765     @ngdoc property
 766     @name throwsError
 767     @propertyOf ngCordovaMocks.cordovaDeviceMotion
 768
 769     @description
 770     A flag that signals whether a promise should be rejected or not.
 771     This property should only be used in automated tests.
 772     */
 773    throwsError: throwsError,
 774
 775    /**
 776     @ngdoc property
 777     @name positions
 778     @propertyOf ngCordovaMocks.cordovaDeviceMotion
 779
 780     @description
 781     The collection of 'positions' that have been logged.
 782     This property should only be used in automated tests.
 783     */
 784    positions: positions,
 785
 786    /**
 787     @ngdoc property
 788     @name watchIntervals
 789     @propertyOf ngCordovaMocks.cordovaDeviceMotion
 790
 791     @description
 792     The collection of watchers that are currently active.
 793     This property should only be used in automated tests.
 794     */
 795    watchIntervals: watchIntervals,
 796
 797    getCurrentAcceleration: function () {
 798      var defer = $q.defer();
 799      if (this.throwsError) {
 800        defer.reject('There was an error getting the current acceleration.');
 801      } else {
 802        defer.resolve(this.currentAcceleration);
 803      }
 804
 805      return defer.promise;
 806    },
 807
 808    watchAcceleration: function (options) {
 809      var defer = $q.defer();
 810      var watchId = Math.floor((Math.random() * 1000000) + 1);
 811
 812      this.positions = [];
 813      self = this;
 814
 815      if (this.throwsError) {
 816        defer.reject('There was an error watching the current acceleration.');
 817      } else {
 818        var delay = 10000;		// The default based on https://github.com/apache/cordova-plugin-device-motion
 819        if (options && options.frequency) {
 820          delay = options.frequency;
 821        }
 822
 823        this.watchIntervals.push($interval(
 824          function () {
 825            if (self.throwsError) {
 826              defer.reject('There was an error watching the acceleration.');
 827            }
 828
 829            // Generate a random position
 830            var randomX = Math.floor((Math.random() * 100) + 1);
 831            var randomY = Math.floor((Math.random() * 100) + 1);
 832            var randomZ = Math.floor((Math.random() * 100) + 1);
 833            var result = {x: randomX, y: randomY, z: randomZ, timestamp: Date.now()};
 834
 835            self.positions.push(result);
 836            defer.notify(result);
 837          },
 838          delay
 839        ));
 840      }
 841
 842      return {
 843        watchId: watchId,
 844        promise: defer.promise
 845      };
 846    },
 847
 848    clearWatch: function (watchId) {
 849      var defer = $q.defer();
 850      if (watchId) {
 851        if (this.throwsError) {
 852          defer.reject('Unable to clear watch.');
 853        } else {
 854          var removed = -1;
 855          for (var i = 0; i < this.watchIntervals.length; i++) {
 856            if (this.watchIntervals[i].watchId === watchId) {
 857              $interval.cancel(watchIntervals[i].interval);
 858              removed = i;
 859              break;
 860            }
 861          }
 862
 863          if (removed !== -1) {
 864            this.watchIntervals.splice(removed, 1);
 865          }
 866        }
 867      } else {
 868        defer.reject('Unable to clear watch. No watch ID provided.');
 869      }
 870
 871      return defer.promise;
 872    }
 873  };
 874}]);
 875
 876/**
 877 * @ngdoc service
 878 * @name ngCordovaMocks.cordovaDeviceOrientation
 879 *
 880 * @description
 881 * A service for testing compass fetures
 882 * in an app build with ngCordova.
 883 */
 884ngCordovaMocks.factory('$cordovaDeviceOrientation', ['$interval', '$q', function ($interval, $q) {
 885  var currentHeading = null;
 886  var throwsError = false;
 887  var readings = [];
 888  var watchIntervals = [];
 889
 890  return {
 891    /**
 892     * @ngdoc property
 893     * @name currentHeading
 894     * @propertyOf ngCordovaMocks.cordovaDeviceOrientation
 895     *
 896     * @description
 897     * The current heading.
 898     * This property should only be used in automated tests.
 899     **/
 900    currentHeading: currentHeading,
 901
 902    /**
 903     @ngdoc property
 904     @name throwsError
 905     @propertyOf ngCordovaMocks.cordovaDeviceOrientation
 906
 907     @description
 908     A flag that signals whether a promise should be rejected or not.
 909     This property should only be used in automated tests.
 910     */
 911    throwsError: throwsError,
 912
 913    /**
 914     @ngdoc property
 915     @name positions
 916     @propertyOf ngCordovaMocks.cordovaDeviceOrientation
 917
 918     @description
 919     The collection of compass 'readings' that have been logged.
 920     This property should only be used in automated tests.
 921     */
 922    readings: readings,
 923
 924    /**
 925     @ngdoc property
 926     @name watchIntervals
 927     @propertyOf ngCordovaMocks.cordovaDeviceOrientation
 928
 929     @description
 930     The collection of watchers that are currently active.
 931     This property should only be used in automated tests.
 932     */
 933    watchIntervals: watchIntervals,
 934
 935    getCurrentHeading: function () {
 936      var defer = $q.defer();
 937      if (this.throwsError) {
 938        defer.reject('There was an error getting the current heading.');
 939      } else {
 940        defer.resolve(this.currentHeading);
 941      }
 942
 943      return defer.promise;
 944    },
 945
 946    watchHeading: function (options) {
 947      var defer = $q.defer();
 948      var watchID = Math.floor((Math.random() * 1000000) + 1);
 949      var self = this;
 950
 951      self.readings = [];
 952
 953      if (self.throwsError) {
 954        defer.reject('There was an error getting the compass heading.');
 955      } else {
 956        var delay = 100;		// The default based on https://github.com/apache/cordova-plugin-device-orientation
 957        if (options && options.frequency) {
 958          delay = options.frequency;
 959        }
 960
 961        self.watchIntervals.push({
 962          watchID: watchID,
 963          interval: $interval(
 964            function () {
 965              if (self.throwsError) {
 966                defer.reject('There was an error watching the acceleration.');
 967              }
 968
 969              // Generate a random position
 970              var magneticHeading = (Math.random() * 359.99) + 1;
 971              var trueHeading = (Math.random() * 359.99) + 1;
 972              var headingAccuracy = Math.floor((Math.random() * 360) + 1);
 973              var result = {magneticHeading: magneticHeading, trueHeading: trueHeading, headingAccuracy: headingAccuracy, timestamp: Date.now()};
 974
 975              self.readings.push(result);
 976              defer.notify(result);
 977            },
 978            delay
 979          )
 980        });
 981      }
 982
 983      var cancel = function (id) {
 984        var removed = -1;
 985        for (var i = 0; i < self.watchIntervals.length; i++) {
 986          if (self.watchIntervals[i].watchID === id) {
 987            $interval.cancel(watchIntervals[i].interval);
 988            removed = i;
 989            break;
 990          }
 991        }
 992
 993        if (removed !== -1) {
 994          self.watchIntervals.splice(removed, 1);
 995        }
 996      };
 997
 998      defer.promise.cancel = function () {
 999        cancel(watchID);
1000      };
1001
1002      defer.promise.clearWatch = function (id) {
1003        cancel(id || watchID);
1004      };
1005
1006      defer.promise.watchID = watchID;
1007
1008      return defer.promise;
1009    },
1010
1011    clearWatch: function (watchId) {
1012      var defer = $q.defer();
1013      if (watchId) {
1014        if (this.throwsError) {
1015          defer.reject('Unable to clear watch.');
1016        } else {
1017          var removed = -1;
1018          for (var i = 0; i < this.watchIntervals.length; i++) {
1019            if (this.watchIntervals[i].watchId === watchId) {
1020              $interval.cancel(watchIntervals[i].interval);
1021              removed = i;
1022              break;
1023            }
1024          }
1025
1026          if (removed !== -1) {
1027            this.watchIntervals.splice(removed, 1);
1028          }
1029        }
1030      } else {
1031        defer.reject('Unable to clear watch. No watch ID provided.');
1032      }
1033
1034      return defer.promise;
1035    }
1036  };
1037}]);
1038
1039/**
1040 * @ngdoc service
1041 * @name ngCordovaMocks.cordovaDialogs
1042 *
1043 * @description
1044 * A service for testing dialogs
1045 * in an app build with ngCordova.
1046 */
1047ngCordovaMocks.factory('$cordovaDialogs', ['$q', function ($q) {
1048  var dialogText = false;
1049  var dialogTitle = '';
1050  var defaultValue = '';
1051  var promptResponse = '';
1052  var beepCount = 0;
1053  var useHostAbilities = true;
1054
1055  return {
1056    /**
1057     @ngdoc property
1058     @name dialogText
1059     @propertyOf ngCordovaMocks.cordovaDialogs
1060
1061     @description
1062     The main content in the dialog.
1063     This property should only be used in automated tests.
1064     */
1065    dialogText: dialogText,
1066
1067    /**
1068     @ngdoc property
1069     @name dialogTitle
1070     @propertyOf ngCordovaMocks.cordovaDialogs
1071
1072     @description
1073     The title of the dialog.
1074     This property should only be used in automated tests.
1075     */
1076    dialogTitle: dialogTitle,
1077
1078    /**
1079     @ngdoc property
1080     @name defaultValue
1081     @propertyOf ngCordovaMocks.cordovaDialogs
1082
1083     @description
1084     The default value to be used in a prompt.
1085     This property should only be used in automated tests.
1086     */
1087    defaultValue: defaultValue,
1088
1089    /**
1090     @ngdoc property
1091     @name promptResponse
1092     @propertyOf ngCordovaMocks.cordovaDialogs
1093
1094     @description
1095     Used to simulate a user's response to a prompt.
1096     This property should only be used in automated tests.
1097     */
1098    promptResponse: promptResponse,
1099
1100    /**
1101     @ngdoc property
1102     @name buttonLabels
1103     @propertyOf ngCordovaMocks.cordovaDialogs
1104
1105     @description
1106     An array of the text of each button in the dialog.
1107     This property should only be used in automated tests.
1108     */
1109    buttonLabels: [],
1110
1111    /**
1112     @ngdoc property
1113     @name beepCount
1114     @propertyOf ngCordovaMocks.cordovaDialogs
1115
1116     @description
1117     The number of times a beep has occurred.
1118     This property should only be used in automated tests.
1119     */
1120    beepCount: beepCount,
1121
1122    /**
1123     @ngdoc property
1124     @name useHostAbilities
1125     @propertyOf ngCordovaMocks.cordovaDialogs
1126
1127     @description
1128     A flag that signals whether or not to try and use the host's
1129     (browser or otherwise) prompting capabilities.
1130     This property should only be used in automated tests.
1131     */
1132    useHostAbilities: useHostAbilities,
1133
1134    alert: function (message, title, buttonName) {
1135      var d = $q.defer();
1136
1137      if (this.useHostAbilities) {
1138        // NOTE: The window.alert method doesn't support a title or callbacks.
1139        alert(message);
1140        d.resolve();
1141      } else {
1142        this.dialogText = message;
1143        this.dialogTitle = title;
1144        this.buttonLabels.push(buttonName);
1145        d.resolve();
1146      }
1147
1148      return d.promise;
1149    },
1150
1151    confirm: function (message, title, buttonName) {
1152      var d = $q.defer();
1153
1154      if (this.useHostAbilities) {
1155        // NOTE: The window.confirm method doesn't support a title or custom button naming.
1156        var result = confirm(message);
1157        d.resolve(result ? 2 : 1);
1158      } else {
1159        this.dialogText = message;
1160        this.dialogTitle = title;
1161        this.buttonLabels.push(buttonName);
1162        d.resolve(0);
1163      }
1164
1165      return d.promise;
1166    },
1167
1168    prompt: function (message, title, buttonLabels, defaultText) {
1169      var d = $q.defer();
1170
1171      if (this.useHostAbilities) {
1172        // NOTE: The window.prompt method doesn't support a title or custom button naming.
1173        var result = prompt(message, defaultText);
1174        d.resolve(result);
1175      } else {
1176        this.dialogText = message;
1177        this.dialogTitle = title;
1178        this.defaultValue = defaultText;
1179
1180        for (var i = 0; i < buttonLabels.length; i++) {
1181          this.buttonLabels.push(buttonLabels[i]);
1182        }
1183
1184        d.resolve(this.promptResponse);
1185      }
1186
1187      return d.promise;
1188    },
1189
1190    beep: function (times) {
1191      this.beepCount = times;
1192    }
1193  };
1194}]);
1195
1196/**
1197 * @ngdoc service
1198 * @name ngCordovaMocks.cordovaFacebook
1199 *
1200 * @description
1201 * A service for testing Facebook features
1202 * in an app built with ngCordova.
1203 **/
1204ngCordovaMocks.factory('$cordovaFacebook', ['$q', function ($q) {
1205  return {
1206
1207    /**
1208     * These properties are here for the purpose of automated testing only.
1209     **/
1210    loginShouldSucceedWith: null,
1211    showDialogShouldSucceedWith: null,
1212    apiShouldSucceedWith: null,
1213    getAccessTokenShouldSucceedWith: null,
1214    getLoginStatusShouldSucceedWith: null,
1215    logoutShouldSuceedWith: null,
1216
1217    login: function (permissions) {
1218      if (this.loginShouldSucceedWith !== null) {
1219        return $q.when(this.loginShouldSucceedWith);
1220      } else {
1221        return $q.reject();
1222      }
1223    },
1224
1225    showDialog: function (options) {
1226      if (this.showDialogShouldSucceedWith !== null) {
1227        return $q.when(this.showDialogShouldSucceedWith);
1228      } else {
1229        return $q.reject();
1230      }
1231    },
1232
1233    api: function (path, permissions) {
1234      if (this.apiShouldSucceedWith !== null) {
1235        return $q.when(this.apiShouldSucceedWith);
1236      } else {
1237        return $q.reject();
1238      }
1239    },
1240
1241    getAccessToken: function () {
1242      if (this.getAccessTokenShouldSucceedWith !== null) {
1243        return $q.when(this.getAccessTokenShouldSucceedWith);
1244      } else {
1245        return $q.reject();
1246      }
1247    },
1248
1249    getLoginStatus: function () {
1250      if (this.getLoginStatusShouldSucceedWith !== null) {
1251        return $q.when(this.getLoginStatusShouldSucceedWith);
1252      } else {
1253        return $q.reject();
1254      }
1255    },
1256
1257    logout: function () {
1258      if (this.logoutShouldSuceedWith !== null) {
1259        return $q.when(this.logoutShouldSuceedWith);
1260      } else {
1261        return $q.reject();
1262      }
1263    }
1264  };
1265}]);
1266
1267/**
1268 * @ngdoc service
1269 * @name ngCordovaMocks.cordovaFile
1270 *
1271 * @description
1272 * A service for testing interaction with device directories and files
1273 * in an app build with ngCordova.
1274 */
1275ngCordovaMocks.factory('$cordovaFile', ['$q', function ($q) {
1276  var throwsError = false;
1277  var fileSystem = {};
1278  var shouldMockFiles = false;
1279  var files = {};
1280
1281  var mockIt = function (errorMessage) {
1282    var defer = $q.defer();
1283    if (this.throwsError) {
1284      defer.reject(errorMessage);
1285    } else {
1286      defer.resolve();
1287    }
1288
1289    return defer.promise;
1290  };
1291
1292  return {
1293    /**
1294     * @ngdoc property
1295     * @name throwsError
1296     * @propertyOf ngCordovaMocks.cordovaFile
1297     *
1298     * @description
1299     * A flag that signals whether a promise should be rejected or not.
1300     * This property should only be used in automated tests.
1301     **/
1302    throwsError: throwsError,
1303
1304    /**
1305     * @ngdoc property
1306     * @name fileSystem
1307     * @propertyOf ngCordovaMocks.cordovaFile
1308     *
1309     * @description
1310     * A fake, in-memory file system. This is incomplete at this time.
1311     * This property should only be used in automated tests.
1312     **/
1313    fileSystem: fileSystem,
1314
1315    /**
1316     * @ngdoc property
1317     * @name shouldMockFiles
1318     * @propertyOf ngCordovaMocks.cordovaFile
1319     *
1320     * @description
1321     * A flag that signals whether one wish to mock files.
1322     * This is useful if you need mocks specific file scenarios.
1323     * This property should only be used in automated tests.
1324     **/
1325    shouldMockFiles: shouldMockFiles,
1326
1327    /**
1328     * @ngdoc property
1329     * @name files
1330     * @propertyOf ngCordovaMocks.cordovaFile
1331     *
1332     * @description
1333     * An object that may be used for mocking files on the device.
1334     * This property should only be used in automated tests.
1335     *
1336     * **/
1337    files: files,
1338
1339    checkDir: function (directory) {
1340      if (this.shouldMockFiles) {
1341        var defer = $q.defer();
1342        if (this.files[directory] && !this.files[directory].isFile) {
1343          defer.resolve();
1344        } else {
1345          defer.reject();
1346        }
1347
1348        return defer.promise;
1349      }
1350
1351      return mockIt.call(this, 'There was an error checking the directory.');
1352    },
1353
1354    createDir: function (directory, overwrite) {
1355      if (this.shouldMockFiles) {
1356        var defer = $q.defer();
1357        this.files[directory] = {isFile: false};
1358        defer.resolve();
1359        return defer.promise;
1360      }
1361
1362      return mockIt.call(this, 'There was an error creating the directory.');
1363    },
1364
1365    listDir: function (filePath) {
1366      return mockIt.call(this, 'There was an error listing the directory');
1367    },
1368
1369    checkFile: function (filePath) {
1370      if (this.shouldMockFiles) {
1371        var defer = $q.defer();
1372        if (this.files[filePath] && this.files[filePath].isFile) {
1373          defer.resolve();
1374        } else {
1375          defer.reject();
1376        }
1377
1378        return defer.promise;
1379      }
1380
1381      return mockIt.call(this, 'There was an error checking for the file.');
1382    },
1383
1384    createFile: function (filePath, overwrite) {
1385      if (this.shouldMockFiles) {
1386        var defer = $q.defer();
1387        this.files[filePath] = {
1388          isFile: true,
1389          fileContent: ''
1390        };
1391        defer.resolve();
1392        return defer.promise;
1393      }
1394
1395      return mockIt.call(this, 'There was an error creating the file.');
1396    },
1397
1398    removeFile: function (directory, file) {
1399      return mockIt.call(this, 'There was an error removng the file.');
1400    },
1401
1402    writeFile: function (filePath, data, options) {
1403      if (this.shouldMockFiles && filePath && data) {
1404        this.files[filePath] = {
1405          isFile: true,
1406          fileContent: data
1407        };
1408      }
1409
1410      return mockIt.call(this, 'There was an error writing the file.');
1411    },
1412
1413    readFile: function (filePath) {
1414      return this.readAsText(filePath);
1415    },
1416
1417    readAsText: function (filePath) {
1418      if (this.shouldMockFiles) {
1419        var defer = $q.defer();
1420        if (files[filePath] && files[filePath].isFile) {
1421          defer.resolve(files[filePath].fileContent);
1422        } else {
1423          defer.reject();
1424        }
1425
1426        return defer.promise;
1427      }
1428
1429      return mockIt.call(this, 'There was an error reading the file as text.');
1430    },
1431
1432    readAsDataURL: function (filePath) {
1433      return mockIt.call(this, 'There was an error reading the file as a data url.');
1434    },
1435
1436    readAsBinaryString: function (filePath) {
1437      return mockIt.call(this, 'There was an error reading the file as a binary string.');
1438    },
1439
1440    readAsArrayBuffer: function (filePath) {
1441      return mockIt.call(this, 'There was an error reading the file as an array buffer.');
1442    },
1443
1444    readFileMetadata: function (filePath) {
1445      return mockIt.call(this, 'There was an error reading the file metadata');
1446    },
1447
1448    readFileAbsolute: function (filePath) {
1449      return mockIt.call(this, 'There was an error reading the file from the absolute path');
1450    },
1451
1452    readFileMetadataAbsolute: function (filePath) {
1453      return mockIt.call(this, 'There was an error reading the file metadta from the absolute path');
1454    }
1455  };
1456}]);
1457
1458/**
1459 * @ngdoc service
1460 * @name ngCordovaMocks.cordovaFileOpener2
1461 *
1462 * @description
1463 * A service for testing fileOpener2
1464 * in an app build with ngCordova.
1465 */
1466ngCordovaMocks.factory('$cordovaFileOpener2', ['$q', function ($q) {
1467
1468  var throwsError = false;
1469
1470  return {
1471
1472    /**
1473     * @ngdoc property
1474     * @name throwsError
1475     * @propertyOf ngCordovaMocks.cordovaFileOpener2
1476     *
1477     * @description
1478     * A flag that signals whether a promise should be rejected or not.
1479     * This property should only be used in automated tests.
1480     **/
1481    throwsError: throwsError,
1482
1483    open: function (file, type) {
1484
1485      var defer = $q.defer();
1486
1487      if (this.throwError) {
1488        defer.reject({
1489          status: 0,
1490          message: 'There was an error capturing the file.'
1491        });
1492      } else {
1493        defer.resolve();
1494      }
1495
1496      return defer.promise;
1497
1498    },
1499
1500    uninstall: function (pack) {
1501
1502      var defer = $q.defer();
1503
1504      if (this.throwError) {
1505        defer.reject({
1506          status: 0,
1507          message: 'There was an error capturing the packageId.'
1508        });
1509      } else {
1510        defer.resolve();
1511      }
1512
1513      return defer.promise;
1514
1515    },
1516
1517    appIsInstalled: function (pack) {
1518
1519      var defer = $q.defer();
1520
1521      if (this.throwError) {
1522        defer.reject({
1523          status: 0,
1524          message: 'There was an error capturing the packageId.'
1525        });
1526      } else {
1527        defer.resolve();
1528      }
1529
1530      return defer.promise;
1531
1532    }
1533
1534  };
1535
1536}]);
1537
1538
1539/**
1540 * @ngdoc service
1541 * @name ngCordovaMocks.cordovaFileTransfer
1542 *
1543 * @description
1544 * A service for testing download and upload
1545 * in an app build with ngCordova.
1546 */
1547ngCordovaMocks.factory('$cordovaFileTransfer', ['$q', function ($q) {
1548    var throwsError = false;
1549
1550    var mockIt = function (errorMessage) {
1551        var defer = $q.defer();
1552        if (this.throwsError) {
1553            defer.reject(errorMessage);
1554        } else {
1555            defer.resolve();
1556        }
1557        return defer.promise;
1558    };
1559
1560    return {
1561        /**
1562         * @ngdoc property
1563         * @name throwsError
1564         * @propertyOf ngCordovaMocks.cordovaFileTransfer
1565         *
1566         * @description
1567         * A flag that signals whether a promise should be rejected or not.
1568         * This property should only be used in automated tests.
1569         **/
1570        throwsError: throwsError,
1571
1572        download: function (source, filePath, options, trust) {
1573            return mockIt.call(this, 'There was an error downloading the file.');
1574        },
1575
1576        upload: function (server, filePath, options) {
1577            return mockIt.call(this, 'There was an error uploading the file.'); 
1578        }
1579    };
1580}]);
1581
1582/**
1583 * @ngdoc service
1584 * @name ngCordovaMocks.cordovaGeolocation
1585 *
1586 * @description
1587 * A service for testing location services
1588 * in an app build with ngCordova.
1589 */
1590ngCordovaMocks.factory('$cordovaGeolocation', ['$interval', '$q', function ($interval, $q) {
1591  var throwsError = false;
1592  var useHostAbilities = true;
1593
1594  var watchIntervals = [];
1595  var locations = [];
1596  var currentPosition = null;
1597  var nextPosition = null;
1598
1599  return {
1600    /**
1601     @ngdoc property
1602     @name throwsError
1603     @propertyOf ngCordovaMocks.cordovaGeolocation
1604
1605     @description
1606     A flag that signals whether a promise should be rejected or not.
1607     This property should only be used in automated tests.
1608     */
1609    throwsError: throwsError,
1610
1611    /**
1612     @ngdoc property
1613     @name watchIntervals
1614     @propertyOf ngCordovaMocks.cordovaGeolocation
1615
1616     @description
1617     The collection of watchers that are currently active.
1618     This property should only be used in automated tests.
1619     */
1620    watchIntervals: watchIntervals,
1621
1622    /**
1623     @ngdoc property
1624     @name locations
1625     @propertyOf ngCordovaMocks.cordovaGeolocation
1626
1627     @description
1628     The collection of 'locations' that have been logged.
1629     This property should only be used in automated tests.
1630     */
1631    locations: locations,
1632
1633    /**
1634     @ngdoc property
1635     @name currentPosition
1636     @propertyOf ngCordovaMocks.cordovaGeolocation
1637
1638     @description
1639     The last location logged.
1640     This property should only be used in automated tests.
1641     */
1642    currentPosition: currentPosition,
1643
1644    /**
1645     @ngdoc property
1646     @name nextPosition
1647     @propertyOf ngCordovaMocks.cordovaGeolocation
1648
1649     @description
1650     The position to be logged the next time that a watcher
1651     gets the location.
1652     This property should only be used in automated tests.
1653     */
1654    nextPosition: nextPosition,
1655
1656    /**
1657     @ngdoc property
1658     @name useHostAbilities
1659     @propertyOf ngCordovaMocks.cordovaGeolocation
1660
1661     @description
1662     A flag that signals whether or not to try and use the host's
1663     (browser or otherwise) geolocation capabilities.
1664     This property should only be used in automated tests.
1665     */
1666    useHostAbilities: useHostAbilities,
1667
1668    getCurrentPosition: function (options) {
1669      var defer = $q.defer();
1670      if (this.throwsError) {
1671        defer.reject('There was an error getting the location.');
1672      } else {
1673        if (options) {
1674          options = options;	// This is just to get by JSHint.
1675        }
1676
1677        if (this.useHostAbilities) {
1678          if (navigator.geolocation) {
1679            navigator.geolocation.getCurrentPosition(
1680              function (position) {
1681                this.currentPosition = position;
1682                defer.resolve(this.currentPosition);
1683              },
1684              function (error) {
1685                defer.reject(error);
1686              }
1687            );
1688          } else {
1689            defer.reject('Geolocation is not supported by this browser.');
1690          }
1691        } else {
1692          defer.resolve(this.currentPosition);
1693        }
1694      }
1695
1696      return defer.promise;
1697    },
1698
1699    watchPosition: function (options) {
1700      var defer = $q.defer();
1701      var watchID = Math.floor((Math.random() * 1000000) + 1);
1702      var self = this;
1703
1704      self.locations = [];
1705
1706      if (self.throwsError) {
1707        defer.reject('There was an error getting the geolocation.');
1708      } else {
1709        var delay = 1000;
1710        if (options && options.timeout) {
1711          delay = options.timeout;
1712        }
1713
1714        self.watchIntervals.push({
1715          watchID: watchID,
1716          interval: $interval(
1717            function () {
1718              if (self.throwsError) {
1719                defer.reject('There was an error watching the geolocation.');
1720              }
1721
1722              // Attempt to use nextPosition.
1723              var result = self.nextPosition;
1724              if (result === null) {
1725                // Determine whether to use the host's geolocation capabilities or not
1726                if (self.useHostAbilities) {
1727                  if (navigator.geolocation) {
1728                    navigator.geolocation.getCurrentPosition(
1729                      function (position) {
1730                        self.currentPosition = position;
1731                        self.locations.push(position);
1732                        defer.resolve(position);
1733                      },
1734                      function (error) {
1735                        defer.reject(error);
1736                      }
1737                    );
1738                  } else {
1739                    defer.reject('Geolocation is not supported by this browser.');
1740                  }
1741                } else {
1742                  result = {
1743                    coords: {
1744                      latitude: ((Math.random() * 180) + 1) - 90,
1745                      longitude: ((Math.random() * 360) + 1) - 180,
1746                      altitude: ((Math.random() * 100) + 1),
1747
1748                      accuracy: ((Math.random() * 10) + 1),
1749                      altitudeAccuracy: ((Math.random() * 10) + 1),
1750                      heading: ((Math.random() * 360) + 1),
1751                      speed: ((Math.random() * 100) + 1)
1752                    },
1753                    timestamp: Date.now()
1754                  };
1755
1756                  self.currentPosition = result;
1757                  self.locations.push(result);
1758                  defer.notify(result);
1759                }
1760              }
1761            },
1762            delay
1763          )
1764        });
1765      }
1766
1767      var cancel = function (id) {
1768        var removed = -1;
1769        for (var i = 0; i < self.watchIntervals.length; i++) {
1770          if (self.watchIntervals[i].watchID === id) {
1771            $interval.cancel(watchIntervals[i].interval);
1772            removed = i;
1773            break;
1774          }
1775        }
1776
1777        if (removed !== -1) {
1778          self.watchIntervals.splice(removed, 1);
1779        }
1780      };
1781
1782      defer.promise.cancel = function () {
1783        cancel(watchID);
1784      };
1785
1786      defer.promise.clearWatch = function (id) {
1787        cancel(id || watchID);
1788      };
1789
1790      defer.promise.watchID = watchID;
1791
1792      return defer.promise;
1793    },
1794
1795    clearWatch: function (watchID) {
1796      var defer = $q.defer();
1797      if (watchID) {
1798        if (this.throwsError) {
1799          defer.reject('Unable to clear watch.');
1800        } else {
1801          var removed = -1;
1802          for (var i = 0; i < this.watchIntervals.length; i++) {
1803            if (this.watchIntervals[i].watchID === watchID) {
1804              $interval.cancel(watchIntervals[i].interval);
1805              removed = i;
1806              break;
1807            }
1808          }
1809
1810          if (removed !== -1) {
1811            this.watchIntervals.splice(removed, 1);
1812          }
1813        }
1814      } else {
1815        defer.reject('Unable to clear watch. No watch ID provided.');
1816      }
1817
1818      return defer.promise;
1819    }
1820  };
1821}]);
1822
1823/**
1824 * @ngdoc service
1825 * @name ngCordovaMocks.cordovaGlobalization
1826 *
1827 * @description
1828 * A service for testing features related to a user's locale and timezone.
1829 * in an app build with ngCordova.
1830 */
1831ngCordovaMocks.factory('$cordovaGlobalization', ['$q', function ($q) {
1832  var throwsError = false;
1833  var language = (navigator.language) ? navigator.language : 'en-US';
1834  var preferredLanguage = {value: language};
1835  var firstDayOfWeek = 'Sunday';
1836  var localeName = {value: language};
1837
1838  return {
1839    /**
1840     * @ngdoc property
1841     * @name throwsError
1842     * @propertyOf ngCordovaMocks.cordovaGlobalization
1843     *
1844     * @description
1845     * A flag that signals whether a promise should be rejected or not.
1846     * This property should only be used in automated tests.
1847     **/
1848    throwsError: throwsError,
1849
1850    /**
1851     * @ngdoc property
1852     * @name preferredLanguage
1853     * @propertyOf ngCordovaMocks.cordovaGlobalization
1854     *
1855     * @description
1856     * The user's preferred language.
1857     * This property should only be used in automated tests.
1858     **/
1859    preferredLanguage: preferredLanguage,
1860
1861    /**
1862     * @ngdoc property
1863     * @name localeName
1864     * @propertyOf ngCordovaMocks.cordovaGlobalization
1865     *
1866     * @description
1867     * The name of the user's locale.
1868     * This property should only be used in automated tests.
1869     **/
1870    localeName: localeName,
1871
1872    /**
1873     * @ngdoc property
1874     * @name firstDayOfWeek
1875     * @propertyOf ngCordovaMocks.cordovaGlobalization
1876     *
1877     * @description
1878     * The first day of the week based on the user's locale.
1879     * This property should only be used in automated tests.
1880     **/
1881    firstDayOfWeek: firstDayOfWeek,
1882
1883    getPreferredLanguage: function () {
1884      var defer = $q.defer();
1885      if (this.throwsError) {
1886        defer.reject('There was an error getting the preferred language.');
1887      } else {
1888        defer.resolve(this.preferredLanguage);
1889      }
1890
1891      return defer.promise;
1892    },
1893
1894    getLocaleName: function () {
1895      var defer = $q.defer();
1896      if (this.throwsError) {
1897        defer.reject('There was an error getting the locale name.');
1898      } else {
1899        defer.resolve(this.localeName);
1900      }
1901
1902      return defer.promise;
1903    },
1904
1905    getFirstDayOfWeek: function () {
1906      var defer = $q.defer();
1907      if (this.throwsError) {
1908        defer.reject('There was an error getting the first day of week.');
1909      } else {
1910        defer.resolve(this.firstDayOfWeek);
1911      }
1912
1913      return defer.promise;
1914    },
1915
1916    dateToString: function (date, options) {
1917      var defer = $q.defer();
1918      if (this.throwsError) {
1919        defer.reject('There was an error getting the string from the date.');
1920      } else {
1921        var result = '';
1922
1923        // TODO: Review
1924        date = date;
1925        options = options;
1926
1927        // END TODO: Review
1928
1929        defer.resolve(result);
1930      }
1931
1932      return defer.promise;
1933    },
1934
1935    stringToDate: function (dateString, options) {
1936      var defer = $q.defer();
1937      if (this.throwsError) {
1938        defer.reject('There was an error getting the date from the string.');
1939      } else {
1940        var result = '';
1941
1942        // TODO: Review
1943        dateString = dateString;
1944        options = options;
1945
1946        // END TODO: Review
1947
1948        defer.resolve(result);
1949      }
1950
1951      return defer.promise;
1952    },
1953
1954    getDatePattern: function (options) {
1955      var defer = $q.defer();
1956      if (this.throwsError) {
1957        defer.reject('There was an error getting the date pattern.');
1958      } else {
1959        var result = '';
1960
1961        // TODO: Review
1962        options = options;
1963
1964        // END TODO: Review
1965
1966        defer.resolve(result);
1967      }
1968
1969      return defer.promise;
1970    },
1971
1972    getDateNames: function (options) {
1973      var defer = $q.defer();
1974      if (this.throwsError) {
1975        defer.reject('There was an error getting the date names.');
1976      } else {
1977        var result = '';
1978
1979        // TODO: Review
1980        options = options;
1981
1982        // END TODO: Review
1983
1984        defer.resolve(result);
1985      }
1986
1987      return defer.promise;
1988    },
1989
1990    isDayLightSavingsTime: function (date) {
1991      var defer = $q.defer();
1992      if (this.throwsError) {
1993        defer.reject('There was an error getting if this is in daylight savings time mode.');
1994      } else {
1995        var result = '';
1996
1997        // TODO: Review
1998        date = date;
1999
2000        // END TODO: Review
2001
2002        defer.resolve(result);
2003      }
2004
2005      return defer.promise;
2006    },
2007
2008    numberToString: function (number, options) {
2009      var defer = $q.defer();
2010      if (this.throwsError) {
2011        defer.reject('There was an error convertng the number to a string.');
2012      } else {
2013        var result = '';
2014
2015        // TODO: Review
2016        number = number;
2017        options = options;
2018
2019        // END TODO: Review
2020
2021        defer.resolve(result);
2022      }
2023
2024      return defer.promise;
2025    },
2026
2027    stringToNumber: function (numberString, options) {
2028      var defer = $q.defer();
2029      if (this.throwsError) {
2030        defer.reject('There was an error convertng the string to a number.');
2031      } else {
2032        var result = '';
2033
2034        // TODO: Review
2035        options = options;
2036
2037        // END TODO: Review
2038
2039        defer.resolve(result);
2040      }
2041
2042      return defer.promise;
2043    },
2044
2045    getNumberPattern: function (options) {
2046      var defer = $q.defer();
2047      if (this.throwsError) {
2048        defer.reject('There was an error convertng the string to a number.');
2049      } else {
2050        var result = '';
2051
2052        // TODO: Review
2053        options = options;
2054
2055        // END TODO: Review
2056
2057        defer.resolve(result);
2058      }
2059
2060      return defer.promise;
2061    },
2062
2063    getCurrencyPattern: function (currencyCode) {
2064      var defer = $q.defer();
2065      if (this.throwsError) {
2066        defer.reject('There was an error convertng the string to a number.');
2067      } else {
2068        var result = '';
2069
2070        // TODO: Review
2071        currencyCode = currencyCode;
2072
2073        // END TODO: Review
2074
2075        defer.resolve(result);
2076      }
2077
2078      return defer.promise;
2079    }
2080  };
2081}]);
2082
2083/**
2084 * @ngdoc service
2085 * @name ngCordovaMocks.cordovaGoogleAnalytics
2086 *
2087 * @description
2088 * A service for testing google analytics services
2089 * in an app build with ngCordova.
2090 */
2091ngCordovaMocks.factory('$cordovaGoogleAnalytics', ['$q', function ($q) {
2092  var throwsError = false;
2093  var methods = {};
2094
2095  /**
2096   * @ngdoc property
2097   * @name throwsError
2098   * @propertyOf ngCordovaMocks.cordovaGeolocation
2099   *
2100   * @description
2101   * A flag that signals whether a promise should be rejected or not.
2102   * This property should only be used in automated tests.
2103   **/
2104  methods.throwsError = throwsError;
2105
2106  var methodsName = [
2107    'startTrackerWithId',
2108    'setUserId',
2109    'debugMode',
2110    'trackView',
2111    'addCustomDimension',
2112    'trackEvent',
2113    'trackException',
2114    'trackTiming',
2115    'addTransaction',
2116    'addTransactionItem'
2117  ];
2118
2119  methodsName.forEach(function (funcName) {
2120    methods[funcName] = function () {
2121      var defer = $q.defer();
2122
2123      (this.throwsError) ?
2124        defer.reject() :
2125        defer.resolve();
2126
2127      return defer.promise;
2128    };
2129  });
2130
2131  return methods;
2132}]);
2133
2134'use strict';
2135
2136/**
2137 * @ngdoc service
2138 * @name ngCordovaMocks.googlePlayGame
2139 *
2140 * @description
2141 * A service for testing Google Play Game features
2142 * in an app build with ngCordova.
2143 */
2144ngCordovaMocks.factory('$cordovaGooglePlayGame', ['$q', function ($q) {
2145  var throwsError = false;
2146  var isSignedIn = false;
2147  var displayName = '';
2148
2149  return {
2150
2151    /**
2152     * @ngdoc property
2153     * @name _throwsError
2154     * @propertyOf ngCordovaMocks.googlePlayGame
2155     *
2156     * @description
2157     * A flag that signals whether a promise should be rejected or not.
2158     * This property should only be used in automated tests.
2159     **/
2160    _throwsError: throwsError,
2161
2162    /**
2163     * @ngdoc property
2164     * @name _isSignedIn
2165     * @propertyOf ngCordovaMocks.googlePlayGame
2166     *
2167     * @description
2168     * A flag that signals whether a promise should be rejected or not.
2169     * This property should only be used in automated tests.
2170     **/
2171    _isSignedIn: isSignedIn,
2172
2173    /**
2174     * @ngdoc property
2175     * @name _displayName
2176     * @propertyOf ngCordovaMocks.googlePlayGame
2177     *
2178     * @description
2179     * A flag that signals whether a promise should be rejected or not.
2180     * This property should only be used in automated tests.
2181     **/
2182    _displayName: displayName,
2183
2184    auth: function () {
2185      var defer = $q.defer();
2186      if (this._throwsError) {
2187        defer.reject('There was a auth error.');
2188      } else {
2189        this.isSignedIn = true;
2190        defer.resolve('SIGN IN SUCCESS');
2191      }
2192
2193      return defer.promise;
2194    },
2195    signout: function () {
2196      var defer = $q.defer();
2197      if (this.throwsError) {
2198        defer.reject('There was a signout error.');
2199      } else {
2200        defer.resolve();
2201      }
2202
2203      return defer.promise;
2204    },
2205    isSignedIn: function () {
2206      var defer = $q.defer();
2207      if (this._throwsError) {
2208        defer.reject('There was a isSignedIn error.');
2209      } else {
2210        defer.resolve({
2211          'isSignedIn': this._isSignedIn
2212        });
2213      }
2214
2215      return defer.promise;
2216    },
2217    showPlayer: function () {
2218      var defer = $q.defer();
2219      if (this.throwsError) {
2220        defer.reject('There was a showPlayer error.');
2221      } else {
2222        defer.resolve({
2223          'displayName': this._displayName
2224        });
2225      }
2226
2227      return defer.promise;
2228    },
2229    submitScore: function (data) {
2230      var defer = $q.defer();
2231      if (this._throwsError) {
2232        defer.reject('There was a submitScore error.');
2233      } else {
2234        defer.resolve('OK');
2235      }
2236
2237      return defer.promise;
2238    },
2239    showAllLeaderboards: function () {
2240      var defer = $q.defer();
2241      if (this.throwsError) {
2242        defer.reject('There was a showAllLeaderboards error.');
2243      } else {
2244        defer.resolve('OK');
2245      }
2246
2247      return defer.promise;
2248    },
2249    showLeaderboard: function (data) {
2250      var defer = $q.defer();
2251      if (this._throwsError) {
2252        defer.reject('There was a showLeaderboard error.');
2253      } else {
2254        defer.resolve('OK');
2255      }
2256
2257      return defer.promise;
2258    },
2259    unlockAchievement: function (data) {
2260      var defer = $q.defer();
2261      if (this.throwsError) {
2262        defer.reject('There was a unlockAchievement error.');
2263      } else {
2264        defer.resolve('OK');
2265      }
2266
2267      return defer.promise;
2268    },
2269    incrementAchievement: function (data) {
2270      var defer = $q.defer();
2271      if (this._throwsError) {
2272        defer.reject('There was a incrementAchievement error.');
2273      } else {
2274        defer.resolve('OK');
2275      }
2276
2277      return defer.promise;
2278    },
2279    showAchievements: function () {
2280      var defer = $q.defer();
2281      if (this.throwsError) {
2282        defer.reject('There was a showAchievements error.');
2283      } else {
2284        defer.resolve('OK');
2285      }
2286
2287      return defer.promise;
2288    }
2289  };
2290
2291}]);
2292
2293/**
2294 * @ngdoc service
2295 * @name ngCordovaMocks.cordovaKeyboard
2296 *
2297 * @description
2298 * A service for testing device keyboard features
2299 * in an app build with ngCordova.
2300 **/
2301ngCordovaMocks.factory('$cordovaKeyboard', function () {
2302  var isVisible = false;
2303
2304  return {
2305    hideAccessoryBar: function (bool) {
2306    },
2307
2308    close: function () {
2309      isVisible = false;
2310    },
2311
2312    show: function () {
2313      isVisible = true;
2314    },
2315
2316    disableScroll: function (bool) {
2317    },
2318
2319    isVisible: function () {
2320      return isVisible;
2321    }
2322
2323  };
2324});
2325
2326/**
2327 * @ngdoc service
2328 * @name ngCordovaMocks.cordovaKeychain
2329 *
2330 * @description
2331 * A service for testing Keychain features
2332 * in an app built with ngCordova.
2333 **/
2334ngCordovaMocks.factory('$cordovaKeychain', ['$q', function ($q) {
2335  var keychains = {};
2336
2337  return {
2338    /**
2339     * @ngdoc property
2340     * @name keychains
2341     * @propertyOf ngCordovaMocks.cordovaKeychain
2342     *
2343     * @description
2344     * The collection of 'keychains' that have been saved.
2345     * This property should only be used in automated tests.
2346     **/
2347    keychains: keychains,
2348
2349    getForKey: function (key, serviceName) {
2350      var defer = $q.defer();
2351
2352      if (this.keychains[serviceName]) {
2353        defer.resolve(this.keychains[serviceName][key]);
2354      } else {
2355        defer.reject();
2356      }
2357
2358      return defer.promise;
2359    },
2360
2361    setForKey: function (key, serviceName, value) {
2362      var defer = $q.defer();
2363
2364      if (!this.keychains[serviceName]) {
2365        this.keychains[serviceName] = {};
2366      }
2367
2368      this.keychains[serviceName][key] = value;
2369
2370      defer.resolve();
2371
2372      return defer.promise;
2373    },
2374
2375    removeForKey: function (key, serviceName) {
2376      var defer = $q.defer();
2377
2378      if (this.keychains[serviceName]) {
2379        delete this.keychains[serviceName][key];
2380      }
2381
2382      defer.resolve();
2383
2384      return defer.promise;
2385    }
2386  };
2387}]);
2388
2389
2390/**
2391 * @ngdoc service
2392 * @name ngCordovaMocks.localNotification
2393 *
2394 * @description
2395 * A service for testing LocalNotificatio
2396 * in an app build with ngCordovaMocks.
2397 */
2398
2399ngCordovaMocks.factory('$cordovaLocalNotification', ['$q', function ($q) {
2400
2401  var storageKeyPfx  = "ngCordLocNotif-";
2402  
2403  function pfxId(id) {
2404    return storageKeyPfx + id;
2405  }
2406
2407  function getAllIds(){
2408    var defer = $q.defer();
2409    var locNotifIds = [];
2410    for ( var i = 0, len = localStorage.length; i < len; ++i ) {
2411      if (localStorage.key( i ).indexOf(storageKeyPfx) > -1)
2412        locNotifIds.push(parseInt(localStorage.key( i ).split("-")[1]));
2413    }
2414    defer.resolve(locNotifIds);
2415    return defer.promise;
2416  }
2417
2418
2419  return {
2420    cancel: function (ids) {
2421      var defer = $q.defer();
2422      if (typeof(ids) == "number") ids = [ids];
2423      ids.forEach(function (id){
2424        localStorage.removeItem([pfxId(id)]);
2425      });      
2426      defer.resolve();
2427      return defer.promise;
2428    },
2429    cancelAll: function () {
2430      var defer = $q.defer();
2431      // TODO
2432      defer.resolve();
2433      return defer.promise;
2434    },
2435    clear: function (ids) {
2436      if (typeof(ids) == "number") ids = [ids];
2437      var defer = $q.defer();
2438      ids.forEach(function (id){
2439        localStorage.removeItem([pfxId(id)]);
2440      });      
2441      defer.resolve();
2442      return defer.promise;
2443    },
2444    clearAll: function () {
2445      var defer = $q.defer();
2446      // TODO
2447      // defer.resolve();
2448      return defer.promise;
2449    },
2450    isScheduled: function (id){
2451      var defer = $q.defer();
2452      if (localStorage[pfxId(id)]) {
2453        defer.resolve(true);
2454      } else {
2455        defer.resolve(false);
2456      }
2457      return defer.promise;
2458    },
2459    isPresent: function (id){
2460      var defer = $q.defer();
2461      if (localStorage[pfxId(id)]) {
2462        defer.resolve(true);
2463      } else {
2464        defer.resolve(false);
2465      }
2466      return defer.promise;
2467    },
2468    isTriggered: function (id){
2469      var defer = $q.defer();
2470      if (localStorage[pfxId(id)]) {
2471        defer.resolve(false);
2472      } else {
2473        defer.resolve(true);
2474      }
2475      return defer.promise;
2476    },
2477    getAllIds: function () {
2478      return getAllIds();
2479    },
2480    getIds: function () {
2481      return getAllIds();
2482    },
2483    getScheduledIds:  function () {
2484      return getAllIds();
2485    },
2486    getTriggeredIds: function () {
2487      var defer = $q.defer();
2488      defer.resolve([]);
2489      return defer.promise;
2490    },
2491    hasPermission: function (id){
2492      var defer = $q.defer();
2493      defer.resolve(true);
2494      return defer.promise;
2495    },
2496    schedule: function (data){
2497      var defer = $q.defer();
2498      var id = pfxId(data.id);
2499      localStorage[id] = JSON.stringify(data);
2500      defer.resolve();
2501      return defer.promise;
2502    },
2503    update: function (data){
2504      var defer = $q.defer();
2505      var id = pfxId(data.id);
2506      localStorage[id] = JSON.stringify(data);
2507      defer.resolve();
2508      return defer.promise;
2509    }
2510  };
2511}]);
2512/**
2513 * @ngdoc service
2514 * @name ngCordovaMocks.cordovaNetwork
2515 *
2516 * @description
2517 * A service for testing networked fetures
2518 * in an app build with ngCordova.
2519 */
2520ngCordovaMocks.factory('$cordovaNetwork', ['$rootScope',function ($rootScope) {
2521  var connectionType = 'WiFi connection';
2522  var isConnected = true;
2523
2524  return {
2525    /**
2526     * @ngdoc property
2527     * @name connectionType
2528     * @propertyOf ngCordovaMocks.cordovaNetwork
2529     *
2530     * @description
2531     * They type of connection. Values should match those found at
2532     * https://github.com/apache/cordova-plugin-network-information
2533     * This property should only be used in automated tests.
2534     **/
2535    connectionType: connectionType,
2536
2537    /**
2538     * @ngdoc property
2539     * @name isConnected
2540     * @propertyOf ngCordovaMocks.cordovaNetwork
2541     *
2542     * @description
2543     * A flag that signals whether the app is connected to a network.
2544     * This property should only be used in automated tests.
2545     **/
2546    isConnected: isConnected,
2547
2548    switchToOnline: function (){
2549      this.isConnected = true;
2550      $rootScope.$broadcast('$cordovaNetwork:online');
2551    },
2552
2553    switchToOffline: function (){
2554      this.isConnected = false;
2555      $rootScope.$broadcast('$cordovaNetwork:offline');
2556    },
2557
2558    getNetwork: function () {
2559      return this.connectionType;
2560    },
2561
2562    isOnline: function () {
2563      return this.isConnected;
2564    },
2565
2566    isOffline: function () {
2567      return !this.isConnected;
2568    }
2569  };
2570}]);
2571
2572/**
2573 * @ngdoc service
2574 * @name ngCordovaMocks.cordovaProgress
2575 *
2576 * @description
2577 * A service for testing Progress Indicator
2578 * in an app build with ngCordova.
2579 */
2580
2581ngCordovaMocks.factory('$cordovaProgress', [
2582  '$timeout', function ($timeout) {
2583
2584    return {
2585      show: function (_message) {
2586        var message = _message || 'Please wait...';
2587        console.info('$cordovaProgress.message', message);
2588      },
2589
2590      showSimple: function (_dim) {
2591        var dim = _dim || false;
2592        console.info('$cordovaProgress.dim', dim);
2593      },
2594
2595      showSimpleWithLabel: function (_dim, _label) {
2596        var dim   = _dim || false;
2597        var label = _label || 'Loading...';
2598        console.group();
2599        console.info('$cordovaProgress.dim', dim);
2600        console.info('$cordovaProgress.label', label);
2601        console.groupEnd();
2602      },
2603
2604      showSimpleWithLabelDetail: function (_dim, _label, _detail) {
2605        var dim    = _dim || false;
2606        var label  = _label || 'Loading...';
2607        var detail = _detail || 'Please wait';
2608
2609        console.group();
2610        console.info('$cordovaProgress.dim', dim);
2611        console.info('$cordovaProgress.label', label);
2612        console.info('$cordovaProgress.detail', detail);
2613        console.groupEnd();
2614      },
2615
2616      showDeterminate: function (_dim, _timeout) {
2617        var dim     = _dim || false;
2618        var timeout = _timeout || 50000;
2619        console.group();
2620        console.info('$cordovaProgress.dim show', dim);
2621        console.info('$cordovaProgress.timeout', timeout);
2622        console.groupEnd();
2623        $timeout(function () {
2624          console.info('$cordovaProgress.dim timeout', dim);
2625        }, timeout);
2626      },
2627
2628      showDeterminateWithLabel: function (_dim, _timeout, _label) {
2629        var dim     = _dim || false;
2630        var timeout = _timeout || 50000;
2631        var label   = _label || 'Loading...';
2632
2633        console.group();
2634        console.info('$cordovaProgress.dim', dim);
2635        console.info('$cordovaProgress.timeout', timeout);
2636        console.info('$cordovaProgress.label', label);
2637        console.groupEnd();
2638        $timeout(function () {
2639          console.info('$cordovaProgress[dim, label] timeout', [dim, label]);
2640        }, timeout);
2641      },
2642
2643      showAnnular: function (_dim, _timeout) {
2644        var dim     = _dim || false;
2645        var timeout = _timeout || 50000;
2646
2647        console.group();
2648        console.info('$cordovaProgress.dim', dim);
2649        console.info('$cordovaProgress.timeout', timeout);
2650        console.groupEnd();
2651        $timeout(function () {
2652          console.info('$cordovaProgress.dim timeout', dim);
2653        }, timeout);
2654      },
2655
2656      showAnnularWithLabel: function (_dim, _timeout, _label) {
2657        var dim     = _dim || false;
2658        var timeout = _timeout || 50000;
2659        var label   = _label || 'Loading...';
2660
2661        console.group();
2662        console.info('$cordovaProgress.dim', dim);
2663        console.info('$cordovaProgress.timeout', timeout);
2664        console.info('$cordovaProgress.label', label);
2665        console.groupEnd();
2666        $timeout(function () {
2667          console.info('$cordovaProgress[dim, label] timeout', [dim, label]);
2668        }, timeout);
2669      },
2670
2671      showBar: function (_dim, _timeout) {
2672        var dim     = _dim || false;
2673        var timeout = _timeout || 50000;
2674
2675        console.group();
2676        console.info('$cordovaProgress.dim', dim);
2677        console.info('$cordovaProgress.timeout', timeout);
2678        console.groupEnd();
2679        $timeout(function () {
2680          console.info('$cordovaProgress.dim timeout', dim);
2681        }, timeout);
2682      },
2683
2684      showBarWithLabel: function (_dim, _timeout, _label) {
2685        var dim     = _dim || false;
2686        var timeout = _timeout || 50000;
2687        var label   = _label || 'Loading...';
2688        console.group();
2689        console.info('$cordovaProgress.dim', dim);
2690        console.info('$cordovaProgress.label', label);
2691        console.info('$cordovaProgress.timeout', timeout);
2692        console.groupEnd();
2693        $timeout(function () {
2694          console.info('$cordovaProgress[dim, label] timeout', [dim, label]);
2695        }, timeout);
2696      },
2697
2698      showSuccess: function (_dim, _label) {
2699        var dim   = _dim || false;
2700        var label = _label || 'Success';
2701        console.group();
2702        console.info('$cordovaProgress.dim', dim);
2703        console.info('$cordovaProgress.label', label);
2704        console.groupEnd();
2705      },
2706
2707      showText: function (_dim, _text, _position) {
2708        var dim      = _dim || false;
2709        var text     = _text || 'Warning';
2710        var position = _position || 'center';
2711        console.group();
2712        console.info('$cordovaProgress.dim', dim);
2713        console.info('$cordovaProgress.text', text);
2714        console.info('$cordovaProgress.position', position);
2715        console.groupEnd();
2716      },
2717
2718      hide: function () {
2719        console.info('$cordovaProgress.hide');
2720      }
2721    };
2722  }
2723]);
2724
2725'use strict';
2726
2727/**
2728 * @ngdoc service
2729 * @name ngCordovaMocks.cordovaPush
2730 *
2731 * @description
2732 * A service for testing push notifications features
2733 * in an app build with ngCordova.
2734 */
2735ngCordovaMocks.factory('$cordovaPush', ['$q', '$timeout', '$rootScope', function ($q, $timeout, $rootScope) {
2736  var throwsError = false;
2737
2738  var deviceToken = '';
2739
2740  return {
2741    /**
2742     * @ngdoc property
2743     * @name throwsError
2744     * @propertyOf ngCordovaMocks.cordovaPush
2745     *
2746     * @description
2747     * A flag that signals whether a promise should be rejected or not.
2748     * This property should only be used in automated tests.
2749     **/
2750    throwsError: throwsError,
2751
2752    /**
2753     * @ngdoc property
2754     * @name deviceToken
2755     * @propertyOf ngCordovaMocks.cordovaPush
2756     *
2757     * @description
2758     * Token send when service register device
2759     * This property should only be used in automated tests.
2760     **/
2761    deviceToken: deviceToken,
2762
2763    onNotification: function (notification) {
2764      $timeout(function () {
2765        $rootScope.$broadcast('$cordovaPush:notificationReceived', notification);
2766      });
2767    },
2768
2769    register: function (config) {
2770      var _self = this;
2771      var defer = $q.defer();
2772      if (config !== undefined && config.ecb === undefined) {
2773        config.ecb = this.onNotification;
2774      }
2775
2776      if (this.throwsError) {
2777        defer.reject('There was a register error.');
2778      } else {
2779        defer.resolve(this.deviceToken);
2780        if (config && config.ecb) {
2781          config.ecb({
2782            event: 'registered',
2783            regid: _self.deviceToken
2784          });
2785        }
2786      }
2787      return defer.promise;
2788    },
2789
2790    unregister: function (options) {
2791      var defer = $q.defer();
2792      if (this.throwsError) {
2793        defer.reject('There was a register error.');
2794      } else {
2795        defer.resolve();
2796      }
2797      return defer.promise;
2798    },
2799  };
2800}]);
2801
2802/**
2803 * @ngdoc service
2804 * @name ngCordovaMocks.cordovaScreenshot
2805 *
2806 * @description
2807 * A service for test app screenshot
2808 * in an app build with ngCordova.
2809 *
2810 * @example
2811 */
2812ngCordovaMocks.factory('$cordovaScreenshot', ['$q', function ($q) {
2813  var throwsError = false;
2814
2815  var DATA_URI_MOCK = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAABYCAYAAADLGnoRAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAKLJJREFUeNrsfQmcXFWV/qmtqzudpLd0upN0kk46IQsJEHaFYAAVHFCjrC6jqOMCzAz+Hdf/oAjiKHFBnHHUERBxBNmUXZF9DyGEJBjSZO0knXSnO72l91rnfK/Orbp1+72q6k6nl+Sd/G666r37bt333v3uWe4553ri8Ti55JJL45M8LoBdcukIAfA7u9vHaj8XcHkvl09zmcLlHi6PcVnDJTQWOnig00vPbA7SzuYA3X6l1x1ZLh31AJ7G5f1cLuNyNpd8mzp/5/IQlwe4bOQSHc0OH+z10vYmP12+fII7slw6KgFcxOV9XC7nsoJLWY7Xxbi8JUB+mMuG0bqBGD/ORbOL3ZHl0lED4ElcztA47WybOlHu5/pYLHpXNBptjsViF8dj8eU+v6/E5/OT1+slj8ej6oa5vC4i9oNc3h5xeX+WC2CXjmwAQ0k8k8slXC7kUm1WQL8YqG/39vb8ed/e+vsa9tZv9My4MN7V56HukJd2Pvn16T6f733Vc+ZesvT4E8+uqKicMKFwIvn9fh3M0I/Xc7mXyyNctrgAdskF8NBpmYD2A1xOcADtzr6+3gcb9+17qLZ20+qO8k/0t3Z5qbvfQ6GIh6IxjyWmWr3m//y+OLU/dWnNgoXHnn3s0uMuqZ5Tc2Zp2ZQJjGYdyKAeLqtFxAaYd7gAdskFcHZayOWDUs4Q7ptG4VCoobm56S9763c/smP7tqf6Z1/ZBatuF4M2HPVYQM202AWYAsjBAFHHs58+ZvqMqgsWLlpy4XEnnHjmlPLyPIjZBnVzeYbL41J2uwB2yQVwiqDHnkMJY9RZZG9Bbu3u7npxx7at9/39rQ1P9FdffQCcFqCNRBNcdkg35EkAOs8fp+iaLy5+9/IVK086+bQLSkrLTmWO7Le5pIPLcyJmv8Cl3gWwS0cjgGExPltAC0vyZJs6vZFI5PWm/Y13b377rUdbii6qb+zwUWdfQjy2RONh9CvxMa8vKojRMZURWjDhzePn1sxbydz4o3xqqTBuk/AAnhQwA9QHXAC7dCQDOF9ACwvyeVwqzQrRaJRaDjSv2VW344GdO7b9OTrnS1tbwGn7vNQX9lB/mCgSY+DGEtwTsPIKF/WKsO09BL8ItBlkbjyjJEonVYeoprTNx/rx8cyNL+bTH+JyrMOl+7k8xeV+Lk9z6XQB7NKRAOAgl1MEtOC0C+wqxWKxTc1N+x946m+PPfrmG2vXlr3vrng4iuMeC7C9/UR9ocFxXEs8Fr7p9aSO6aIzeVKfk98tHZmoeEKMFs8I08lzwlQ+KcocOp7HQD6NT1/AZaXTvTDVCUe+j8vLIna7AHZpXAH4JC4flbLQoQ4suw/39/fds2vnzjfWtZ8U3trkZy6bQFkowiWU+DsqNwvdOBCnmaUxOnNhyAJzYTCuZGlMTCdyuZQSS1vzHJrZw+UJ4czPc+lzAezSWAXwIgHshcJ1fTZtNFDCaeKBcDj8clco2Fl3wE9v7g5QfavP0m3Bafv6SRmmjuPyfWlzpOl2Ltcwh+4qnxSjpbMjtGx2mKpKo5TnSxMFCrmcLlzZdp1aaIuI1+DMr3DpdwHs0mgDeBalln1WCGeyM/aACz3K1/81HPUe6Oj10J5WP23b76fdLTBMeSnKonKExeaD3cnr4CS8WoxIo0W/4nIluG7p5DjNmhKlBZURixuXTYzZWbbgKYZAig9IqXJoFx5fj3K5lwH8hju0XBoNAMMQdRfGtk3dbuEyf5KBWt8b8hC47RYGbUObj1p7vJa4DOAq6uiGISv59Tou3x3le8YNv4fLi9CVSxiekwtiLFZH6V3zQjS7LEIej+O1eC4w2sEZZTmX6XbPiQE80R1aLo0GgH/Lf67QzkNbfZMS4XvwYNpqIYAvae700ivbgrSVwdvd77VAatqjYKjq7U9+hej8GqXWhH/99HWeL43ETZ57ffwi/vNVEYtBiGKC8arHB+NWYcLSXTYxSmctCNHSqpC1BJWFsGwGI95lAuZSUbMhQnvcoeXSaAD4Wv7zPfmKgIDPUSLKJ43gJfX05iBtaQhYOq6dIRlc+GBXGqifE84HqqWEK2X/CN7riSJBBDVp4AZ8yM9j2V6mlUn5MVp+TIhOmdtPAV/Obc+TyQkgjjKA/e7QcmkkyOQz27TPbXbghU/yul15tLUxQP0O4AX19KWB92oNvBCwrxph8ILWcfmh9v2blPDNtoxsyjIO3f2lrXl8j0FrnTrHVa5eTbLocoeVS6MF4Ebt80zzPKzI0HlhqALndSI4Z4RTS0Uwit2onb6Vy7OjdL+ruGySzwVcblH32N2LNWpBIIN47c4Avb2XJYxwTtIwkg+oKP5Wd1i5NFoAhveRMjmVkOEO2dHjtXTe1m6vo68yJPKe9JXR/+Si1lXquHxrFO+3R7i/6j10139R/e7qTU1UzQd99PrOPKptzDxZCVVon1vcYeXSaAEYa7rN8rlYA56l0wK8O+CYkWFAW6JzCtyw1n5IO/31McChELDwG+37d0iSCGDJSxnd4C3W0O6j1duCVNvgt75n4cCK6t1h5dJIkWlsaRcQV4pOVyVck9qY675VH6COXq+j+yPEZojPQuVcfqqdhufSfXr9p68bOWPtudendRr673kC3FIRpVdaymx/wu0y4E+AeB+D+MUtQfLzVLdoRpgceqyvDb/jDiuXRgvASoxWNJfLSxApaxsCtLfNl7bGmyY6Q49MF52/pw1sTAxfMy4pYlDBFfH4LH1sY6CXGgBMTgB8HD3KNhOA435Bb1OkgXvk+4e5XCyTjKUPT56Y8LfG/TaxOI3Ja15FxApTtCHdh3qPO6xcGi0R2gTwDPwHHXBns585rDNOwLliKXC/1wDMNxUn1+gLOYBX6eKZ+p4LG/8nSriC6nSvIRHcIlKDpQN396ZO4Du4sdfjaJOeZaghLrk0ahx4rwngnpDHWlKxoGIzhuHE0ZdaFII19mYNWOCytxqXwDj25UPse2wQddGXbwiXJUMnR+IBOGXAqwrW8i8qdQD3lB9MXIw1YQcPrQAlclXbTYBDpjGco/uIoKllxbO1Sf2xppb23vHUf+Vvnw3AcyykxBAc77wiaojOcJBYIp9h9YW3lZmv+SpKuSGCY51KKeMZqF/EbqSZjQxCXw4aHHkFl7/K549QwhNrtXa+TqSD32hSAVxFn7A6D33Yj+weEp5o34UiDcAh4z6ONkDkYTgwGPaNgy5jbNwhn7FkOi6Nj3YA1kXdai4+HsDR/EDclgHDCSKSgiccI67RTt9ECa8rnTDY/5/2/UcOD69I9ZH13FyjhsNGFwFE5Lz6BxG5v02J2F+d4D76cUr4OIN+KhOKFYKBpSW4WkadewA9X1nrD9IQs3iMU9DiHV3B5Xyxl8Dw2cnH6+TZ/5bB7Dq2jLAOvFPjmLDQTgZ4JwTjAzJjQDfUfJ0hSv43pVwV3xQAk43uO1U+Y6a+zc44NQTaIRzApJs0UMPy/G5TA6CEp1iPfF9MiaUlUtIHQBx3TvdTpT3HepEcjgbwQpp5kcvPBMDHiC3gWJkkf85lDdc7x4XZyAK4VTiJMiAVI+MjInYC6TGz1NObNqivpFSwQFS4rOkuWWHovqu03zLp+4O4j4fJ2T0T676PymefiPgmbTYmm2tEmkiw9WhCz3cQoc014NhRAF7k9P4zpcJC/8Dl85RYisPfB+U44sn/yPVXuFAbOQC3a1wE3LQcAxexskFtCcXKrpFyl5xH6e6SvxDjlUkAebl83kXpDhUmXUupzDgDCvfJ4/OSx++zyodZOngiQxjg9zUujP2WzrSpAz/p9dp9/1KpGGg26rzrkh5S2HAUgBfZWH5PCV8BjJNLWUz+JJdbuTyEv5Rw4EFyw15531NdqI2cDtwvnGSO4ppW8HthjCblx6lDfIZ70m12P6FE4DsIIYf/bvfuRVQlTddUYqsVvgcAxrLwL4jx+TyRTCpAiVF+ICEFIDa5s9eTluFSo9eEC39QM7S9z2g6JBPMcwLg04SrQxTM5Ik13eDARzJ4/fLsqmWcXMWAvc+sx8cwtd/D9fHUJvD3e12ojRyAlT65XD7DQmeBF0nhGjp8Ccd/e3dJHF3FOuwAw8W518e/RSlr7W4xHiUJcbkKjB+6KU6F/Hv4DECr38JSzpRJMaouj9LssiiVF0VpQh7qeeggg7ex3Ufbm3xUd8Bn+W1HogN04QtE6sA69UXczweMbq7mfsK541Py/bsQz7kfdVhGQ1+8vowAPtK9sJAX7TL5jN0tMgLTDtwujQyAdW8iK4EdgFI0IaEHI/G6xlVvNkVRBsGPbdos0kD+A9LStILzAlUwlJWyqF4xOWZx/IA/LtyVLCcScNyZDNxpPLEXwCquiczTWVtH/ufFVT7asNvPJUD7ebKx0tYmgIxskvC0ulQuud/Ou8sg2ABu5loXdfd7Yr0M4knpdgDAWd+MbfcRPl6+QKlluh8zQKMuhMYmgPV1PIsDw5A1kQEGAPu8HgUKDN4ZWl283GxbgsJolcb5AMRiBuwJsxO5qQDewry4tfasQArYeLWUsU7i9dTJUVq+IMbtxWn1tjwr1c/BVKjgXRqAcyV4i/mZA4ew/++k/LQxW6xxYIjgI7KExKIpnvGH5fljuet5BtNrOVynpA+oB7iRdXzdXwfxmyqmGxlN1g3TvaBPnsM5GQzHb3AbHpHeYtxOfITes08kmehgAazHBVcokIEDQleFs78ELWDJqUUDbZdgzQ5jhXK8QLhxs0J8CXP25QtDdFJ12MqI4TnEGAcse50wK2z5MT9fG6SekJdCCQCXDqG5HdydENpCQAcSxGtUpun+kChah/HlnSf6Zkje01v8Iq/k47D0wu1Td9/s4+NI1vctrtPn0B4m4jtENQrI4Qgfh23gM1z+jRJr4RGxAdzCbf1RawJeS8q3/W98LnyI93cuJTK+YJnJz98hvSBr6F3cdqvDNRg7y+R51HK9Jj4GBoIVD6zdX4xjWn30+Styz/n8faNIDo8T5Zarga85QWw356hxy8fwXG7ndvYYdTEWTpBhvYPP1zu0GZR6+NvI9bZo52Ac/LioKjVy7HVhPvdw3dBgAWxFJnGP+ooKmCt6SM8XBY5TpwH4atYr77RrkMXV9cLN8sQIsk2BDeB997wQBQPDN7FBUgCID3T6qL07GZg/U6vyS+7rVQ59/S/N4GZxmljcY2XrMGgKpdaeW2gQuzfkQODs79IFDH6R58sgN/3D4UCB5TlYwVfZDJjpYsQ7zmYCXym6O86doZ17yKi7lFJr/K8dInivEZtE0JgMETv+MT5/iYM3FyatF4UTfpHrQXr4CyXW7tVzUL8BEGAlQY9pxwR1Np/7pExU2fqJlMqYGMuNfsI28gk+Dwv8eu0cfusF+Qwbz2cdmsb4Vx6B/6GMvtze+8UgvMSof76U0/DsdI6cCcB98kAqpdRBB0Y0jmHI2SnGDUvPzaBX7qNU8EKV4upLZkZY5E2C99OU8OwBp/jdENSBm2Qgwj3yDUwOp8wN0ZYGFqN7fNCn9WTttRn6quu1W1Qt+ITDoOZNSQhztXrNwi2Hi6I2EszN5BzcAfoyv+Db+AWbSQVutAGvTlfRQBdQ8/drFNemQ4i4wqCnhPMHaKNMSHtlgGLAw9HmTq73Dya3EeNqg6hteEfXCniR+qlW1An8Brg0ligniMr2PwL8RSJp/FrO95H9xntoAxz9D3J+n1yzUSZVJIGYz+Vurvde7udeEXX38nd4oEF6OhGiOx+zW79YJH9hyX9Cfg9j839lsqiTCWCd1L1KQA+m8hKXP+YC4Ea5qEDE6DropQVclC4qThzwuFJBAoszvDt9gFQCAxWsr567pN9qkxJJ526X2RW61gZKrcvmQleKuKR0XYgovdhCZX5lhHY3sxgd9VQ59Mc0TNXoALZGbSyxVAUDnhZSOM+YyA4nLZb3tUEmOL9Yy/Uc29MEqM9qAxED4BNGW/UygCGqXi6cd1IWHVJJWR0KKEMALwB1g3xdy+UDPMCV3eB+Pg+pDGGo5wqYf2VYtcOyNAWC59cFch//wud0J57rBLx9IlY/Kccf5uvx+TERUTOlLfy2gBeT1XncxmY5/iC3sUZ+d6GMuX/TrntGAIyxdizZ5JUTG4RiaooTIwjmOZmgP8W/p3wKHuXfg7X/b3LPn+fvcFyylmCdkqf2UnpUTYUyZAFsnnQxepNh8HEi3clhGkCwrDpC01M65SWUHiJ48SDHhz5IcaOWVxgmm5qpESoIktcwsDlFDVVqul4HJZeGPAQrtLEerC8hbR0BgyOMR+BMP+PyYwGf6clmctrLKd3FFHaKj/P1N3CBqoCdJ57P8tuFlEobBMC1DfEeIJIuEP3zGxp4Fd0kAxV0BQ/UyRnaAseGbni1Dl5xNDlLvt6pgVdNAusE4NM0W4A50ZxMiST+oFUaeFUbMML+Xr5+kuvr9oi1cn+lwpTsSBkD1ygpg/92ipV/pQZe9Xu7RAIgkVCShuNM2Y/3GzO7BVxkpgC6fKm5a5dmEKgm+21F0wDM11eXTYrT4qqI1Z4xK5k3mQtV0MD9mlYkFdVJMZqQFyv0pNahY+Scu2qBxo32Ji3LHkQnyYbjKZrhYLk/HIQ+36Trhvz5bRENdZpvWDGXG+dhCHlRawPeVD/NohN6NWktYiNe50ofUQPXpt8k1t275F5PI+f9qdSk8p82xrQVwsX6yPA10OgRSs/AatJK4c54Nnc71LlTuOBUSrkQg/BONgsTWmIzOZRo9/W0cf/tXJykm9colf20MhcA73HgNAk505s2cNs1o46T29wu7drZlcVRD5aLhJRhi4xJI5jjwJhJqXVm3VAgBi1r4qnQOHAvOS/51BjPIKruFz7RmvO3xzBuHG4A91HKp1un7cb3IkOa0CeZuAO3fYayL4HFtfse9DqBWGiVd9/LGazYazSpYmkWlexJm+PHas9ll92FwuE2Z2j7BPn7Cjn76r+lGXtP1ZsXEFvtiOVcp9M1O8bawayGUMpzsToXAOthgJZIibGLQYy/GoBbKBVDHDCWN0wAW4PA642XlBXGCvNTVueAjTEh4CTi2FCBzbEk+NFnFn2nxVPH9pPzkk+N8dCSa8/w+PL70iy/5ZrB53A7cdQ6DKawDadWVG4AWlMJ0gZ0Fw3Tum4Gmq2J4bVOlbgvWzVrfibD22au22Gjq1do460pw/WbHCaaydqkt9lpohHRd4s50YjRSlnpT6KBe2arZbB1anxlmPSmcVnAZbGopwETt/4cOXByUFvGq3QROiqzkRIXFsqMblKLzCCFrJcWB3zxSdglUBuE5vplaBBW3R6bY0m9CDtJ9IS8FQa3dMrAoIttG5QebSE2L67v1lBGKZG8bQQ4cERenGnVzMQNpxpW605yDrjYnuX5Nmn3XUzpiR9yVXOmyCSejdvvFqlqTiYA2xybSKnosOYsjht1GZ5ZsaZCZSLF4c1+PivPrETwsFMA6aFUlNsacwKSOkExTr5fQFupATffkIZy1oHBgfMAXmzDabk+etLC67ZodZ0U9w41s8biNLE/6i3WfJVDNgNo3yAAvMfGsGLNbnDAQCL63pCnIgcDlp9SJn4So5Hl4YX7hcOJP5WZZKYMGDU5dR5mAA/FvcVnvOMIOe+I0ZOBK4a151tmo67kQnmaMS2bFVupZBMy1OlweEY+cwIf5P0GNcAcHGI/12vgPsdQaRSje9MGvDVixPsfMeJWiqS4T1SGmJ1xIpOOoQCEGakIT2difnJDbF2M3u4ggpIx+zcnAOzxtnV7yhE5ZOg+Oj0/iMHRZCMaPgeo7Wvz0ea9SMiXJso0ZeASszQ9uV4BGH7Z04qjelID3S5wwEaUHSs0XLl7N2uTXNUQ24jnMO70PsezGNYO5b49GfoYH2QbcWPCA2tSDh1nGLaauTL5rLYxbsGAd5YwmH8FM+S2qrnUSDvtg3kIbdoFmHEtN0REJPnFoV8To/U10LliIbSzou5WXLGx3TsVwQZaVNO9miUUfwcbyaJ7gG2Kx+NrEJH08pY8K0F7PF0X2eXQRpXGVZsU0DFRYflsenHUNLIpGqtxwH0GJwJ3cVrvnZalrS3aJHXCEPoS1ThINvDpFu/BThCRQf6G3TiNaxLMUPv5nGJoDE6lai0RKWSnku40+iylUjl9nkELC/u2bP31ZhFRWrWL5+KuigpSgf3+dA7coYFgtkOb9coY1trlrdlU76eWTp+ub2It93H5+5bTG3LY1gXrZHACeCgWi152oMvX++I7QXprT0AlHtA5ptMSwvGGHtardODiCXEqKUyTYOaMAwA3Gsa6Ykp3J9Vpfpa21miSy/k8KAOD7Eu9PCdPDhxcqTFvD+YHeMAfpFRMdlWWPi7KoI6p+1yQ5ScXZ+gn1qi7ROVQy0wqC+bLuoeWGN9UrPpTfO4Rm/aKycao680yY9YZVkQqDCbyYxlrwY1aXW8GACcHen/YMwei7dodid0eNC58AdnEmVqJ4/sT+ak37wvQ7ha/FfOLOF3o0lxi/Pk7Bzq9K9fvKdj0lw359EZdwIoT5qt9xsBtzPJClB6TnKhKC6NmUvcFORhERpuaDV1xAtl4y0lAwKIs4MC7e1Wzup44yL40aX2ZkcHyCkmp4BCea6NmjMqkq8/NoBt3aJNAJoxUZ5Do0I91wsXVMtOZDuohjFNq+etVh9+aYyfZZtvHVn+A0638yP5EbDCle2PF5SaOz/JwGrULKtp7sEl4gEHIU9T8MFUURXU/42TDcKDY3uSnjXvyqJ51WuRsBphgVAJXtBLuCcCZ81JTu4fauG3US3BrzyRKidARcnbi0PX35FJHgOc9uGRqffNQuki+ZSyiF55OPABrtcEB+jAf+7Vhof2IZnnNRLeJcQXj5ivczsccfH0VGDF4C8EZpS/vSF/ez59vdFiiOUfUtUiGwZyJ1osYvFQm2QMOk8RSh2cW5/OvSj9WSF/s2lim2UuetWmnm+usFp32eIkGmycTxEs2jFQ5QIUzSIfewQJ4QJJ3WKHzhPMqa7SItBCBVWaOYzLMwslnEEuI0vTK1jwri8b8yijNKY9YscEe/gdAYm+inc0+2tPqt7hpRECJNdl9LV7LqGTt4mul4/FY+rXN9i9Fmm7bRfZrwF5KX8NOukZCZSidmMZ9wSGmaHPMWM6FBb/fi7TvSCUE391VMhAh3n0tx7aekYLBDRdMxCT/OUN9JLi7jH/jE+JBhpzbHxVREuUVAxRemUy8lMM6qQM9KYxiukw2L9vUuTCLygD7CyKEymVM325T53KRaNpsDLCKVsv4gHTzKeG0z9gwEMVUppGN9xk/l3wamAJq0ACuVIM5oImSEKNjCR1T11mPywHAeDiFrA+HGKge7HpY3+qlV/0+CnhCFI+GKBwOUW8oRqGon6dU1v19AZ40kGUd2yR4U4J+ZmNhXB5MgWacs8tVXKaJ2d2a1dUKeSxL138xW5ZohqKxnAv6UbFqVmjSw39IXDH6/R5ydn81uUqIr/uOiISYEG/j7712SQH4OHyJfyiTJ0Idvy5g3yaDdBXCI4280QgwWCmffyc67WCljgZuF0sxV3D5Ehz/+Zge3AFD0g1i46gkm1TEXH8D11P5xK/lzy/oBiXJyvl5+fq/5BydtVaefTWlfPtftYmy6pe6HxTpZIrhJ/4lGW+dphEyG4C3mQCGCI1YW2vjL/HICg8Ut+fK7GSute2XzgZlBky+vKgV7cM6bUi53SaW1izt1Td8ayFiWe9xMOIoUO5Tkw2kDIRRIpmBAXalj7SMEIA9OR73GIMRAejXUyJnN2nW1XcZton2bHqwtPcyt4cBdas8r/v4+y2i1+0X3ROc+Ur5nXoRvXFtD9cFZ8NyCZZFHufvv5OBeYoMVLx8+EnfkeV+Mw0Jlf8MTALJ9RCG+Y6M4a/J+LuTMm/v811KBA5A93yE2/hvGRcQy6+We4c1+SdOagQC/vk6WJvfK5Z7QOU1B7H9DwLgGunzj2QMgvMiZhiZVT8mAI4NhgMrwOHmi3zeeAe2GkG6myiLrJoevFebIabKjL/Txoh1kNJ9iAewyxGwzNrRPMNias2SAStNTyypNmiTmU+zVncfhn6aSxiBHOvZvdNbRfe82sFY+e8y4Bfl0jEecH/gAYZXdYuoErj+GzIJFGt9gFT2Ga6vr9Ejkuf/y4BcTgODLWC9vSLDjg55Dvet96+W+/cFEX3LBQA6fU4kp6DTZMBtvM5tfE4mH3hT/dzGWv2PEimUiZ4TAKvxv8GhHnJp3yNSyDlSeoSTQdVAwMk/GsazrABWOaIrpFQyR+pQHJjSLdHN0sFJIusvtgFwt+hBXxwlcTIkIk82C3RS98rLi1P5xJi5N9R8BzVjOAk64I0ya/tkoog5iMhdMtHifb5hMxjRxj/zgHxFRMs50hYGH1LnPCbZJ3Lh+KrNuyRFDfTpk2UCnCKTOLgOIm1+ZIrBYjxbJdcCZEsoFTQPUfznTil1hH4goHw2S/8Qt4t2rpF3WyCgu4PP3c7njhMu6yF7ry608SdJ9fPPco+TRdp6SZ7b9hze490y+eIdbudrdjv8Vj//FhJabBIdfZr0CxMADH7tfP4Gec5JndsT17ZWsNkRzycvQ4XqQV964W9/z6c1O/KsJRxc3taZNruqgQBRZUB2ypHc1DsbGRk5MHjOk89fFu5CFUVxuuT0Xlo8Pc04+EPhOCQzs74fVHLnuEOhw7U7ofjjJgGsErTx8Zco3WsIqVt+nmOb06TNPJmkayW+NZdrq+W6/Xa+wcN0zzOF29Y75QzLoY3pove32sQxD3d/i2WSarXJrpI2xrJx4KjI4QrAFQAs9NWkr1m6JVoXlWpyAM1YIT+lhzNuVCyoAOveeQP6rDuFjIed+NL0LdO6Kw701RnsH1kNR0O1xPO1dSNwz3uGoY19I/iO9N1RMpI3hzq6438NgBqKeiz9V7dEK8ZhGLLGC5VpVtqQblXMlzRCBs0YTwBmgBaKo7wTvYfS47h76SjdJnW8kT+HOrqcf4zapU/fqU+zRG+kVFrZuSK29I81EdpGCgBHLdIMWMl0oMiFPTGYpnqa3GrvOHjPsDl8g0GMZGz3G258kMW+YhjJsAZe58LjyACwnutpGhwnMKjTFOUUB1bba8LEDnfKmaYoxuCBEeKbDr8FvQlrjLWHcE9YeH8ow3kYCszUt0s0ow28qvqUeoCdIvLT092WUsqJo5/G+G4MsjMgjB9Y9oKVE0sUTwmHhZ4FJ/p3GZch77PLgY8QAOsiYgX03XkVEVq/O0BwhVQcWKhVdKESmdFn2+hSp2b4LViwTztEAJ+V5fwSm2NL7SQOOKxUlUT1+yMB70TtfpvGMHhhNf0BpfvQXiYl5qBCYRK+xYXG+KDB6sCWA0NVSYQWToskE7FrA9xMLbM4y4SAKI4/GdeUHeI96ZEu66V9Xcy1WweeZ2e8wYZuM0sHJHUo154brJFjeQd6SDRwCNiZ47sH1/2s044CLo1PACsvHRLOWoS8UKfX9NOcKRErR5RliU61pMc5LrNpT1/4hs/pRQIyncMdCulOIt+T9tcbg1QnSAqL7FSG8qKY5Zdt0DRjchuzG3rD4oy1TEosj/2EMhumsIx2oZmG1aXxL0I3C9cqFtER1sp90A1PnxeythtBwDy4sGwgpoNlThadepYmitoBcChkJnEz29xlU1/5QEP3tXygEUI4qyxqBW8YNJK5oIcLyOjnV1mkRqoWeAWdLO8zJjo/nCJeG4rvsUtjH8BR4TQLxdCD5Yj10IVnsXh54uwQvdQfpJ6+RPieIa5BND3n6es8epK73517ffwOA8C6mH7coViquW2dQ7ZpkgMIaJzP7b+g1f+opiNiotqHX8f+xNVTonYbrY3IbgzD4QxiQ1soQ+hjSWGxi4gjEMAmwJIcCDG5i2dEqKnTx5w4QL39VmDfDuF8RaKPPp3BeUOBTV9oP5XrD4e3B1a2WkRqULsSAo63cvu3OlyDfvQh0GnqpJi+awQ5SBUN7hByaazrwCDd8KQHh1vbgS6bFbK4leTK2k+5b35V4CDWDgd1ifhfQCmrcTayMgVCbJ5TEbGikAyCFLLABbBL4w3AuuUWERqInDglyZKLo7SMRek5Fdi90BJTETP6eob2Nsr5r2miHZY7NgzTfSEQAE72PQLib1H2jdKwNvoLqAaVJTFaNCOq54CGpAC/7tWUHvS/3x1CLo0mZQtmUIT8Ry9Q+noiRFRE9iBiZgd27nt1W5Be25FHbZ3IpmF5a2WaIGKHMKFkI7u2s20JEkOygpppMWuv4qUzw4h7xv0iEgWeSuaWMdjc6p/IJnf1YdJfXXJpyAAGIScP4j4vMY7Dgoxg55s7er2tz7wdpE17A9Zeuu2dY/CGJZcXwgNVVk08AuS7PqUmTKfWhGjKxBjqIfYSHmPmWvYbMmk96PQbLoBdGosAVnS+DGxz90AYr37S2LD3tpf2zu/HbghIRtfPfLovlA4g28+U4o9prNKTzjYdrzd4q9c4h4I4ZgAVyfCg3yLKCMkJ4CoJNaCqFGJzHGumCBU82+b+EFQNA1jGrP8ugF0aywBWGPuU6LDHGufWdrS33bi5peKh2oYAIXl7n+yrGx+lSEJwXOSzBkDhBjq7NEKTJ8STCeoF68tkYrrURsL4pYC3NZffcwHs0lgHsCLoiFdx+aqpI3K7Txw82HH9gf4pryKH855Wn7XJWJfssTsSYAZwYSWfURKlJVVha6Nvm9jeKuG4yA6hJzjDqvadIi4Par3XBbBL4wXAimaIoQeZ+vSseVhIRQKzVZEo/b2500e1DX56hzlzM4M5dIhA9hgittoGFEEIkxm4s6dErUwa8GcOBgb8EFw2kUTtGhrovvmwAPf1ofTLBbBL4w3AirBOiiUkRLvoFmUs58DQ9VP+uYaufi/taPLR1qYANR300sFeZKNMiNk5dVp2SYQ+O5lFY4Q3AqDKOAUdd3ZZlKZMillgNtRjcFmEFGJpyXT1xDIRMjj+9VAeggtgl8YrgBUht9J3KZWNT1Gj6JK/AKjhO90d8lI9i9fvMGfe0ey3tlmJxpyBC4PT1MlRWlAZoWO4lBbGknmqE5tw0wDDl0aIFb6OBm4LslU47l00+A21XAC7dMQBWNFHhCObu9kh8x5y9/6eBHQwdNUd8FvJ8na1YPsUTyK1h4esPXmxJxPSu0IkXjgtbHHfQRAC1r/N5QPGcTh5wEEDTv7DdvMugF06UgAMCopuDM+oauMcghyQ4dEKYQNHbu7y0sbdiT2QAF7LCFUco5llEQvAAd+ggLtAfvczlO733SugRcLvYXfjdAHs0pEEYEUwFMHQhfxMpca5u4UjW66UsFJjwzPotNB1fYPfmQEWcSQxh4HK3KHufkrECW88XDfqAtilIxHAipDs7loun6T0RGp9whWx6dZQE8XlC7eFgcrcBxeuoNcL1z+s5ALYpSMZwIpOFb30Qhu99GeU2LC7Jdf7oISLJ7bsON44t1G4O7j8iLiSuAB2aVQAXLur3S6A/XATdoC7jgYmu4PrIiKU4EwRynD9WcJZVxjHEQKJfFC/Eu4+YuQC2KWRorToH2zxGRt5d0ds44hlpysoPYMlRO3fUGJjpw/aXIfskkiT+rwBXsQBwzC2TDh5n/uaXToqAPxsbZC2A8Qjn6YNa6/YZhIxxvBH1veeOYkSnlGPC5eG1xf27MEu6rrfMnr9W6kDHbjJfb0uHVUi9MduidOM0gidMT9kOUn4vaO2jxHySSvXzALtOERpBCmaqWcfEz33xdF+oHBCWVztitAujQIHhitjfaufXngnSBt2B6g/PGrboGBtFktA2GD5Ae14ngFe7GqOnc8vHG3wYqoL8fPa2+ZzR5VLowNgxUEa23308tagVTp6vKPZv/UC0HMFoK1S4Pp4lQ3ARxy0sBlgomvt8tLmRj89sznfHVUujRj9nwADAFIAdCgbzMwPAAAAAElFTkSuQmCC";
2816
2817  return {
2818    /**
2819     * @ngdoc property
2820     * @name throwsError
2821     * @propertyOf ngCordovaMocks.cordovaScreenshot
2822     *
2823     * @description
2824     * A flag that signals whether a promise should be rejected or not.
2825     * This property should only be used in automated tests.
2826     **/
2827    throwsError: throwsError,
2828
2829    captureToFile: function () {
2830      var defer = $q.defer();
2831      if (this.throwsError) {
2832        defer.reject('There was an error capturing the screenshot.');
2833      } else {
2834        defer.resolve("path");
2835      }
2836
2837      return defer.promise;
2838    },
2839
2840    captureToUri: function () {
2841      var defer = $q.defer();
2842      if (this.throwsError) {
2843        defer.reject('There was an error capturing the screenshot.');
2844      } else {
2845        defer.resolve();
2846      }
2847
2848      return defer.promise;
2849    }
2850  };
2851}]);
2852
2853/**
2854 * @ngdoc service
2855 * @name ngCordovaMocks.cordovaSocialSharing
2856 *
2857 * @description
2858 * A service for testing via social services
2859 * in an app build with ngCordova.
2860 */
2861ngCordovaMocks.factory('$cordovaSocialSharing', ['$q', function ($q) {
2862  var throwsError = false;
2863  var message = '';
2864  var image = '';
2865  var link = '';
2866  var number = '';
2867
2868  var socialService = '';
2869  var subject = '';
2870  var toAddresses = [];
2871  var bccAddresses = [];
2872  var attachments = [];
2873
2874  return {
2875    /**
2876     * @ngdoc property
2877     * @name throwsError
2878     * @propertyOf ngCordovaMocks.cordovaSocialSharing
2879     *
2880     * @description
2881     * A flag that signals whether a promise should be rejected or not.
2882     * This property should only be used in automated tests.
2883     **/
2884    throwsError: throwsError,
2885
2886    /**
2887     * @ngdoc property
2888     * @name message
2889     * @propertyOf ngCordovaMocks.cordovaSocialSharing
2890     *
2891     * @description
2892     * The message to be shared via a social service.
2893     * This property should only be used in automated tests.
2894     **/
2895    message: message,
2896
2897    /**
2898     * @ngdoc property
2899     * @name image
2900     * @propertyOf ngCordovaMocks.cordovaSocialSharing
2901     *
2902     * @description
2903     * An image to be shared via a social service.
2904     * This property should only be used in automated tests.
2905     **/
2906    image: image,
2907
2908    /**
2909     * @ngdoc property
2910     * @name link
2911     * @propertyOf ngCordovaMocks.cordovaSocialSharing
2912     *
2913     * @description
2914     * A link to be shared via a social service.
2915     * This property should only be used in automated tests.
2916     **/
2917    link: link,
2918
2919    /**
2920     * @ngdoc property
2921     * @name number
2922     * @propertyOf ngCordovaMocks.cordovaSocialSharing
2923     *
2924     * @description
2925     * A comma-delimited list of phone numbers to send a social message to.
2926     * This property should only be used in automated tests.
2927     **/
2928    number: number,
2929
2930    /**
2931     * @ngdoc property
2932     * @name subject
2933     * @propertyOf ngCordovaMocks.cordovaSocialSharing
2934     *
2935     * @description
2936     * The subject of an email.
2937     * This property should only be used in automated tests.
2938     **/
2939    subject: subject,
2940
2941    /**
2942     * @ngdoc property
2943     * @name toAddresses
2944     * @propertyOf ngCordovaMocks.cordovaSocialSharing
2945     *
2946     * @description
2947     * An array of email addresses to send an email to.
2948     * This property should only be used in automated tests.
2949     **/
2950    toAddresses: toAddresses,
2951
2952    /**
2953     * @ngdoc property
2954     * @name bccAddresses
2955     * @propertyOf ngCordovaMocks.cordovaSocialSharing
2956     *
2957     * @description
2958     * An array of email addresses to blind carbon-copy an email to.
2959     * This property should only be used in automated tests.
2960     **/
2961    bccAddresses: bccAddresses,
2962
2963    /**
2964     * @ngdoc property
2965     * @name socialService
2966     * @propertyOf ngCordovaMocks.cordovaSocialSharing
2967     *
2968     * @description
2969     * The name of a social service to share content through.
2970     * This property should only be used in automated tests.
2971     **/
2972    socialService: socialService,
2973
2974    /**
2975     * @ngdoc property
2976     * @name attachments
2977     * @propertyOf ngCordovaMocks.cordovaSocialSharing
2978     *
2979     * @description
2980     * An array of attachments to include with an email to be sent.
2981     * This property should only be used in automated tests.
2982     **/
2983    attachments: attachments,
2984
2985    shareViaTwitter: function (message, image, link) {
2986      var defer = $q.defer();
2987      if (this.throwsError) {
2988        defer.reject('There was an error sharing via Twitter.');
2989      } else {
2990        this.message = message;
2991        this.image = image;
2992        this.link = link;
2993
2994        defer.resolve();
2995      }
2996      return defer.promise;
2997    },
2998
2999    shareViaWhatsApp: function (message, image, link) {
3000      var defer = $q.defer();
3001      if (this.throwsError) {
3002        defer.reject('There was an error sharing via WhatsApp.');
3003      } else {
3004        this.message = message;
3005        this.image = image;
3006        this.link = link;
3007
3008        defer.resolve();
3009      }
3010      return defer.promise;
3011    },
3012
3013    shareViaFacebook: function (message, image, link) {
3014      var defer = $q.defer();
3015      if (this.throwsError) {
3016        defer.reject('There was an error sharing via Facebook.');
3017      } else {
3018        this.message = message;
3019        this.image = image;
3020        this.link = link;
3021
3022        defer.resolve();
3023      }
3024      return defer.promise;
3025    },
3026
3027    shareViaSMS: function (message, number) {
3028      var defer = $q.defer();
3029      if (this.throwsError) {
3030        defer.reject('There was an error sharing via SMS.');
3031      } else {
3032        this.message = message;
3033        this.number = number;
3034
3035        defer.resolve();
3036      }
3037      return defer.promise;
3038    },
3039
3040    shareViaEmail: function (message, subject, toArr, bccArr, file) {
3041      var defer = $q.defer();
3042      if (this.throwsError) {
3043        defer.reject('There was an error sharing via SMS.');
3044      } else {
3045        // These are added to get by JSHINT for now
3046        this.message = message;
3047        this.subject = subject;
3048        this.toAddresses = toArr;
3049        this.bccAddressesc = bccArr;
3050        this.attachments = file;
3051
3052        defer.resolve();
3053      }
3054      return defer.promise;
3055    },
3056
3057    canShareViaEmail: function () {
3058      var defer = $q.defer();
3059      if (this.throwsError) {
3060        defer.reject(false);
3061      } else {
3062        defer.resolve(true);
3063      }
3064      return defer.promise;
3065    },
3066
3067    canShareVia: function (via, message, subject, file, link) {
3068      var defer = $q.defer();
3069      if (this.throwsError) {
3070        defer.reject('There was an error sharing via SMS.');
3071      } else {
3072        // These are added to get by JSHINT for now
3073        this.message = message;
3074        this.socialService = via;
3075        this.subject = subject;
3076        this.attachments = file;
3077        this.link = link;
3078
3079        defer.resolve();
3080      }
3081      return defer.promise;
3082    },
3083
3084    shareVia: function (via, message, subject, file, link) {
3085      var defer = $q.defer();
3086      if (this.throwsError) {
3087        defer.reject('There was an error sharing via SMS.');
3088      } else {
3089        this.socialService = via;
3090        this.message = message;
3091        this.subject = subject;
3092        this.attachments = file;
3093        this.link = link;
3094
3095        defer.resolve();
3096      }
3097      return defer.promise;
3098    },
3099
3100    share: function (message, subject, file, link) {
3101      var defer = $q.defer();
3102      if (this.throwsError) {
3103        defer.reject('There was an error sharing via SMS.');
3104      } else {
3105        this.message = message;
3106        this.subject = subject;
3107        this.attachments = file;
3108        this.link = link;
3109
3110        defer.resolve();
3111      }
3112      return defer.promise;
3113    },
3114
3115    shareWithOptions: function (options) {
3116      var defer = $q.defer();
3117      if (this.throwsError) {
3118        defer.reject('There was an error sharing via SMS.');
3119      } else {
3120        this.message = options.message;
3121        this.subject = options.subject;
3122        this.attachments = options.files;
3123        this.link = options.url;
3124
3125        defer.resolve();
3126      }
3127      return defer.promise;
3128    }
3129  };
3130}]);
3131
3132/**
3133 * @ngdoc service
3134 * @name ngCordovaMocks.cordovaSplashscreen
3135 *
3136 * @description
3137 * A service for testing the splash screen
3138 * in an app build with ngCordova.
3139 */
3140ngCordovaMocks.factory('$cordovaSplashscreen', function () {
3141  var isVisible = false;
3142
3143  return {
3144    /**
3145     * @ngdoc property
3146     * @name isVisible
3147     * @propertyOf ngCordovaMocks.cordovaSplashscreen
3148     *
3149     * @description
3150     * A flag that signals whether the splash screen is visible or not.
3151     * This property should only be used in automated tests.
3152     **/
3153    isVisible: isVisible,
3154
3155    hide: function () {
3156      // do nothing. everything happens behind the scenes in this case.
3157      // its a stub that is present for completeness.
3158      this.isVisible = false;
3159      return true;
3160    },
3161    show: function () {
3162      // do nothing. everything happens behind the scenes in this case.
3163      // its a stub that is present for completeness.
3164      this.isVisible = true;
3165      return true;
3166    }
3167  };
3168});
3169
3170/**
3171 * @ngdoc service
3172 * @name ngCordovaMocks.cordovaSQLite
3173 *
3174 * @description
3175 * A service for testing SQLite
3176 * in an app build with ngCordova.
3177 */
3178
3179ngCordovaMocks.factory('$cordovaSQLite', ['$q', function ($q) {
3180
3181  return {
3182    /**
3183     * These properties are here for the purpose of automated testing only.
3184     **/
3185    openDBShouldSucceedWith: null,
3186    executeShouldSucceedWith: null,
3187    insertCollectionShouldSucceedWith: null,
3188    nestedExecuteShouldSucceedWith: null,
3189    deleteDBShouldSucceedWith : null,
3190
3191    openDB: function (options, background) {
3192      if (this.openDBShouldSucceedWith !== null) {
3193        $q.when(this.openDBShouldSucceedWith)
3194      } else {
3195        $q.reject()
3196      }
3197    },
3198    execute: function (db, query, binding) {
3199      if (this.executeShouldSucceedWith !== null) {
3200        $q.when(this.executeShouldSucceedWith)
3201      } else {
3202        $q.reject()
3203      }
3204    },
3205    insertCollection: function (db, query, bindings) {
3206      if (this.insertCollectionShouldSucceedWith !== null) {
3207        $q.when(this.insertCollectionShouldSucceedWith)
3208      } else {
3209        $q.reject()
3210      }
3211    },
3212    nestedExecute: function (db, query1, query2, binding1, binding2) {
3213      if (this.nestedExecuteShouldSucceedWith !== null) {
3214        $q.when(this.nestedExecuteShouldSucceedWith)
3215      } else {
3216        $q.reject()
3217      }
3218    },
3219    deleteDB: function (dbName) {
3220      if (this.deleteDBShouldSucceedWith !== null) {
3221        $q.when(this.deleteDBShouldSucceedWith)
3222      } else {
3223        $q.reject()
3224      }
3225    }
3226  }
3227}]);
3228
3229/**
3230 * @ngdoc service
3231 * @name ngCordovaMocks.cordovaStatusbar
3232 *
3233 * @description
3234 * A service for testing the status bar
3235 * in an app build with ngCordova.
3236 */
3237ngCordovaMocks.factory('$cordovaStatusbar', function () {
3238  var isStatusBarVisible = true;
3239  var canOverlayWebView = true;
3240
3241  return {
3242    /**
3243     * @ngdoc property
3244     * @name isStatusBarVisible
3245     * @propertyOf ngCordovaMocks.cordovaStatusbar
3246     *
3247     * @description
3248     * A flag that signals whether the status bar is visible or not.
3249     * This property should only be used in automated tests.
3250     **/
3251    isStatusBarVisible: isStatusBarVisible,
3252
3253    /**
3254     * @ngdoc property
3255     * @name canOverlayWebView
3256     * @propertyOf ngCordovaMocks.cordovaStatusbar
3257     *
3258     * @description
3259     * A flag that signals whether the status bar can overlay the web view.
3260     * This property should only be used in automated tests.
3261     **/
3262    canOverlayWebView: canOverlayWebView,
3263
3264    overlaysWebView: function (bool) {
3265      this.canOverlayWebView = bool;
3266    },
3267
3268    style: function (style) {
3269      // TODO: Review
3270      return style;
3271    },
3272
3273    styleHex: function (colorHex) {
3274      // TODO: review
3275      return colorHex;
3276    },
3277
3278    styleColor: function (color) {
3279      // TODO: review
3280      return color;
3281    },
3282
3283    hide: function () {
3284      this.isStatusBarVisible = false;
3285    },
3286
3287    show: function () {
3288      this.isStatusBarVisible = true;
3289    },
3290
3291    isVisible: function () {
3292      return this.isStatusBarVisible;
3293    }
3294  };
3295});
3296
3297/**
3298 * @ngdoc service
3299 * @name ngCordovaMocks.cordovaToast
3300 *
3301 * @description
3302 * A service for testing toasts
3303 * in an app build with ngCordova.
3304 *
3305 * @example
3306 */
3307ngCordovaMocks.factory('$cordovaToast', ['$q', function ($q) {
3308  var throwsError = false;
3309
3310  return {
3311    /**
3312     * @ngdoc property
3313     * @name throwsError
3314     * @propertyOf ngCordovaMocks.cordovaToast
3315     *
3316     * @description
3317     * A flag that signals whether a promise should be rejected or not.
3318     * This property should only be used in automated tests.
3319     **/
3320    throwsError: throwsError,
3321
3322    showShortTop: function (message) {
3323      var defer = $q.defer();
3324      if (this.throwsError) {
3325        defer.reject('There was an error showing the toast.');
3326      } else {
3327        defer.resolve();
3328      }
3329      return defer.promise;
3330    },
3331    showShortCenter: function (message) {
3332      var defer = $q.defer();
3333      if (this.throwsError) {
3334        defer.reject('There was an error showing the toast.');
3335      } else {
3336        defer.resolve();
3337      }
3338      return defer.promise;
3339    },
3340    showShortBottom: function (message) {
3341      var defer = $q.defer();
3342      if (this.throwsError) {
3343        defer.reject('There was an error showing the toast.');
3344      } else {
3345        defer.resolve();
3346      }
3347      return defer.promise;
3348    },
3349    showLongTop: function (message) {
3350      var defer = $q.defer();
3351      if (this.throwsError) {
3352        defer.reject('There was an error showing the toast.');
3353      } else {
3354        defer.resolve();
3355      }
3356      return defer.promise;
3357    },
3358    showLongCenter: function (message) {
3359      var defer = $q.defer();
3360      if (this.throwsError) {
3361        defer.reject('There was an error showing the toast.');
3362      } else {
3363        defer.resolve();
3364      }
3365      return defer.promise;
3366    },
3367    showLongBottom: function (message) {
3368      var defer = $q.defer();
3369      if (this.throwsError) {
3370        defer.reject('There was an error showing the toast.');
3371      } else {
3372        defer.resolve();
3373      }
3374      return defer.promise;
3375    },
3376    showWithOptions: function (options) {
3377      var defer = $q.defer();
3378      if (this.throwsError) {
3379        defer.reject('There was an error showing the toast.');
3380      } else {
3381        defer.resolve();
3382      }
3383      return defer.promise;
3384		},
3385    show: function (message, duration, position) {
3386      var defer = $q.defer();
3387      if (this.throwsError) {
3388        defer.reject('There was an error showing the toast.');
3389      } else {
3390        defer.resolve();
3391      }
3392      return defer.promise;
3393    },
3394    hide: function () {
3395      var defer = $q.defer();
3396      if (this.throwsError) {
3397        defer.reject('There was an error hiding the toast.');
3398      } else {
3399        defer.resolve();
3400      }
3401      return defer.promise;
3402    }
3403  };
3404}]);
3405
3406/**
3407 * @ngdoc service
3408 * @name ngCordovaMocks.cordovaVibration
3409 *
3410 * @description
3411 * A service for testing vibration
3412 * in an app build with ngCordova.
3413 */
3414ngCordovaMocks.factory('$cordovaVibration', ['$timeout', function ($timeout) {
3415  var isVibrating = false;
3416  var vibrateTimer = null;
3417
3418  return {
3419    /**
3420     * @ngdoc property
3421     * @name vibrateTimer
3422     * @propertyOf ngCordovaMocks.cordovaVibration
3423     *
3424     * @description
3425     * Access to the timer associated with vibration.
3426     * This property should only be used in automated tests.
3427     **/
3428    vibrateTimer: vibrateTimer,
3429
3430    /**
3431     * @ngdoc property
3432     * @name isVibrating
3433     * @propertyOf ngCordovaMocks.cordovaVibration
3434     *
3435     * @description
3436     * A flag that signals whether vibration is active.
3437     * This property should only be used in automated tests.
3438     **/
3439    isVibrating: isVibrating,
3440
3441    vibrate: function (time) {
3442      if (time > 0) {
3443        this.isVibrating = true;
3444        self = this;
3445
3446        if (time instanceof Array) {
3447          // TODO: Implement pattern here.
3448          // The following is a temporary timer that just looks at the first value
3449          this.vibrateTimer = $timeout(
3450            function () {
3451              self.isVibrating = false;
3452              self.vibrateTimer = null;
3453            },
3454            time[0]
3455          );
3456        } else {
3457          this.vibrateTimer = $timeout(
3458            function () {
3459              self.isVibrating = false;
3460              self.vibrateTimer = null;
3461            },
3462            time
3463          );
3464        }
3465      }
3466    },
3467
3468    /* jshint ignore:start */
3469    vibrateWithPattern: function (pattern, repeat) {
3470      // Based on the documentation (https://github.com/apache/cordova-plugin-vibration)
3471      // This method is deprecated. For that reason, this isn't implemented at this time.
3472    },
3473    /* jshint ignore:end */
3474
3475    cancelVibration: function () {
3476      if (this.vibrateTimer !== null) {
3477        if (this.isVibrating === true) {
3478          $timeout.cancel(this.vibrateTimer);
3479          this.isVibrating = false;
3480        }
3481      }
3482    }
3483  };
3484}]);
3485
3486})();