private void Animate(Action action, float time)
        {
            UICompletionHandler completion = new UICompletionHandler(delegate(bool finished) {
                if (!finished)
                {
                    Console.WriteLine("animation didn't finish!");
                }
                else
                {
                    Console.WriteLine("animation finished");
                }
                //Continue with next message if any
                if (_messages.Count > 0)
                {
                    InformationMessageQueueEntry entry = _messages.Dequeue();
                    Log.Debug("Processing information message {0} from queue", entry.Message);

                    InitShow(entry);
                }
            });

            InvokeOnMainThread(() => {
                UIView.AnimateNotify(
                    time,                     // animation time
                    0.0f,                     // animation delay
                    0.3f,                     // spring dampening ration (lower == springyer)
                    0.1f,                     // initial spring velocity
                    UIViewAnimationOptions.AllowAnimatedContent,
                    action,
                    null
                    );
            });
        }
        private void InitShow(InformationMessageQueueEntry queueEntry)
        {
            //Drop if already existing messages
            if (_currentMessage == queueEntry.Message)
            {
                return;
            }
            foreach (var m in _messages)
            {
                if (m.Message == queueEntry.Message)
                {
                    return;
                }
            }

            //If already showing a message, put new one in queue
            if (_currentMessage.HasValue)
            {
                Log.Debug("Message {0} queued because {1} is shown ({2} already queued)", queueEntry.Message, _currentMessage, _messages.Count);
                _messages.Enqueue(queueEntry);
                return;
            }

            //Here we go
            _currentMessage = queueEntry.Message;
            Log.Debug("Showing message {0}", _currentMessage);

            _imageIcon.SetImageDrawable(queueEntry.Message.GetIcon(_context));
            _textTitle.Text = queueEntry.Message.GetTitle(_context);
            _textTitle.SetTextColor(queueEntry.Message.GetTitleColor(_context));
            _textDescription.TextFormatted = Html.FromHtml(queueEntry.Message.GetDescription(_context));
            _viewMessage.SlideIn(_snackbarHeight, 1000, this);

            if (_isButtonShown && _viewButton != null)
            {
                PrepareButtonAnimation();
                _animatorButton = _viewButton.DecelerateToY(_buttonStopTranslationOffset, 1000);
            }

            //Setup timer for hiding if timed message
            if (!queueEntry.IsPersistent)
            {
                Log.Debug("Starting timer for message hiding in {0} ms", queueEntry.Duration);

                try {
                    var messageToHide = _currentMessage.Value;
                    _handler.PostDelayed(new Action(() => {
                        Log.Debug("Message hiding timer fired");
                        Hide(messageToHide);
                    }), queueEntry.Duration);
                }
                catch (ObjectDisposedException) {
                    // Noop: if the handler is disposed, the app is tearing down
                }
            }
        }
        public void OnAnimationEnd(Animator animation)
        {
            if (_animatorButton == animation)
            {
                _animatorButton = null;
            }
            else if (_animatorSlideOut == animation)
            {
                Log.Debug("Slide out animation completed for {0}", _currentMessage);

                _currentMessage   = null;
                _animatorSlideOut = null;

                //Continue with next message if any
                if (_messages.Count > 0)
                {
                    InformationMessageQueueEntry entry = _messages.Dequeue();
                    Log.Debug("Processing information message {0} from queue", entry.Message);

                    InitShow(entry);
                }
            }
        }
        private void InitShow(InformationMessageQueueEntry queueEntry)
        {
            //Drop if already existing messages
            if (_currentMessage == queueEntry.Message)
            {
                return;
            }
            foreach (var m in _messages)
            {
                if (m.Message == queueEntry.Message)
                {
                    return;
                }
            }

            //If already showing a message, put new one in queue
            if (_currentMessage.HasValue)
            {
                Log.Debug("Message {0} queued because {1} is shown ({2} already queued)", queueEntry.Message, _currentMessage, _messages.Count);
                _messages.Enqueue(queueEntry);
                return;
            }

            //Here we go
            _currentMessage = queueEntry.Message;
            Log.Debug("Showing message {0}", _currentMessage);
            imgIcon.Image      = queueEntry.Message.GetIcon();
            lblTitle.Text      = queueEntry.Message.GetTitle().PrepareForLabel();
            lblTitle.TextColor = queueEntry.Message.GetTitleColor();

            _slideOutAnimator = () => {
                var frameCenter = this.View.Center;
                frameCenter.Y    = this.View.Center.Y + _snackbarHeight;
                this.View.Center = frameCenter;
            };
            Animate(_slideOutAnimator, 1.0f);

            if (_isButtonShown)
            {
                PrepareButtonAnimation();

                _buttonAnimator = () => {
                    var frameCenter = this._viewButton.Center;
                    frameCenter.Y           = this._viewButton.Center.Y + _buttonStopTranslationOffset;
                    this._viewButton.Center = frameCenter;
                };
                Animate(_buttonAnimator, 1.0f);
            }

            //Setup timer for hiding if timed message
            if (!queueEntry.IsPersistent)
            {
                Log.Debug("Starting timer for message hiding in {0} ms", queueEntry.Duration);

                var messageToHide = _currentMessage.Value;
                InvokeInBackground(new Action(() => {
                    Thread.Sleep((int)queueEntry.Duration);
                    Log.Debug("Message hiding timer fired");
                    Hide(messageToHide);
                }));
            }
        }
        private void InitShow(InformationMessageQueueEntry queueEntry)
        {
            //Drop if already existing messages
            if (_currentMessage == queueEntry.Message)
            {
                Log.Debug("message \"{0}\" already displayed", queueEntry.Message);
                return;
            }
            foreach (var m in _messages)
            {
                if (m.Message == queueEntry.Message)
                {
                    Log.Debug("message \"{0}\" already in queue", queueEntry.Message);
                    return;
                }
            }

            //If already showing a message, put new one in queue
            if (_currentMessage.HasValue)
            {
                Log.Debug("Message {0} queued because {1} is shown ({2} already queued)", queueEntry.Message, _currentMessage, _messages.Count);
                _messages.Enqueue(queueEntry);
                return;
            }

            //Here we go
            _currentMessage = queueEntry.Message;
            Log.Debug("Showing message {0}", _currentMessage);
            imgError.Image     = queueEntry.Message.GetIcon();
            lblTitle.Text      = queueEntry.Message.GetTitle().PrepareForLabel();
            lblBody.Text       = queueEntry.Message.GetDescription().PrepareForLabel();
            lblTitle.TextColor = queueEntry.Message.GetTitleColor();

            Animation(1.0f, true);

            // remove stop button if too slow message or stopped moving message
            if (_currentMessage == InformationMessage.GpsSuspendedSpeed || _currentMessage == InformationMessage.GpsSuspendedStationary)
            {
                AnimateStopButton();
                lblCenter.Hidden = true;
            }

            if (_isButtonShown)
            {
                PrepareButtonAnimation();

                _buttonAnimator = () => {
                    btnStopBottomConstraint.Constant = btnStopBottomConstraint.Constant + _buttonStopTranslationOffset;
                    btnStop.NeedsUpdateConstraints();
                    btnStop.LayoutIfNeeded();
                };
                TraslateStopButton(_buttonAnimator, 1.0f);
            }

            //Setup timer for hiding if timed message
            if (!queueEntry.IsPersistent)
            {
                Log.Debug("Starting timer for message hiding in {0} ms", queueEntry.Duration);

                var messageToHide = _currentMessage.Value;
                InvokeInBackground(new Action(() => {
                    Thread.Sleep((int)queueEntry.Duration);
                    Log.Debug("Message hiding timer fired");
                    Hide(messageToHide);
                }));
            }
        }