I'm trying to upload image from Camera or gallery. I wrote all the code in the service. The controller must receive the complete url from the camera or gallery to show it in a slide box, but now nothing receive.
Everything works, but I couldn't send back to the controller the url of the image. I think the error is because I'm trying to return the value before that the function "obtenerImagen" execute.
I'm trying to implement Callbacks, but I think I did not implemented correctly.
The variable that I want to return with the url of the image is urlImagen
This is my controller that calls the service:
 //generar el popup para seleccionar el origen de la imagen: cámara o galería
    function seleccionarImagen() {
        cambiarImagenesService.seleccionarImagen()
            .then(reemplazarImagen);
    }
And the service:
(function() {
'use strict';
angular
    .module('example.cambiarimagenes')
    .factory('cambiarImagenesService', cambiarImagenesService);
cambiarImagenesService.$inject = ['remoteDataService','$q', '$ionicPopup','$cordovaCamera', '$cordovaFile', '$cordovaFileTransfer', '$cordovaDevice', '$rootScope'];
/* @ngInject */
function cambiarImagenesService(remoteDataService,$q, $ionicPopup, $cordovaCamera, $cordovaFile,  $cordovaFileTransfer, $cordovaDevice, $rootScope){ 
    var dias = [];
    var mensaje = '';
    var image = null;
    var urlImagen = '';
    var service = {
        obtenerHorariosComplejo: obtenerHorariosComplejo,
        seleccionarImagen: seleccionarImagen
    };
    return service;
    //cargar una nueva imagen
    function seleccionarImagen() {
        var popup = seleccionarImagenPopup();
        return $ionicPopup.show(popup).then(function(result) {
            if (result == -1) {
                return false;
            }
            return urlImagen;
        });
    }
    function obtenerImagen(sourceType, callback){
        var options = {
            callback: callback,
            quality: 100,
            destinationType: Camera.DestinationType.FILE_URI,
            sourceType: sourceType,
            saveToPhotoAlbum: false
        };
        $cordovaCamera.getPicture(options).then(function(imagePath) {
            // Grab the file name of the photo in the temporary directory
            var currentName = imagePath.replace(/^.*[\\\/]/, '');
            //Create a new name for the photo
            var d = new Date(),
            n = d.getTime(),
            newFileName =  n + ".jpg";
            // If you are trying to load image from the gallery on Android we need special treatment!
            if ($cordovaDevice.getPlatform() == 'Android' && sourceType === Camera.PictureSourceType.PHOTOLIBRARY) {
                window.FilePath.resolveNativePath(imagePath, function(entry) {
                    window.resolveLocalFileSystemURL(entry, success, fail);
                    function fail(e) {
                        console.error('Error: ', e);
                    }
                    function success(fileEntry) {
                        var namePath = fileEntry.nativeURL.substr(0, fileEntry.nativeURL.lastIndexOf('/') + 1);
                        // Only copy because of access rights
                        $cordovaFile.copyFile(namePath, fileEntry.name, cordova.file.dataDirectory, newFileName).then(function(success){
                            image = cordova.file.dataDirectory + newFileName;
                            urlImagen = image;
                        }, function(error){
                            $scope.showAlert('Error', error.exception);
                        });
                    };
                }
                );
            } else {
                var namePath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
                // Move the file to permanent storage
                $cordovaFile.moveFile(namePath, currentName, cordova.file.dataDirectory, newFileName).then(function(success){
                    image = cordova.file.dataDirectory + newFileName;
                    urlImagen = image;
                }, function(error){
                    $scope.showAlert('Error', error.exception);
                });
            }
        },
        function(err){
            console.log("error en el serivicio o cancelacion:"+err);
            // Not always an error, maybe cancel was pressed...
        })
    }
    //poopup para cargar nuevo imagen
    function seleccionarImagenPopup() {
        var scope = $rootScope.$new();
        scope.data = {
            tipo: null
        };
        return {
            templateUrl: 'scripts/complejo/agenda/nuevo-turno.html',
            title: "¿De dónde desea obtener la imagen?",
            scope: scope,
            buttons: [{
                text: 'Cancelar',
                onTap: function(e) {
                    scope.tipo = -1
                    return scope.tipo;
                }
            }, {
                text: '<b>Cámara</b>',
                type: 'button-positive',
                onTap: function(e) {
                    scope.tipo = Camera.PictureSourceType.CAMERA;
                    obtenerImagen(scope.tipo, function(val){
                        urlImagen = val;
                    });
                    console.log("el valor de la imagen al tocar la camara es:"+image);
                    return urlImagen;
                }
            }, {
                text: '<b>Galería</b>',
                type: 'button-positive',
                onTap: function(e) {
                    scope.tipo = Camera.PictureSourceType.PHOTOLIBRARY;
                    obtenerImagen(scope.tipo, function(val){
                        urlImagen = val;
                    });
                    console.log("el valor de la imagen al tocar la galeria es:"+image);
                    return urlImagen;
                }
            }]
        };
    }
    //generar error si hubo un problema
    function generarError(e){
        console.log("error!!!!!!:"+e);
        if (e.message) {
            return $q.reject(e.message);
        }
        return $q.reject('Ups! Hubo un problema al conectarse al servidor.');
    }
}
})();
Thanks for helping me!
//EDIT//
This is now my service:
(function() {
'use strict';
angular
.module('example.cambiarimagenes')
.factory('cambiarImagenesService', cambiarImagenesService);
cambiarImagenesService.$inject = ['remoteDataService','$q', '$ionicPopup','$cordovaCamera', '$cordovaFile', '$cordovaFileTransfer', '$cordovaDevice', '$rootScope'];
/* @ngInject */
function cambiarImagenesService(remoteDataService,$q, $ionicPopup,$cordovaCamera, $cordovaFile,  $cordovaFileTransfer, $cordovaDevice, $rootScope){ 
var dias = [];
var mensaje = '';
var image = null;
var urlImagen = '';
var service = {
    obtenerHorariosComplejo: obtenerHorariosComplejo,
    seleccionarImagen: seleccionarImagen
};
return service;
//cargar una nueva imagen
function seleccionarImagen() {
    var popup = seleccionarImagenPopup();
    return $ionicPopup.show(popup).then(function(result) {
        if (result == -1) {
            return false;
        }
        return urlImagen;
    });
}
function obtenerImagen(sourceType){
    var options = {
        quality: 100,
        destinationType: Camera.DestinationType.FILE_URI,
        sourceType: sourceType,
        saveToPhotoAlbum: false
    };
    return $cordovaCamera.getPicture(options).then(function(imagePath) {
        // Grab the file name of the photo in the temporary directory
        var currentName = imagePath.replace(/^.*[\\\/]/, '');
        //Create a new name for the photo
        var d = new Date(),
        n = d.getTime(),
        newFileName =  n + ".jpg";
        // If you are trying to load image from the gallery on Android we need special treatment!
        if ($cordovaDevice.getPlatform() == 'Android' && sourceType === Camera.PictureSourceType.PHOTOLIBRARY) {
            window.FilePath.resolveNativePath(imagePath, function(entry) {
                window.resolveLocalFileSystemURL(entry, success, fail);
                function fail(e) {
                    console.error('Error: ', e);
                }
                function success(fileEntry) {
                    var namePath = fileEntry.nativeURL.substr(0, fileEntry.nativeURL.lastIndexOf('/') + 1);
                    // Only copy because of access rights
                    $cordovaFile.copyFile(namePath, fileEntry.name, cordova.file.dataDirectory, newFileName).then(function(success){
                        image = cordova.file.dataDirectory + newFileName;
                        return image;
                    }, function(error){
                        $scope.showAlert('Error', error.exception);
                    });
                };
            }
            );
        } else {
            var namePath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
            // Move the file to permanent storage
            $cordovaFile.moveFile(namePath, currentName, cordova.file.dataDirectory, newFileName).then(function(success){
                image = cordova.file.dataDirectory + newFileName;
                return image;
            }, function(error){
                $scope.showAlert('Error', error.exception);
            });
        }
    },
    function(err){
        console.log("error en el serivicio o cancelacion:"+err);
        // Not always an error, maybe cancel was pressed...
    })
}
//poopup para cargar nuevo imagen
function seleccionarImagenPopup() {
    var scope = $rootScope.$new();
    scope.data = {
        tipo: null
    };
    return {
        templateUrl: 'scripts/complejo/agenda/nuevo-turno.html',
        title: "¿De dónde desea obtener la imagen?",
        scope: scope,
        buttons: [{
            text: 'Cancelar',
            onTap: function(e) {
                scope.tipo = -1
                return scope.tipo;
            }
        }, {
            text: '<b>Cámara</b>',
            type: 'button-positive',
            onTap: function(e) {
                scope.tipo = Camera.PictureSourceType.CAMERA;
                var promise = obtenerImagen(scope.tipo)
                .then(function(val){
                    // asignamos el valor asincrónico
                    urlImagen = val;
                    // retornamos el valor a la cadena
                    return val;
                });
                // retornamos la promesa de manera síncrona
                return promise;
            }
        }, {
            text: '<b>Galería</b>',
            type: 'button-positive',
            onTap: function(e) {
                scope.tipo = Camera.PictureSourceType.PHOTOLIBRARY;
                var promise = obtenerImagen(scope.tipo)
                .then(function(val){
                    // asignamos el valor asincrónico
                    urlImagen = val;
                    // retornamos el valor a la cadena
                    return val;
                });
                // retornamos la promesa de manera síncrona
                return promise;
            }
        }]
    };
}
//generar error si hubo un problema
function generarError(e){
    console.log("error!!!!!!:"+e);
    if (e.message) {
        return $q.reject(e.message);
    }
    return $q.reject('Ups! Hubo un problema al conectarse al servidor.');
}
}
})();