/// <summary>
        /// This is the main thread for the Downloader. 
        /// This thread is responsible for queuing up downloads and other goodness.
        /// </summary>
        /// <param name="intent">
        /// The intent that was recieved.
        /// </param>
        protected override void OnHandleIntent(Intent intent)
        {
            Log.Debug(Tag,"DownloaderService.OnHandleIntent");

            this.IsServiceRunning = true;
            try
            {
                var pendingIntent = (PendingIntent)intent.GetParcelableExtra(DownloaderServiceExtras.PendingIntent);

                if (null != pendingIntent)
                {
                    this.downloadNotification.PendingIntent = pendingIntent;
                    this.pPendingIntent = pendingIntent;
                }
                else if (null != this.pPendingIntent)
                {
                    this.downloadNotification.PendingIntent = this.pPendingIntent;
                }
                else
                {
                    Log.Debug(Tag,"LVLDL Downloader started in bad state without notification intent.");
                    return;
                }

                // when the LVL check completes, a successful response will update the service
                if (IsLvlCheckRequired(this.packageInfo))
                {
                    this.UpdateLvl(this);
                    return;
                }

                // get each download
                List<DownloadInfo> infos = DownloadsDatabase.GetDownloads();
                this.BytesSoFar = 0;
                this.TotalLength = 0;
                this.fileCount = infos.Count();
                foreach (DownloadInfo info in infos)
                {
                    // We do an (simple) integrity check on each file, just to 
                    // make sure and to verify that the file matches the state
                    if (info.Status == DownloadStatus.Success
                        && !Helpers.DoesFileExist(this, info.FileName, info.TotalBytes, true))
                    {
                        info.Status = DownloadStatus.None;
                        info.CurrentBytes = 0;
                    }

                    // get aggregate data
                    this.TotalLength += info.TotalBytes;
                    this.BytesSoFar += info.CurrentBytes;
                }

                this.PollNetworkState();
                if (this.connectionReceiver == null)
                {
                    // We use this to track network state, such as when WiFi, Cellular, etc. is enabled
                    // when downloads are paused or in progress.
                    this.connectionReceiver = new InnerBroadcastReceiver(this);
                    var intentFilter = new IntentFilter(ConnectivityManager.ConnectivityAction);
                    intentFilter.AddAction(WifiManager.WifiStateChangedAction);
                    this.RegisterReceiver(this.connectionReceiver, intentFilter);
                }

                // loop through all downloads and fetch them
                int types = Enum.GetValues(typeof(ApkExpansionPolicy.ExpansionFileType)).Length;
                for (int index = 0; index < types; index++)
                {
                    DownloadInfo info = infos[index];
                    Log.Debug(Tag,"Starting download of " + info.FileName);

                    long startingCount = info.CurrentBytes;

                    if (info.Status != DownloadStatus.Success)
                    {
                        var dt = new DownloadThread(info, this, this.downloadNotification);
                        this.CancelAlarms();
                        this.ScheduleAlarm(ActiveThreadWatchdog);
                        dt.Run();
                        this.CancelAlarms();
                    }

                    DownloadsDatabase.UpdateFromDatabase(ref info);
                    bool setWakeWatchdog = false;
                    DownloaderState notifyStatus;
                    switch (info.Status)
                    {
                        case DownloadStatus.Forbidden:

                            // the URL is out of date
                            this.UpdateLvl(this);
                            return;
                        case DownloadStatus.Success:
                            this.BytesSoFar += info.CurrentBytes - startingCount;

                            if (index < infos.Count() - 1)
                            {
                                continue;
                            }

                            DownloadsDatabase.UpdateMetadata(this.packageInfo.VersionCode, DownloadStatus.None);
                            this.downloadNotification.OnDownloadStateChanged(DownloaderState.Completed);
                            return;
                        case DownloadStatus.FileDeliveredIncorrectly:

                            // we may be on a network that is returning us a web page on redirect
                            notifyStatus = DownloaderState.PausedNetworkSetupFailure;
                            info.CurrentBytes = 0;
                            DownloadsDatabase.UpdateDownload(info);
                            setWakeWatchdog = true;
                            break;
                        case DownloadStatus.PausedByApp:
                            notifyStatus = DownloaderState.PausedByRequest;
                            break;
                        case DownloadStatus.WaitingForNetwork:
                        case DownloadStatus.WaitingToRetry:
                            notifyStatus = DownloaderState.PausedNetworkUnavailable;
                            setWakeWatchdog = true;
                            break;
                        case DownloadStatus.QueuedForWifi:
                        case DownloadStatus.QueuedForWifiOrCellularPermission:

                            // look for more detail here
                            notifyStatus = this.wifiManager != null && !this.wifiManager.IsWifiEnabled
                                               ? DownloaderState.PausedWifiDisabledNeedCellularPermission
                                               : DownloaderState.PausedNeedCellularPermission;
                            setWakeWatchdog = true;
                            break;
                        case DownloadStatus.Canceled:
                            notifyStatus = DownloaderState.FailedCanceled;
                            setWakeWatchdog = true;
                            break;

                        case DownloadStatus.InsufficientSpaceError:
                            notifyStatus = DownloaderState.FailedSdCardFull;
                            setWakeWatchdog = true;
                            break;

                        case DownloadStatus.DeviceNotFoundError:
                            notifyStatus = DownloaderState.PausedSdCardUnavailable;
                            setWakeWatchdog = true;
                            break;

                        default:
                            notifyStatus = DownloaderState.Failed;
                            break;
                    }

                    if (setWakeWatchdog)
                    {
                        this.ScheduleAlarm(WatchdogWakeTimer);
                    }
                    else
                    {
                        this.CancelAlarms();
                    }

                    // failure or pause state
                    this.downloadNotification.OnDownloadStateChanged(notifyStatus);
                    return;
                }

                this.downloadNotification.OnDownloadStateChanged(DownloaderState.Completed);
            }
            catch (Exception ex)
            {
                Log.Error(Tag,ex.Message);
                Log.Error(Tag,ex.StackTrace);
            }
            finally
            {
                this.IsServiceRunning = false;
            }
        }
        /// <summary>
        /// This is the main thread for the Downloader.
        /// This thread is responsible for queuing up downloads and other goodness.
        /// </summary>
        /// <param name="intent">
        /// The intent that was recieved.
        /// </param>
        protected override void OnHandleIntent(Intent intent)
        {
            Log.Debug(Tag, "DownloaderService.OnHandleIntent");

            this.IsServiceRunning = true;
            try
            {
                var pendingIntent = (PendingIntent)intent.GetParcelableExtra(DownloaderServiceExtras.PendingIntent);

                if (null != pendingIntent)
                {
                    this.downloadNotification.PendingIntent = pendingIntent;
                    this.pPendingIntent = pendingIntent;
                }
                else if (null != this.pPendingIntent)
                {
                    this.downloadNotification.PendingIntent = this.pPendingIntent;
                }
                else
                {
                    Log.Debug(Tag, "LVLDL Downloader started in bad state without notification intent.");
                    return;
                }

                // when the LVL check completes, a successful response will update the service
                if (IsLvlCheckRequired(this.packageInfo))
                {
                    this.UpdateLvl(this);
                    return;
                }

                // get each download
                List <DownloadInfo> infos = DownloadsDatabase.GetDownloads();
                this.BytesSoFar  = 0;
                this.TotalLength = 0;
                this.fileCount   = infos.Count();
                foreach (DownloadInfo info in infos)
                {
                    // We do an (simple) integrity check on each file, just to
                    // make sure and to verify that the file matches the state
                    if (info.Status == ExpansionDownloadStatus.Success &&
                        !Helpers.DoesFileExist(this, info.FileName, info.TotalBytes, true))
                    {
                        info.Status       = ExpansionDownloadStatus.None;
                        info.CurrentBytes = 0;
                    }

                    // get aggregate data
                    this.TotalLength += info.TotalBytes;
                    this.BytesSoFar  += info.CurrentBytes;
                }

                this.PollNetworkState();
                if (this.connectionReceiver == null)
                {
                    // We use this to track network state, such as when WiFi, Cellular, etc. is enabled
                    // when downloads are paused or in progress.
                    this.connectionReceiver = new InnerBroadcastReceiver(this);
                    var intentFilter = new IntentFilter(ConnectivityManager.ConnectivityAction);
                    intentFilter.AddAction(WifiManager.WifiStateChangedAction);
                    this.RegisterReceiver(this.connectionReceiver, intentFilter);
                }

                // loop through all downloads and fetch them
                int types = Enum.GetValues(typeof(ApkExpansionPolicy.ExpansionFileType)).Length;
                for (int index = 0; index < types; index++)
                {
                    DownloadInfo info = infos[index];
                    Log.Debug(Tag, "Starting download of " + info.FileName);

                    long startingCount = info.CurrentBytes;

                    if (info.Status != ExpansionDownloadStatus.Success)
                    {
                        var dt = new DownloadThread(info, this, this.downloadNotification);
                        this.CancelAlarms();
                        this.ScheduleAlarm(ActiveThreadWatchdog);
                        dt.Run();
                        this.CancelAlarms();
                    }

                    DownloadsDatabase.UpdateFromDatabase(ref info);
                    bool            setWakeWatchdog = false;
                    DownloaderState notifyStatus;
                    switch (info.Status)
                    {
                    case ExpansionDownloadStatus.Forbidden:

                        // the URL is out of date
                        this.UpdateLvl(this);
                        return;

                    case ExpansionDownloadStatus.Success:
                        this.BytesSoFar += info.CurrentBytes - startingCount;

                        if (index < infos.Count() - 1)
                        {
                            continue;
                        }

                        DownloadsDatabase.UpdateMetadata(this.packageInfo.VersionCode, ExpansionDownloadStatus.None);
                        this.downloadNotification.OnDownloadStateChanged(DownloaderState.Completed);
                        return;

                    case ExpansionDownloadStatus.FileDeliveredIncorrectly:

                        // we may be on a network that is returning us a web page on redirect
                        notifyStatus      = DownloaderState.PausedNetworkSetupFailure;
                        info.CurrentBytes = 0;
                        DownloadsDatabase.UpdateDownload(info);
                        setWakeWatchdog = true;
                        break;

                    case ExpansionDownloadStatus.PausedByApp:
                        notifyStatus = DownloaderState.PausedByRequest;
                        break;

                    case ExpansionDownloadStatus.WaitingForNetwork:
                    case ExpansionDownloadStatus.WaitingToRetry:
                        notifyStatus    = DownloaderState.PausedNetworkUnavailable;
                        setWakeWatchdog = true;
                        break;

                    case ExpansionDownloadStatus.QueuedForWifi:
                    case ExpansionDownloadStatus.QueuedForWifiOrCellularPermission:

                        // look for more detail here
                        notifyStatus = this.wifiManager != null && !this.wifiManager.IsWifiEnabled
                                               ? DownloaderState.PausedWifiDisabledNeedCellularPermission
                                               : DownloaderState.PausedNeedCellularPermission;
                        setWakeWatchdog = true;
                        break;

                    case ExpansionDownloadStatus.Canceled:
                        notifyStatus    = DownloaderState.FailedCanceled;
                        setWakeWatchdog = true;
                        break;

                    case ExpansionDownloadStatus.InsufficientSpaceError:
                        notifyStatus    = DownloaderState.FailedSdCardFull;
                        setWakeWatchdog = true;
                        break;

                    case ExpansionDownloadStatus.DeviceNotFoundError:
                        notifyStatus    = DownloaderState.PausedSdCardUnavailable;
                        setWakeWatchdog = true;
                        break;

                    default:
                        notifyStatus = DownloaderState.Failed;
                        break;
                    }

                    if (setWakeWatchdog)
                    {
                        this.ScheduleAlarm(WatchdogWakeTimer);
                    }
                    else
                    {
                        this.CancelAlarms();
                    }

                    // failure or pause state
                    this.downloadNotification.OnDownloadStateChanged(notifyStatus);
                    return;
                }

                this.downloadNotification.OnDownloadStateChanged(DownloaderState.Completed);
            }
            catch (Exception ex)
            {
                Log.Error(Tag, ex.Message);
                Log.Error(Tag, ex.StackTrace);
            }
            finally
            {
                this.IsServiceRunning = false;
            }
        }