JNIEXPORT jstring JNICALL Java_org_cef_callback_CefDownloadItem_1N_N_1GetFullPath
  (JNIEnv *env, jobject obj) {
  CefRefPtr<CefDownloadItem> downloadItem =
      GetCefFromJNIObject<CefDownloadItem>(env, obj, "CefDownloadItem");
  if (!downloadItem.get())
    return NULL;
  return NewJNIString(env, downloadItem->GetFullPath());
}
void ClientHandler::OnDownloadUpdated(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefDownloadItem> download_item,
    CefRefPtr<CefDownloadItemCallback> callback) {
  REQUIRE_UI_THREAD();
  if (download_item->IsComplete()) {
    SetLastDownloadFile(download_item->GetFullPath());
    SendNotification(NOTIFY_DOWNLOAD_COMPLETE);
  }
}
void CWebBrowserDownloadHandler::OnDownloadUpdated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item,
                                                   CefRefPtr<CefDownloadItemCallback> callback)
{
  std::string url = download_item->GetOriginalUrl().ToString();
  std::shared_ptr<CDownloadItem> downloadItem;

  {
    std::lock_guard<std::mutex> lock(m_mutex);

    auto it = m_activeDownloads.find(url);
    if (it == m_activeDownloads.end())
    {
      downloadItem = std::make_shared<CDownloadItem>(url, callback);
      m_activeDownloads[url] = downloadItem;
    }
    else
      downloadItem = it->second;
  }

  if (!downloadItem->IsActive())
    return;

#ifdef DEBUG_LOGS
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s", __FUNCTION__);
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- IsValid: '%i'", __FUNCTION__, download_item->IsValid());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- IsInProgress: '%i'", __FUNCTION__, download_item->IsInProgress());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- IsComplete: '%i'", __FUNCTION__, download_item->IsComplete());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- IsCanceled: '%i'", __FUNCTION__, download_item->IsCanceled());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetCurrentSpeed: '%li'", __FUNCTION__, download_item->GetCurrentSpeed());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetPercentComplete: '%i'", __FUNCTION__, download_item->GetPercentComplete());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetTotalBytes: '%li'", __FUNCTION__, download_item->GetTotalBytes());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetReceivedBytes: '%li'", __FUNCTION__, download_item->GetReceivedBytes());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetStartTime: '%f'", __FUNCTION__, download_item->GetStartTime().GetDoubleT());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetEndTime: '%f'", __FUNCTION__, download_item->GetEndTime().GetDoubleT());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetFullPath: '%s'", __FUNCTION__, download_item->GetFullPath().ToString().c_str());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetId: '%i'", __FUNCTION__, download_item->GetId());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetURL: '%s'", __FUNCTION__, download_item->GetURL().ToString().c_str());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetOriginalUrl: '%s'", __FUNCTION__, download_item->GetOriginalUrl().ToString().c_str());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetSuggestedFileName: '%s'", __FUNCTION__, download_item->GetSuggestedFileName().ToString().c_str());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetContentDisposition: '%s'", __FUNCTION__, download_item->GetContentDisposition().ToString().c_str());
  LOG_MESSAGE(ADDON_LOG_DEBUG, "%s --- GetMimeType: '%s'", __FUNCTION__, download_item->GetMimeType().ToString().c_str());
#endif

  downloadItem->SetCanceled(download_item->IsCanceled());
  downloadItem->SetInProgress(download_item->IsInProgress());
  downloadItem->SetProgressText(static_cast<long>(download_item->GetTotalBytes() / 1024 / 1024),
                                static_cast<long>(download_item->GetReceivedBytes() / 1024 / 1024),
                                static_cast<float>(download_item->GetPercentComplete()));

  if (download_item->IsComplete())
  {
    downloadItem->SetComplete();

    std::lock_guard<std::mutex> lock(m_mutex);
    m_finishedDownloads[url] = downloadItem;
    m_activeDownloads.erase(url);
    SaveDownloadHistory();

    kodi::Log(ADDON_LOG_INFO, "Download of '%s' finished", download_item->GetOriginalUrl().ToString().c_str());
    kodi::Log(ADDON_LOG_INFO, " - Is valid: '%i'", download_item->IsValid());
    kodi::Log(ADDON_LOG_INFO, " - Is complete: '%i'", download_item->IsComplete());
    kodi::Log(ADDON_LOG_INFO, " - Is canceled: '%i'", download_item->IsCanceled());
    kodi::Log(ADDON_LOG_INFO, " - Total bytes: '%li'", download_item->GetTotalBytes());
    kodi::Log(ADDON_LOG_INFO, " - Received bytes: '%li'", download_item->GetReceivedBytes());
    kodi::Log(ADDON_LOG_INFO, " - Start time: '%f'", download_item->GetStartTime().GetDoubleT());
    kodi::Log(ADDON_LOG_INFO, " - End time: '%f'", download_item->GetEndTime().GetDoubleT());
    kodi::Log(ADDON_LOG_INFO, " - Full path: '%s'", download_item->GetFullPath().ToString().c_str());
    kodi::Log(ADDON_LOG_INFO, " - URL: '%s'", download_item->GetURL().ToString().c_str());
    kodi::Log(ADDON_LOG_INFO, " - Original Url: '%s'", download_item->GetOriginalUrl().ToString().c_str());
    kodi::Log(ADDON_LOG_INFO, " - Suggested file name: '%s'", download_item->GetSuggestedFileName().ToString().c_str());
    kodi::Log(ADDON_LOG_INFO, " - Content disposition: '%s'", download_item->GetContentDisposition().ToString().c_str());
    kodi::Log(ADDON_LOG_INFO, " - Mime type: '%s'", download_item->GetMimeType().ToString().c_str());
  }

  UpdateEntry(downloadItem, download_item->IsComplete());
}