[gnome-software: 1/4] gs-app: Split ‘unknown’ state out of app size values into separate type




commit 451057b7ecb9b9364d30d9af9a7fd9008918d07f
Author: Philip Withnall <pwithnall endlessos org>
Date:   Thu May 12 20:52:30 2022 +0100

    gs-app: Split ‘unknown’ state out of app size values into separate type
    
    Rather than representing an ‘unknown’ size as `0` and an ‘unknowable’
    size as `G_MAXUINT64`, this changes all the size properties in `GsApp`
    to represent them as `(GS_SIZE_TYPE_UNKNOWN, _)` and
    `(GS_SIZE_TYPE_UNKNOWABLE, _)`, and to represent known/valid sizes as
    `(GS_SIZE_TYPE_VALID, size)`.
    
    This allows `0` byte sizes to be represented consistently, which is
    important for indicating that an app doesn’t need any additional
    downloads (if `GsApp:size-download` is `0`, for example).
    
    Signed-off-by: Philip Withnall <pwithnall endlessos org>

 doc/api/gnome-software-docs.xml                    |   4 +-
 lib/gs-app.c                                       | 588 ++++++++++++++++-----
 lib/gs-app.h                                       |  54 +-
 lib/gs-metered.c                                   |   4 +-
 plugins/dpkg/gs-plugin-dpkg.c                      |   2 +-
 plugins/dummy/gs-plugin-dummy.c                    |   8 +-
 plugins/eos-updater/gs-plugin-eos-updater.c        |  20 +-
 plugins/epiphany/gs-plugin-epiphany.c              |   2 +-
 .../gs-plugin-fedora-pkgdb-collections.c           |   4 +-
 plugins/flatpak/gs-flatpak-utils.c                 |   4 +-
 plugins/flatpak/gs-flatpak.c                       |  68 ++-
 plugins/fwupd/gs-fwupd-app.c                       |   4 +-
 plugins/fwupd/gs-plugin-fwupd.c                    |   4 +-
 plugins/fwupd/gs-self-test.c                       |   6 +-
 plugins/packagekit/gs-plugin-packagekit.c          |  18 +-
 plugins/packagekit/packagekit-common.c             |  32 +-
 plugins/rpm-ostree/gs-plugin-rpm-ostree.c          |   6 +-
 plugins/snap/gs-plugin-snap.c                      |  23 +-
 plugins/snap/gs-self-test.c                        |  19 +-
 src/gs-app-context-bar.c                           |  40 +-
 src/gs-app-row.c                                   |   9 +-
 src/gs-storage-context-dialog.c                    |  63 ++-
 src/gs-update-monitor.c                            |  11 +-
 src/gs-updates-section.c                           |  12 +-
 src/gs-upgrade-banner.c                            |  18 +-
 25 files changed, 730 insertions(+), 293 deletions(-)
---
diff --git a/doc/api/gnome-software-docs.xml b/doc/api/gnome-software-docs.xml
index ecc9545d5..50e321a4a 100644
--- a/doc/api/gnome-software-docs.xml
+++ b/doc/api/gnome-software-docs.xml
@@ -247,8 +247,8 @@ gs_plugin_custom_list_installed_apps_async (GsPlugin                       *plug
 
   /* these are all optional, but make details page looks better */
   gs_app_set_version (app, "1.2.3");
-  gs_app_set_size_installed (app, 2 * 1024 * 1024);
-  gs_app_set_size_download (app, 3 * 1024 * 1024);
+  gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, 2 * 1024 * 1024);
+  gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, 3 * 1024 * 1024);
   gs_app_set_origin_hostname (app, "http://www.teaching-example.org/";);
   gs_app_add_category (app, "Game");
   gs_app_add_category (app, "ActionGame");
diff --git a/lib/gs-app.c b/lib/gs-app.c
index 7dfb6e02f..573d1a822 100644
--- a/lib/gs-app.c
+++ b/lib/gs-app.c
@@ -101,10 +101,16 @@ typedef struct
        GArray                  *review_ratings;
        GPtrArray               *reviews; /* of AsReview */
        GPtrArray               *provided; /* of AsProvided */
+
+       GsSizeType               size_installed_type;
        guint64                  size_installed;
+       GsSizeType               size_download_type;
        guint64                  size_download;
+       GsSizeType               size_user_data_type;
        guint64                  size_user_data;
+       GsSizeType               size_cache_data_type;
        guint64                  size_cache_data;
+
        AsComponentKind          kind;
        GsAppSpecialKind         special_kind;
        GsAppState               state;
@@ -158,11 +164,17 @@ typedef enum {
        PROP_URL_MISSING,
        PROP_CONTENT_RATING,
        PROP_LICENSE,
+       PROP_SIZE_CACHE_DATA_TYPE,
        PROP_SIZE_CACHE_DATA,
+       PROP_SIZE_DOWNLOAD_TYPE,
        PROP_SIZE_DOWNLOAD,
+       PROP_SIZE_DOWNLOAD_DEPENDENCIES_TYPE,
        PROP_SIZE_DOWNLOAD_DEPENDENCIES,
+       PROP_SIZE_INSTALLED_TYPE,
        PROP_SIZE_INSTALLED,
+       PROP_SIZE_INSTALLED_DEPENDENCIES_TYPE,
        PROP_SIZE_INSTALLED_DEPENDENCIES,
+       PROP_SIZE_USER_DATA_TYPE,
        PROP_SIZE_USER_DATA,
        PROP_PERMISSIONS,
        PROP_RELATIONS,
@@ -269,15 +281,27 @@ gs_app_kv_lpad (GString *str, const gchar *key, const gchar *value)
 }
 
 static void
-gs_app_kv_size (GString *str, const gchar *key, guint64 value)
+gs_app_kv_size (GString     *str,
+                const gchar *key,
+                GsSizeType   size_type,
+                guint64      value)
 {
        g_autofree gchar *tmp = NULL;
-       if (value == GS_APP_SIZE_UNKNOWABLE) {
+
+       switch (size_type) {
+       case GS_SIZE_TYPE_UNKNOWN:
+               gs_app_kv_lpad (str, key, "unknown");
+               break;
+       case GS_SIZE_TYPE_UNKNOWABLE:
                gs_app_kv_lpad (str, key, "unknowable");
-               return;
+               break;
+       case GS_SIZE_TYPE_VALID:
+               tmp = g_format_size (value);
+               gs_app_kv_lpad (str, key, tmp);
+               break;
+       default:
+               g_assert_not_reached ();
        }
-       tmp = g_format_size (value);
-       gs_app_kv_lpad (str, key, tmp);
 }
 
 G_GNUC_PRINTF (3, 4)
@@ -515,6 +539,8 @@ gs_app_to_string_append (GsApp *app, GString *str)
        const gchar *tmp;
        guint i;
        g_autoptr(GsPlugin) management_plugin = NULL;
+       GsSizeType size_download_dependencies_type, size_installed_dependencies_type;
+       guint64 size_download_dependencies_bytes, size_installed_dependencies_bytes;
 
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (str != NULL);
@@ -681,18 +707,15 @@ gs_app_to_string_append (GsApp *app, GString *str)
                                  G_GUINT64_FORMAT "",
                                  priv->release_date);
        }
-       if (priv->size_installed != 0)
-               gs_app_kv_size (str, "size-installed", priv->size_installed);
-       if (gs_app_get_size_installed_dependencies (app) != 0)
-               gs_app_kv_size (str, "size-installed-dependencies", gs_app_get_size_installed_dependencies 
(app));
-       if (priv->size_download != 0)
-               gs_app_kv_size (str, "size-download", gs_app_get_size_download (app));
-       if (gs_app_get_size_download_dependencies (app) != 0)
-               gs_app_kv_size (str, "size-download-dependencies", gs_app_get_size_download_dependencies 
(app));
-       if (priv->size_cache_data != GS_APP_SIZE_UNKNOWABLE)
-               gs_app_kv_size (str, "size-cache-data", gs_app_get_size_cache_data (app));
-       if (priv->size_user_data != GS_APP_SIZE_UNKNOWABLE)
-               gs_app_kv_size (str, "size-user-data", gs_app_get_size_user_data (app));
+
+       gs_app_kv_size (str, "size-installed", priv->size_installed_type, priv->size_installed);
+       size_installed_dependencies_type = gs_app_get_size_installed_dependencies (app, 
&size_installed_dependencies_bytes);
+       gs_app_kv_size (str, "size-installed-dependencies", size_installed_dependencies_type, 
size_installed_dependencies_bytes);
+       gs_app_kv_size (str, "size-download", priv->size_download_type, priv->size_download);
+       size_download_dependencies_type = gs_app_get_size_download_dependencies (app, 
&size_download_dependencies_bytes);
+       gs_app_kv_size (str, "size-download-dependencies", size_download_dependencies_type, 
size_download_dependencies_bytes);
+       gs_app_kv_size (str, "size-cache-data", priv->size_cache_data_type, priv->size_cache_data);
+       gs_app_kv_size (str, "size-user-data", priv->size_user_data_type, priv->size_user_data);
 
        for (i = 0; i < gs_app_list_length (priv->related); i++) {
                GsApp *app_tmp = gs_app_list_index (priv->related, i);
@@ -3523,227 +3546,412 @@ gs_app_add_provided_item (GsApp *app, AsProvidedKind kind, const gchar *item)
 /**
  * gs_app_get_size_download:
  * @app: A #GsApp
+ * @size_bytes_out: (optional) (out caller-allocates): return location for
+ *   the download size, in bytes, or %NULL to ignore
  *
- * Get the value of #GsApp:size-download.
+ * Get the values of #GsApp:size-download-type and #GsApp:size-download.
  *
- * Returns: number of bytes, `0` for unknown, or %GS_APP_SIZE_UNKNOWABLE for invalid
+ * If this returns %GS_SIZE_TYPE_VALID, @size_bytes_out (if non-%NULL) will be
+ * set to the download size. Otherwise, its value will be undefined.
  *
- * Since: 3.22
+ * Returns: type of the download size
+ * Since: 43
  **/
-guint64
-gs_app_get_size_download (GsApp *app)
+GsSizeType
+gs_app_get_size_download (GsApp   *app,
+                          guint64 *size_bytes_out)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
 
-       g_return_val_if_fail (GS_IS_APP (app), G_MAXUINT64);
+       g_return_val_if_fail (GS_IS_APP (app), GS_SIZE_TYPE_UNKNOWN);
 
-       return priv->size_download;
+       if (size_bytes_out != NULL)
+               *size_bytes_out = (priv->size_download_type == GS_SIZE_TYPE_VALID) ? priv->size_download : 0;
+
+       return priv->size_download_type;
 }
 
 /**
  * gs_app_set_size_download:
  * @app: a #GsApp
- * @size_download: size in bytes, or %GS_APP_SIZE_UNKNOWABLE for invalid
+ * @size_type: type of the download size
+ * @size_bytes: size in bytes
  *
  * Sets the download size of the application, not including any
  * required runtime.
  *
- * Since: 3.22
+ * @size_bytes will be ignored unless @size_type is %GS_SIZE_TYPE_VALID.
+ *
+ * Since: 43
  **/
 void
-gs_app_set_size_download (GsApp *app, guint64 size_download)
+gs_app_set_size_download (GsApp      *app,
+                          GsSizeType  size_type,
+                          guint64     size_bytes)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
+
        g_return_if_fail (GS_IS_APP (app));
-       if (size_download == priv->size_download)
-               return;
-       priv->size_download = size_download;
-       gs_app_queue_notify (app, obj_props[PROP_SIZE_DOWNLOAD]);
+
+       if (size_type != GS_SIZE_TYPE_VALID)
+               size_bytes = 0;
+
+       if (priv->size_download_type != size_type) {
+               priv->size_download_type = size_type;
+               gs_app_queue_notify (app, obj_props[PROP_SIZE_DOWNLOAD_TYPE]);
+       }
+
+       if (priv->size_download != size_bytes) {
+               priv->size_download = size_bytes;
+               gs_app_queue_notify (app, obj_props[PROP_SIZE_DOWNLOAD]);
+       }
+}
+
+/* Add two sizes, accounting for their validity, and checking for overflow. This
+ * is essentially `out_bytes = a_bytes + b_bytes` with additional checking.
+ *
+ * If either of @a_type or @b_type is %GS_SIZE_TYPE_UNKNOWN or
+ * %GS_SIZE_TYPE_UNKNOWABLE, that type will be propagated to @out_type.
+ *
+ * If the sum of @a_bytes and @b_bytes exceeds %G_MAXUINT64, the result in
+ * @out_bytes will silently be clamped to %G_MAXUINT64.
+ */
+static gboolean
+add_sizes (GsSizeType  a_type,
+           guint64     a_bytes,
+           GsSizeType  b_type,
+           guint64     b_bytes,
+           GsSizeType *out_type,
+           guint64    *out_bytes)
+{
+       g_return_val_if_fail (out_type != NULL, FALSE);
+       g_return_val_if_fail (out_bytes != NULL, FALSE);
+
+       if (a_type == GS_SIZE_TYPE_VALID && b_type == GS_SIZE_TYPE_VALID) {
+               *out_type = GS_SIZE_TYPE_VALID;
+               if (!g_uint64_checked_add (out_bytes, a_bytes, b_bytes))
+                       *out_bytes = G_MAXUINT64;
+               return TRUE;
+       }
+
+       *out_type = (a_type == GS_SIZE_TYPE_UNKNOWABLE || b_type == GS_SIZE_TYPE_UNKNOWABLE) ? 
GS_SIZE_TYPE_UNKNOWABLE : GS_SIZE_TYPE_UNKNOWN;
+       *out_bytes = 0;
+
+       return FALSE;
 }
 
 /**
  * gs_app_get_size_download_dependencies:
  * @app: A #GsApp
+ * @size_bytes_out: (optional) (out caller-allocates): return location for
+ *   the download size of dependencies, in bytes, or %NULL to ignore
  *
- * Get the value of #GsApp:size-download-dependencies.
+ * Get the value of #GsApp:size-download-dependencies-type and
+ * #GsApp:size-download-dependencies.
  *
- * Returns: number of bytes, `0` for unknown
+ * If this returns %GS_SIZE_TYPE_VALID, @size_bytes_out (if non-%NULL) will be
+ * set to the download size of dependencies. Otherwise, its value will be
+ * undefined.
  *
- * Since: 41
+ * Returns: type of the download size of dependencies
+ * Since: 43
  **/
-guint64
-gs_app_get_size_download_dependencies (GsApp *app)
+GsSizeType
+gs_app_get_size_download_dependencies (GsApp   *app,
+                                       guint64 *size_bytes_out)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       guint64 sz = 0;
+       GsSizeType size_type = GS_SIZE_TYPE_VALID;
+       guint64 size_bytes = 0;
 
-       g_return_val_if_fail (GS_IS_APP (app), G_MAXUINT64);
+       g_return_val_if_fail (GS_IS_APP (app), GS_SIZE_TYPE_UNKNOWN);
 
        /* add the runtime if this is not installed */
-       if (priv->runtime != NULL) {
-               if (gs_app_get_state (priv->runtime) == GS_APP_STATE_AVAILABLE)
-                       sz += gs_app_get_size_download (priv->runtime) +
-                             gs_app_get_size_download_dependencies (priv->runtime);
+       if (priv->runtime != NULL &&
+           gs_app_get_state (priv->runtime) == GS_APP_STATE_AVAILABLE) {
+               GsSizeType runtime_size_download_type, runtime_size_download_dependencies_type;
+               guint64 runtime_size_download_bytes, runtime_size_download_dependencies_bytes;
+
+               runtime_size_download_type = gs_app_get_size_download (priv->runtime, 
&runtime_size_download_bytes);
+
+               if (add_sizes (size_type, size_bytes,
+                              runtime_size_download_type, runtime_size_download_bytes,
+                              &size_type, &size_bytes)) {
+                       runtime_size_download_dependencies_type = gs_app_get_size_download_dependencies 
(priv->runtime, &runtime_size_download_dependencies_bytes);
+
+                       add_sizes (size_type, size_bytes,
+                                  runtime_size_download_dependencies_type, 
runtime_size_download_dependencies_bytes,
+                                  &size_type, &size_bytes);
+               }
        }
 
        /* add related apps */
        for (guint i = 0; i < gs_app_list_length (priv->related); i++) {
                GsApp *app_related = gs_app_list_index (priv->related, i);
-               sz += gs_app_get_size_download (app_related) +
-                     gs_app_get_size_download_dependencies (app_related);
+               GsSizeType related_size_download_type, related_size_download_dependencies_type;
+               guint64 related_size_download_bytes, related_size_download_dependencies_bytes;
+
+               related_size_download_type = gs_app_get_size_download (app_related, 
&related_size_download_bytes);
+
+               if (!add_sizes (size_type, size_bytes,
+                               related_size_download_type, related_size_download_bytes,
+                               &size_type, &size_bytes))
+                       break;
+
+               related_size_download_dependencies_type = gs_app_get_size_download_dependencies (app_related, 
&related_size_download_dependencies_bytes);
+
+               if (!add_sizes (size_type, size_bytes,
+                               related_size_download_dependencies_type, 
related_size_download_dependencies_bytes,
+                               &size_type, &size_bytes))
+                       break;
        }
 
-       return sz;
+       if (size_bytes_out != NULL)
+               *size_bytes_out = (size_type == GS_SIZE_TYPE_VALID) ? size_bytes : 0;
+
+       return size_type;
 }
 
 /**
  * gs_app_get_size_installed:
  * @app: a #GsApp
+ * @size_bytes_out: (optional) (out caller-allocates): return location for
+ *   the installed size, in bytes, or %NULL to ignore
  *
- * Get the value of #GsApp:size-installed.
+ * Get the values of #GsApp:size-installed-type and #GsApp:size-installed.
  *
- * Returns: size in bytes, `0` for unknown, or %GS_APP_SIZE_UNKNOWABLE for invalid.
+ * If this returns %GS_SIZE_TYPE_VALID, @size_bytes_out (if non-%NULL) will be
+ * set to the installed size. Otherwise, its value will be undefined.
  *
- * Since: 3.22
+ * Returns: type of the installed size
+ * Since: 43
  **/
-guint64
-gs_app_get_size_installed (GsApp *app)
+GsSizeType
+gs_app_get_size_installed (GsApp   *app,
+                           guint64 *size_bytes_out)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
 
-       g_return_val_if_fail (GS_IS_APP (app), G_MAXUINT64);
+       g_return_val_if_fail (GS_IS_APP (app), GS_SIZE_TYPE_UNKNOWN);
+
+       if (size_bytes_out != NULL)
+               *size_bytes_out = (priv->size_installed_type == GS_SIZE_TYPE_VALID) ? priv->size_installed : 
0;
 
-       return priv->size_installed;
+       return priv->size_installed_type;
 }
 
 /**
  * gs_app_set_size_installed:
  * @app: a #GsApp
- * @size_installed: size in bytes, or %GS_APP_SIZE_UNKNOWABLE for invalid
+ * @size_type: type of the installed size
+ * @size_bytes: size in bytes
  *
  * Sets the installed size of the application.
  *
- * Since: 3.22
+ * @size_bytes will be ignored unless @size_type is %GS_SIZE_TYPE_VALID.
+ *
+ * Since: 43
  **/
 void
-gs_app_set_size_installed (GsApp *app, guint64 size_installed)
+gs_app_set_size_installed (GsApp      *app,
+                           GsSizeType  size_type,
+                           guint64     size_bytes)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
+
        g_return_if_fail (GS_IS_APP (app));
-       if (size_installed == priv->size_installed)
-               return;
-       priv->size_installed = size_installed;
-       gs_app_queue_notify (app, obj_props[PROP_SIZE_INSTALLED]);
+
+       if (size_type != GS_SIZE_TYPE_VALID)
+               size_bytes = 0;
+
+       if (priv->size_installed_type != size_type) {
+               priv->size_installed_type = size_type;
+               gs_app_queue_notify (app, obj_props[PROP_SIZE_INSTALLED_TYPE]);
+       }
+
+       if (priv->size_installed != size_bytes) {
+               priv->size_installed = size_bytes;
+               gs_app_queue_notify (app, obj_props[PROP_SIZE_INSTALLED]);
+       }
 }
 
 /**
  * gs_app_get_size_installed_dependencies:
  * @app: a #GsApp
+ * @size_bytes_out: (optional) (out caller-allocates): return location for
+ *   the installed size of dependencies, in bytes, or %NULL to ignore
  *
- * Get the value of #GsApp:size-installed-dependencies.
+ * Get the values of #GsApp:size-installed-dependencies-type and
+ * #GsApp:size-installed-dependencies.
  *
- * Returns: size in bytes, `0` for unknown.
+ * If this returns %GS_SIZE_TYPE_VALID, @size_bytes_out (if non-%NULL) will be
+ * set to the installed size of dependencies. Otherwise, its value will be
+ * undefined.
  *
- * Since: 41
+ * Returns: type of the installed size of dependencies
+ * Since: 43
  **/
-guint64
-gs_app_get_size_installed_dependencies (GsApp *app)
+GsSizeType
+gs_app_get_size_installed_dependencies (GsApp   *app,
+                                        guint64 *size_bytes_out)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       guint64 sz = 0;
+       GsSizeType size_type = GS_SIZE_TYPE_VALID;
+       guint64 size_bytes = 0;
 
-       g_return_val_if_fail (GS_IS_APP (app), G_MAXUINT64);
+       g_return_val_if_fail (GS_IS_APP (app), GS_SIZE_TYPE_UNKNOWN);
 
        /* add related apps */
        for (guint i = 0; i < gs_app_list_length (priv->related); i++) {
                GsApp *app_related = gs_app_list_index (priv->related, i);
-               sz += gs_app_get_size_installed (app_related) +
-                     gs_app_get_size_installed_dependencies (app_related);
+               GsSizeType related_size_installed_type, related_size_installed_dependencies_type;
+               guint64 related_size_installed_bytes, related_size_installed_dependencies_bytes;
+
+               related_size_installed_type = gs_app_get_size_installed (app_related, 
&related_size_installed_bytes);
+
+               if (!add_sizes (size_type, size_bytes,
+                               related_size_installed_type, related_size_installed_bytes,
+                               &size_type, &size_bytes))
+                       break;
+
+               related_size_installed_dependencies_type = gs_app_get_size_installed_dependencies 
(app_related, &related_size_installed_dependencies_bytes);
+
+               if (!add_sizes (size_type, size_bytes,
+                               related_size_installed_dependencies_type, 
related_size_installed_dependencies_bytes,
+                               &size_type, &size_bytes))
+                       break;
        }
 
-       return sz;
+       if (size_bytes_out != NULL)
+               *size_bytes_out = (size_type == GS_SIZE_TYPE_VALID) ? size_bytes : 0;
+
+       return size_type;
 }
 
 /**
  * gs_app_get_size_user_data:
  * @app: A #GsApp
+ * @size_bytes_out: (optional) (out caller-allocates): return location for
+ *   the user data size, in bytes, or %NULL to ignore
  *
- * Get the value of #GsApp:size-user-data.
+ * Get the values of #GsApp:size-user-data-type and #GsApp:size-user-data.
  *
- * Returns: number of bytes, or %GS_APP_SIZE_UNKNOWABLE for unknown
+ * If this returns %GS_SIZE_TYPE_VALID, @size_bytes_out (if non-%NULL) will be
+ * set to the user data size. Otherwise, its value will be undefined.
  *
- * Since: 41
+ * Returns: type of the user data size
+ * Since: 43
  **/
-guint64
-gs_app_get_size_user_data (GsApp *app)
+GsSizeType
+gs_app_get_size_user_data (GsApp   *app,
+                           guint64 *size_bytes_out)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
 
-       g_return_val_if_fail (GS_IS_APP (app), GS_APP_SIZE_UNKNOWABLE);
+       g_return_val_if_fail (GS_IS_APP (app), GS_SIZE_TYPE_UNKNOWN);
+
+       if (size_bytes_out != NULL)
+               *size_bytes_out = (priv->size_user_data_type == GS_SIZE_TYPE_VALID) ? priv->size_user_data : 
0;
 
-       return priv->size_user_data;
+       return priv->size_user_data_type;
 }
 
 /**
  * gs_app_set_size_user_data:
  * @app: a #GsApp
- * @size_user_data: size in bytes, or %GS_APP_SIZE_UNKNOWABLE for unknown
+ * @size_type: type of the user data size
+ * @size_bytes: size in bytes
  *
  * Sets the user data size of the @app.
  *
- * Since: 41
+ * @size_bytes will be ignored unless @size_type is %GS_SIZE_TYPE_VALID.
+ *
+ * Since: 43
  **/
 void
-gs_app_set_size_user_data (GsApp *app,
-                          guint64 size_user_data)
+gs_app_set_size_user_data (GsApp      *app,
+                           GsSizeType  size_type,
+                           guint64     size_bytes)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
+
        g_return_if_fail (GS_IS_APP (app));
-       if (size_user_data == priv->size_user_data)
-               return;
-       priv->size_user_data = size_user_data;
-       gs_app_queue_notify (app, obj_props[PROP_SIZE_USER_DATA]);
+
+       if (size_type != GS_SIZE_TYPE_VALID)
+               size_bytes = 0;
+
+       if (priv->size_user_data_type != size_type) {
+               priv->size_user_data_type = size_type;
+               gs_app_queue_notify (app, obj_props[PROP_SIZE_USER_DATA_TYPE]);
+       }
+
+       if (priv->size_user_data != size_bytes) {
+               priv->size_user_data = size_bytes;
+               gs_app_queue_notify (app, obj_props[PROP_SIZE_USER_DATA]);
+       }
 }
 
 /**
  * gs_app_get_size_cache_data:
  * @app: A #GsApp
+ * @size_bytes_out: (optional) (out caller-allocates): return location for
+ *   the cache data size, in bytes, or %NULL to ignore
  *
- * Get the value of #GsApp:size-cache-data.
+ * Get the values of #GsApp:size-cache-data-type and #GsApp:size-cache-data.
  *
- * Returns: number of bytes, or %GS_APP_SIZE_UNKNOWABLE for unknown
+ * If this returns %GS_SIZE_TYPE_VALID, @size_bytes_out (if non-%NULL) will be
+ * set to the cache data size. Otherwise, its value will be undefined.
  *
- * Since: 41
+ * Returns: type of the cache data size
+ * Since: 43
  **/
-guint64
-gs_app_get_size_cache_data (GsApp *app)
+GsSizeType
+gs_app_get_size_cache_data (GsApp   *app,
+                            guint64 *size_bytes_out)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
 
-       g_return_val_if_fail (GS_IS_APP (app), GS_APP_SIZE_UNKNOWABLE);
+       g_return_val_if_fail (GS_IS_APP (app), GS_SIZE_TYPE_UNKNOWN);
 
-       return priv->size_cache_data;
+       if (size_bytes_out != NULL)
+               *size_bytes_out = (priv->size_cache_data_type == GS_SIZE_TYPE_VALID) ? priv->size_cache_data 
: 0;
+
+       return priv->size_cache_data_type;
 }
 
 /**
  * gs_app_set_size_cache_data:
  * @app: a #GsApp
- * @size_cache_data: size in bytes, or %GS_APP_SIZE_UNKNOWABLE for unknown
+ * @size_type: type of the cache data size
+ * @size_bytes: size in bytes
  *
  * Sets the cache data size of the @app.
  *
- * Since: 41
+ * @size_bytes will be ignored unless @size_type is %GS_SIZE_TYPE_VALID.
+ *
+ * Since: 43
  **/
 void
-gs_app_set_size_cache_data (GsApp *app,
-                           guint64 size_cache_data)
+gs_app_set_size_cache_data (GsApp      *app,
+                            GsSizeType  size_type,
+                            guint64     size_bytes)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
+
        g_return_if_fail (GS_IS_APP (app));
-       if (size_cache_data == priv->size_cache_data)
-               return;
-       priv->size_cache_data = size_cache_data;
-       gs_app_queue_notify (app, obj_props[PROP_SIZE_CACHE_DATA]);
+
+       if (size_type != GS_SIZE_TYPE_VALID)
+               size_bytes = 0;
+
+       if (priv->size_cache_data_type != size_type) {
+               priv->size_cache_data_type = size_type;
+               gs_app_queue_notify (app, obj_props[PROP_SIZE_CACHE_DATA_TYPE]);
+       }
+
+       if (priv->size_cache_data != size_bytes) {
+               priv->size_cache_data = size_bytes;
+               gs_app_queue_notify (app, obj_props[PROP_SIZE_CACHE_DATA]);
+       }
 }
 
 /**
@@ -3989,7 +4197,9 @@ gs_app_add_related (GsApp *app, GsApp *app2)
        gs_app_list_add (priv->related, app2);
 
        /* The related apps add to the main app’s sizes. */
+       gs_app_queue_notify (app, obj_props[PROP_SIZE_DOWNLOAD_DEPENDENCIES_TYPE]);
        gs_app_queue_notify (app, obj_props[PROP_SIZE_DOWNLOAD_DEPENDENCIES]);
+       gs_app_queue_notify (app, obj_props[PROP_SIZE_INSTALLED_DEPENDENCIES_TYPE]);
        gs_app_queue_notify (app, obj_props[PROP_SIZE_INSTALLED_DEPENDENCIES]);
 }
 
@@ -5002,24 +5212,60 @@ gs_app_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *
        case PROP_LICENSE:
                g_value_set_string (value, priv->license);
                break;
-       case PROP_SIZE_CACHE_DATA:
-               g_value_set_uint64 (value, gs_app_get_size_cache_data (app));
+       case PROP_SIZE_CACHE_DATA_TYPE:
+               g_value_set_enum (value, gs_app_get_size_cache_data (app, NULL));
                break;
-       case PROP_SIZE_DOWNLOAD:
-               g_value_set_uint64 (value, gs_app_get_size_download (app));
+       case PROP_SIZE_CACHE_DATA: {
+               guint64 size_bytes;
+               gs_app_get_size_cache_data (app, &size_bytes);
+               g_value_set_uint64 (value, size_bytes);
                break;
-       case PROP_SIZE_DOWNLOAD_DEPENDENCIES:
-               g_value_set_uint64 (value, gs_app_get_size_download_dependencies (app));
+       }
+       case PROP_SIZE_DOWNLOAD_TYPE:
+               g_value_set_enum (value, gs_app_get_size_download (app, NULL));
                break;
-       case PROP_SIZE_INSTALLED:
-               g_value_set_uint64 (value, gs_app_get_size_installed (app));
+       case PROP_SIZE_DOWNLOAD: {
+               guint64 size_bytes;
+               gs_app_get_size_download (app, &size_bytes);
+               g_value_set_uint64 (value, size_bytes);
                break;
-       case PROP_SIZE_INSTALLED_DEPENDENCIES:
-               g_value_set_uint64 (value, gs_app_get_size_installed_dependencies (app));
+       }
+       case PROP_SIZE_DOWNLOAD_DEPENDENCIES_TYPE:
+               g_value_set_enum (value, gs_app_get_size_download_dependencies (app, NULL));
                break;
-       case PROP_SIZE_USER_DATA:
-               g_value_set_uint64 (value, gs_app_get_size_user_data (app));
+       case PROP_SIZE_DOWNLOAD_DEPENDENCIES: {
+               guint64 size_bytes;
+               gs_app_get_size_download_dependencies (app, &size_bytes);
+               g_value_set_uint64 (value, size_bytes);
+               break;
+       }
+       case PROP_SIZE_INSTALLED_TYPE:
+               g_value_set_enum (value, gs_app_get_size_installed (app, NULL));
+               break;
+       case PROP_SIZE_INSTALLED: {
+               guint64 size_bytes;
+               gs_app_get_size_installed (app, &size_bytes);
+               g_value_set_uint64 (value, size_bytes);
+               break;
+       }
+       case PROP_SIZE_INSTALLED_DEPENDENCIES_TYPE:
+               g_value_set_enum (value, gs_app_get_size_installed_dependencies (app, NULL));
                break;
+       case PROP_SIZE_INSTALLED_DEPENDENCIES: {
+               guint64 size_bytes;
+               gs_app_get_size_installed_dependencies (app, &size_bytes);
+               g_value_set_uint64 (value, size_bytes);
+               break;
+       }
+       case PROP_SIZE_USER_DATA_TYPE:
+               g_value_set_enum (value, gs_app_get_size_user_data (app, NULL));
+               break;
+       case PROP_SIZE_USER_DATA: {
+               guint64 size_bytes;
+               gs_app_get_size_user_data (app, &size_bytes);
+               g_value_set_uint64 (value, size_bytes);
+               break;
+       }
        case PROP_PERMISSIONS:
                g_value_set_flags (value, priv->permissions);
                break;
@@ -5116,23 +5362,37 @@ gs_app_set_property (GObject *object, guint prop_id, const GValue *value, GParam
        case PROP_LICENSE:
                /* Read-only */
                g_assert_not_reached ();
+       case PROP_SIZE_CACHE_DATA_TYPE:
+               gs_app_set_size_cache_data (app, g_value_get_enum (value), priv->size_cache_data);
+               break;
        case PROP_SIZE_CACHE_DATA:
-               gs_app_set_size_cache_data (app, g_value_get_uint64 (value));
+               gs_app_set_size_cache_data (app, priv->size_cache_data_type, g_value_get_uint64 (value));
+               break;
+       case PROP_SIZE_DOWNLOAD_TYPE:
+               gs_app_set_size_download (app, g_value_get_enum (value), priv->size_download);
                break;
        case PROP_SIZE_DOWNLOAD:
-               gs_app_set_size_download (app, g_value_get_uint64 (value));
+               gs_app_set_size_download (app, priv->size_download_type, g_value_get_uint64 (value));
                break;
+       case PROP_SIZE_DOWNLOAD_DEPENDENCIES_TYPE:
        case PROP_SIZE_DOWNLOAD_DEPENDENCIES:
                /* Read-only */
                g_assert_not_reached ();
+       case PROP_SIZE_INSTALLED_TYPE:
+               gs_app_set_size_installed (app, g_value_get_enum (value), priv->size_installed);
+               break;
        case PROP_SIZE_INSTALLED:
-               gs_app_set_size_installed (app, g_value_get_uint64 (value));
+               gs_app_set_size_installed (app, priv->size_installed_type, g_value_get_uint64 (value));
                break;
+       case PROP_SIZE_INSTALLED_DEPENDENCIES_TYPE:
        case PROP_SIZE_INSTALLED_DEPENDENCIES:
                /* Read-only */
                g_assert_not_reached ();
+       case PROP_SIZE_USER_DATA_TYPE:
+               gs_app_set_size_user_data (app, g_value_get_enum (value), priv->size_user_data);
+               break;
        case PROP_SIZE_USER_DATA:
-               gs_app_set_size_user_data (app, g_value_get_uint64 (value));
+               gs_app_set_size_user_data (app, priv->size_user_data_type, g_value_get_uint64 (value));
                break;
        case PROP_PERMISSIONS:
                gs_app_set_permissions (app, g_value_get_flags (value));
@@ -5429,12 +5689,25 @@ gs_app_class_init (GsAppClass *klass)
                                     NULL,
                                     G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
+       /**
+        * GsApp:size-cache-data-type
+        *
+        * The type of #GsApp:size-cache-data.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_SIZE_CACHE_DATA_TYPE] =
+               g_param_spec_enum ("size-cache-data-type", NULL, NULL,
+                                  GS_TYPE_SIZE_TYPE, GS_SIZE_TYPE_UNKNOWN,
+                                  G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
        /**
         * GsApp:size-cache-data
         *
         * The size on the disk for the cache data of the application.
         *
-        * This is %GS_APP_SIZE_UNKNOWABLE if not known.
+        * This is undefined if #GsApp:size-cache-data-type is not
+        * %GS_SIZE_TYPE_VALID.
         *
         * Since: 41
         */
@@ -5443,6 +5716,18 @@ gs_app_class_init (GsAppClass *klass)
                                     0, G_MAXUINT64, 0,
                                     G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
+       /**
+        * GsApp:size-download-type
+        *
+        * The type of #GsApp:size-download.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_SIZE_DOWNLOAD_TYPE] =
+               g_param_spec_enum ("size-download-type", NULL, NULL,
+                                  GS_TYPE_SIZE_TYPE, GS_SIZE_TYPE_UNKNOWN,
+                                  G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
        /**
         * GsApp:size-download
         *
@@ -5450,8 +5735,8 @@ gs_app_class_init (GsAppClass *klass)
         * this application, in bytes. If the app is partially downloaded, this
         * is the number of bytes remaining to download.
         *
-        * This is `0` if the download size is unknown, and
-        * %GS_APP_SIZE_UNKNOWABLE if it’s not possible to know.
+        * This is undefined if #GsApp:size-download-type is not
+        * %GS_SIZE_TYPE_VALID.
         *
         * To get the runtime or other dependencies download size,
         * use #GsApp:size-download-dependencies.
@@ -5463,6 +5748,18 @@ gs_app_class_init (GsAppClass *klass)
                                     0, G_MAXUINT64, 0,
                                     G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
+       /**
+        * GsApp:size-download-dependencies-type
+        *
+        * The type of #GsApp:size-download-dependencies.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_SIZE_DOWNLOAD_DEPENDENCIES_TYPE] =
+               g_param_spec_enum ("size-download-dependencies-type", NULL, NULL,
+                                  GS_TYPE_SIZE_TYPE, GS_SIZE_TYPE_UNKNOWN,
+                                  G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
        /**
         * GsApp:size-download-dependencies
         *
@@ -5470,7 +5767,8 @@ gs_app_class_init (GsAppClass *klass)
         * this application's dependencies, in bytes. If the dependencies are partially
         * downloaded, this is the number of bytes remaining to download.
         *
-        * This is `0` if the download size is unknown.
+        * This is undefined if #GsApp:size-download-dependencies-type is not
+        * %GS_SIZE_TYPE_VALID.
         *
         * Since: 41
         */
@@ -5479,14 +5777,26 @@ gs_app_class_init (GsAppClass *klass)
                                     0, G_MAXUINT64, 0,
                                     G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
+       /**
+        * GsApp:size-installed-type
+        *
+        * The type of #GsApp:size-installed.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_SIZE_INSTALLED_TYPE] =
+               g_param_spec_enum ("size-installed-type", NULL, NULL,
+                                  GS_TYPE_SIZE_TYPE, GS_SIZE_TYPE_UNKNOWN,
+                                  G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
        /**
         * GsApp:size-installed
         *
         * The size of the application on disk, in bytes. If the application is
         * not yet installed, this is the size it would need, once installed.
         *
-        * This is `0` if the download size is unknown, and
-        * %GS_APP_SIZE_UNKNOWABLE if it’s not possible to know.
+        * This is undefined if #GsApp:size-installed-type is not
+        * %GS_SIZE_TYPE_VALID.
         *
         * To get the application runtime or extensions installed sizes,
         * use #GsApp:size-installed-dependencies.
@@ -5498,13 +5808,26 @@ gs_app_class_init (GsAppClass *klass)
                                     0, G_MAXUINT64, 0,
                                     G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
+       /**
+        * GsApp:size-installed-dependencies-type
+        *
+        * The type of #GsApp:size-installed-dependencies.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_SIZE_INSTALLED_DEPENDENCIES_TYPE] =
+               g_param_spec_enum ("size-installed-dependencies-type", NULL, NULL,
+                                  GS_TYPE_SIZE_TYPE, GS_SIZE_TYPE_UNKNOWN,
+                                  G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
        /**
         * GsApp:size-installed-dependencies
         *
         * The size of the application's dependencies on disk, in bytes. If the dependencies are
         * not yet installed, this is the size it would need, once installed.
         *
-        * This is `0` if the download size is unknown.
+        * This is undefined if #GsApp:size-installed-dependencies-type is not
+        * %GS_SIZE_TYPE_VALID.
         *
         * Since: 41
         */
@@ -5513,12 +5836,25 @@ gs_app_class_init (GsAppClass *klass)
                                     0, G_MAXUINT64, 0,
                                     G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
+       /**
+        * GsApp:size-user-data-type
+        *
+        * The type of #GsApp:size-user-data.
+        *
+        * Since: 43
+        */
+       obj_props[PROP_SIZE_USER_DATA_TYPE] =
+               g_param_spec_enum ("size-user-data-type", NULL, NULL,
+                                  GS_TYPE_SIZE_TYPE, GS_SIZE_TYPE_UNKNOWN,
+                                  G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
        /**
         * GsApp:size-user-data
         *
         * The size on the disk for the user data of the application.
         *
-        * This is %GS_APP_SIZE_UNKNOWABLE if not known.
+        * This is undefined if #GsApp:size-user-data-type is not
+        * %GS_SIZE_TYPE_VALID.
         *
         * Since: 41
         */
@@ -5614,8 +5950,10 @@ gs_app_init (GsApp *app)
                                                   NULL,
                                                   g_free);
        priv->allow_cancel = TRUE;
-       priv->size_cache_data = GS_APP_SIZE_UNKNOWABLE;
-       priv->size_user_data = GS_APP_SIZE_UNKNOWABLE;
+       priv->size_download_type = GS_SIZE_TYPE_UNKNOWN;
+       priv->size_installed_type = GS_SIZE_TYPE_UNKNOWN;
+       priv->size_cache_data_type = GS_SIZE_TYPE_UNKNOWN;
+       priv->size_user_data_type = GS_SIZE_TYPE_UNKNOWN;
        g_mutex_init (&priv->mutex);
 }
 
diff --git a/lib/gs-app.h b/lib/gs-app.h
index e5e64272a..663a65677 100644
--- a/lib/gs-app.h
+++ b/lib/gs-app.h
@@ -171,7 +171,25 @@ typedef enum {
 
 #define        GS_APP_INSTALL_DATE_UNSET               0
 #define        GS_APP_INSTALL_DATE_UNKNOWN             1 /* 1s past the epoch */
-#define        GS_APP_SIZE_UNKNOWABLE                  G_MAXUINT64
+
+/**
+ * GsSizeType:
+ * @GS_SIZE_TYPE_UNKNOWN:      Size is unknown
+ * @GS_SIZE_TYPE_UNKNOWABLE:   Size is unknown and is impossible to calculate
+ * @GS_SIZE_TYPE_VALID:                Size is known and valid
+ *
+ * Types of download or file size for applications.
+ *
+ * These are used to represent the validity of properties like
+ * #GsApp:size-download.
+ *
+ * Since: 43
+ */
+typedef enum {
+       GS_SIZE_TYPE_UNKNOWN,
+       GS_SIZE_TYPE_UNKNOWABLE,
+       GS_SIZE_TYPE_VALID,
+} GsSizeType;
 
 /**
  * GsAppQuality:
@@ -412,22 +430,32 @@ AsProvided        *gs_app_get_provided_for_kind   (GsApp          *app,
 void            gs_app_add_provided_item       (GsApp          *app,
                                                 AsProvidedKind kind,
                                                 const gchar    *item);
-guint64                 gs_app_get_size_installed      (GsApp          *app);
+GsSizeType      gs_app_get_size_installed      (GsApp          *app,
+                                                guint64        *size_bytes_out);
 void            gs_app_set_size_installed      (GsApp          *app,
-                                                guint64         size_installed);
-guint64                 gs_app_get_size_installed_dependencies
-                                               (GsApp          *app);
-guint64                 gs_app_get_size_user_data      (GsApp          *app);
+                                                GsSizeType      size_type,
+                                                guint64         size_bytes);
+GsSizeType      gs_app_get_size_installed_dependencies
+                                               (GsApp          *app,
+                                                guint64        *size_bytes_out);
+GsSizeType      gs_app_get_size_user_data      (GsApp          *app,
+                                                guint64        *size_bytes_out);
 void            gs_app_set_size_user_data      (GsApp          *app,
-                                                guint64         size_user_data);
-guint64                 gs_app_get_size_cache_data     (GsApp          *app);
+                                                GsSizeType      size_type,
+                                                guint64         size_bytes);
+GsSizeType      gs_app_get_size_cache_data     (GsApp          *app,
+                                                guint64        *size_bytes_out);
 void            gs_app_set_size_cache_data     (GsApp          *app,
-                                                guint64         size_cache_data);
-guint64                 gs_app_get_size_download       (GsApp          *app);
+                                                GsSizeType      size_type,
+                                                guint64         size_bytes);
+GsSizeType      gs_app_get_size_download       (GsApp          *app,
+                                                guint64        *size_bytes_out);
 void            gs_app_set_size_download       (GsApp          *app,
-                                                guint64         size_download);
-guint64                 gs_app_get_size_download_dependencies
-                                               (GsApp          *app);
+                                                GsSizeType      size_type,
+                                                guint64         size_bytes);
+GsSizeType      gs_app_get_size_download_dependencies
+                                               (GsApp          *app,
+                                                guint64        *size_bytes_out);
 void            gs_app_add_related             (GsApp          *app,
                                                 GsApp          *app2);
 void            gs_app_add_addons              (GsApp          *app,
diff --git a/lib/gs-metered.c b/lib/gs-metered.c
index d4080e97e..e6a82d96f 100644
--- a/lib/gs-metered.c
+++ b/lib/gs-metered.c
@@ -257,13 +257,13 @@ gs_metered_block_app_on_download_scheduler (GsApp         *app,
 {
        g_auto(GVariantDict) parameters_dict = G_VARIANT_DICT_INIT (NULL);
        g_autoptr(GVariant) parameters = NULL;
-       guint64 download_size = gs_app_get_size_download (app);
+       guint64 download_size;
 
        /* Currently no plugins support resumable downloads. This may change in
         * future, in which case this parameter should be refactored. */
        g_variant_dict_insert (&parameters_dict, "resumable", "b", FALSE);
 
-       if (download_size != 0 && download_size != GS_APP_SIZE_UNKNOWABLE) {
+       if (gs_app_get_size_download (app, &download_size) == GS_SIZE_TYPE_VALID) {
                g_variant_dict_insert (&parameters_dict, "size-minimum", "t", download_size);
                g_variant_dict_insert (&parameters_dict, "size-maximum", "t", download_size);
        }
diff --git a/plugins/dpkg/gs-plugin-dpkg.c b/plugins/dpkg/gs-plugin-dpkg.c
index fe82c2aee..3f886e06f 100644
--- a/plugins/dpkg/gs-plugin-dpkg.c
+++ b/plugins/dpkg/gs-plugin-dpkg.c
@@ -92,7 +92,7 @@ gs_plugin_file_to_app (GsPlugin *plugin,
        gs_app_add_source (app, tokens[0]);
        gs_app_set_name (app, GS_APP_QUALITY_LOWEST, tokens[0]);
        gs_app_set_version (app, tokens[1]);
-       gs_app_set_size_installed (app, 1024 * g_ascii_strtoull (tokens[2], NULL, 10));
+       gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, 1024 * g_ascii_strtoull (tokens[2], NULL, 10));
        gs_app_set_url (app, AS_URL_KIND_HOMEPAGE, tokens[3]);
        gs_app_set_summary (app, GS_APP_QUALITY_LOWEST, tokens[4]);
        gs_app_set_kind (app, AS_COMPONENT_KIND_GENERIC);
diff --git a/plugins/dummy/gs-plugin-dummy.c b/plugins/dummy/gs-plugin-dummy.c
index 58a99f284..2a07bbe73 100644
--- a/plugins/dummy/gs-plugin-dummy.c
+++ b/plugins/dummy/gs-plugin-dummy.c
@@ -424,8 +424,8 @@ gs_plugin_add_search (GsPlugin *plugin,
        gs_app_set_name (app, GS_APP_QUALITY_NORMAL, "Chiron");
        gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, "A teaching application");
        gs_app_add_icon (app, ic);
-       gs_app_set_size_installed (app, 42 * 1024 * 1024);
-       gs_app_set_size_download (app, 50 * 1024 * 1024);
+       gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, 42 * 1024 * 1024);
+       gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, 50 * 1024 * 1024);
        gs_app_set_kind (app, AS_COMPONENT_KIND_DESKTOP_APP);
        gs_app_set_state (app, GS_APP_STATE_INSTALLED);
        gs_app_set_management_plugin (app, plugin);
@@ -977,8 +977,8 @@ gs_plugin_dummy_list_distro_upgrades_async (GsPlugin                        *plu
        gs_app_add_quirk (app, GS_APP_QUIRK_PROVENANCE);
        gs_app_add_quirk (app, GS_APP_QUIRK_NOT_REVIEWABLE);
        gs_app_set_version (app, "34");
-       gs_app_set_size_installed (app, 256 * 1024 * 1024);
-       gs_app_set_size_download (app, 1024 * 1024 * 1024);
+       gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, 256 * 1024 * 1024);
+       gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, 1024 * 1024 * 1024);
        gs_app_set_license (app, GS_APP_QUALITY_LOWEST, "LicenseRef-free");
        gs_app_set_management_plugin (app, plugin);
 
diff --git a/plugins/eos-updater/gs-plugin-eos-updater.c b/plugins/eos-updater/gs-plugin-eos-updater.c
index 6ef5b4c73..e4c626065 100644
--- a/plugins/eos-updater/gs-plugin-eos-updater.c
+++ b/plugins/eos-updater/gs-plugin-eos-updater.c
@@ -388,19 +388,23 @@ sync_state_from_updater_unlocked (GsPluginEosUpdater *self)
                /* Nothing to do here. */
                break;
        } case EOS_UPDATER_STATE_UPDATE_AVAILABLE: {
-               guint64 total_size;
+               gint64 total_size;
 
                app_set_state (plugin, app, GS_APP_STATE_AVAILABLE);
 
+               /* The property returns -1 to indicate unknown size */
                total_size = gs_eos_updater_get_download_size (self->updater_proxy);
-               gs_app_set_size_download (app, total_size);
+               if (total_size >= 0)
+                       gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, total_size);
+               else
+                       gs_app_set_size_download (app, GS_SIZE_TYPE_UNKNOWN, 0);
 
                break;
        }
        case EOS_UPDATER_STATE_FETCHING: {
-               guint64 total_size = 0;
-               guint64 downloaded = 0;
-               gfloat progress = 0;
+               gint64 total_size = 0;
+               gint64 downloaded = 0;
+               guint progress = 0;
 
                /* FIXME: Set to QUEUED_FOR_INSTALL if we’re waiting for metered
                 * data permission. */
@@ -412,13 +416,17 @@ sync_state_from_updater_unlocked (GsPluginEosUpdater *self)
                if (total_size == 0) {
                        g_debug ("OS upgrade %s total size is 0!",
                                 gs_app_get_unique_id (app));
+                       progress = GS_APP_PROGRESS_UNKNOWN;
+               } else if (downloaded < 0 || total_size < 0) {
+                       /* Both properties return -1 to indicate unknown */
+                       progress = GS_APP_PROGRESS_UNKNOWN;
                } else {
                        /* set progress only up to a max percentage, leaving the
                         * remaining for applying the update */
                        progress = (gfloat) downloaded / (gfloat) total_size *
                                   (gfloat) max_progress_for_update;
                }
-               gs_app_set_progress (app, (guint) progress);
+               gs_app_set_progress (app, progress);
 
                break;
        }
diff --git a/plugins/epiphany/gs-plugin-epiphany.c b/plugins/epiphany/gs-plugin-epiphany.c
index 9472b11b8..ecf72f754 100644
--- a/plugins/epiphany/gs-plugin-epiphany.c
+++ b/plugins/epiphany/gs-plugin-epiphany.c
@@ -549,7 +549,7 @@ list_installed_apps_thread_cb (GTask        *task,
                        gs_app_set_install_date (app, install_date);
                }
                if (desktop_size > 0 || icon_size > 0) {
-                       gs_app_set_size_installed (app, desktop_size + icon_size);
+                       gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, desktop_size + icon_size);
                }
                gs_app_list_add (list, app);
        }
diff --git a/plugins/fedora-pkgdb-collections/gs-plugin-fedora-pkgdb-collections.c 
b/plugins/fedora-pkgdb-collections/gs-plugin-fedora-pkgdb-collections.c
index ad51d4fb4..1a06d8832 100644
--- a/plugins/fedora-pkgdb-collections/gs-plugin-fedora-pkgdb-collections.c
+++ b/plugins/fedora-pkgdb-collections/gs-plugin-fedora-pkgdb-collections.c
@@ -403,8 +403,8 @@ _create_upgrade_from_info (GsPluginFedoraPkgdbCollections *self,
                            /* TRANSLATORS: this is a title for Fedora distro upgrades */
                            _("Upgrade for the latest features, performance and stability improvements."));
        gs_app_set_version (app, app_version);
-       gs_app_set_size_installed (app, GS_APP_SIZE_UNKNOWABLE);
-       gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE);
+       gs_app_set_size_installed (app, GS_SIZE_TYPE_UNKNOWABLE, 0);
+       gs_app_set_size_download (app, GS_SIZE_TYPE_UNKNOWABLE, 0);
        gs_app_set_license (app, GS_APP_QUALITY_LOWEST, "LicenseRef-free");
        gs_app_add_quirk (app, GS_APP_QUIRK_NEEDS_REBOOT);
        gs_app_add_quirk (app, GS_APP_QUIRK_PROVENANCE);
diff --git a/plugins/flatpak/gs-flatpak-utils.c b/plugins/flatpak/gs-flatpak-utils.c
index 746533f80..4e3adee89 100644
--- a/plugins/flatpak/gs-flatpak-utils.c
+++ b/plugins/flatpak/gs-flatpak-utils.c
@@ -84,7 +84,7 @@ gs_flatpak_app_new_from_remote (GsPlugin *plugin,
        gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE);
        gs_app_set_name (app, GS_APP_QUALITY_LOWEST,
                         flatpak_remote_get_name (xremote));
-       gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE);
+       gs_app_set_size_download (app, GS_SIZE_TYPE_UNKNOWABLE, 0);
        gs_app_set_management_plugin (app, plugin);
        gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_FLATPAK);
        gs_app_set_scope (app, is_user ? AS_COMPONENT_SCOPE_USER : AS_COMPONENT_SCOPE_SYSTEM);
@@ -213,7 +213,7 @@ gs_flatpak_app_new_from_repo_file (GFile *file,
        gs_app_set_state (app, GS_APP_STATE_AVAILABLE_LOCAL);
        gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE);
        gs_app_set_name (app, GS_APP_QUALITY_NORMAL, repo_title);
-       gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE);
+       gs_app_set_size_download (app, GS_SIZE_TYPE_UNKNOWABLE, 0);
        gs_flatpak_app_set_repo_url (app, repo_url);
        gs_app_set_origin_ui (app, repo_title);
        gs_app_set_origin_hostname (app, repo_url);
diff --git a/plugins/flatpak/gs-flatpak.c b/plugins/flatpak/gs-flatpak.c
index b874d6f05..715a3f92e 100644
--- a/plugins/flatpak/gs-flatpak.c
+++ b/plugins/flatpak/gs-flatpak.c
@@ -390,10 +390,9 @@ gs_flatpak_set_metadata (GsFlatpak *self, GsApp *app, FlatpakRef *xref)
        } else if (FLATPAK_IS_INSTALLED_REF (xref)) {
                installed_size = flatpak_installed_ref_get_installed_size (FLATPAK_INSTALLED_REF (xref));
        }
-       if (installed_size != 0)
-               gs_app_set_size_installed (app, installed_size);
-       if (download_size != 0)
-               gs_app_set_size_download (app, download_size);
+
+       gs_app_set_size_installed (app, (installed_size != 0) ? GS_SIZE_TYPE_VALID : GS_SIZE_TYPE_UNKNOWN, 
installed_size);
+       gs_app_set_size_download (app, (download_size != 0) ? GS_SIZE_TYPE_VALID : GS_SIZE_TYPE_UNKNOWN, 
download_size);
 }
 
 static GsApp *
@@ -1417,8 +1416,7 @@ gs_flatpak_set_metadata_installed (GsFlatpak *self,
 
        /* this is faster than flatpak_installation_fetch_remote_size_sync() */
        size_installed = flatpak_installed_ref_get_installed_size (xref);
-       if (size_installed != 0)
-               gs_app_set_size_installed (app, size_installed);
+       gs_app_set_size_installed (app, (size_installed != 0) ? GS_SIZE_TYPE_VALID : GS_SIZE_TYPE_UNKNOWN, 
size_installed);
 
        appdata_version = flatpak_installed_ref_get_appdata_version (xref);
        if (appdata_version != NULL)
@@ -1941,7 +1939,7 @@ gs_flatpak_add_updates (GsFlatpak *self,
                        gs_app_set_update_details_markup (main_app, NULL);
                        gs_app_set_update_version (main_app, NULL);
                        gs_app_set_update_urgency (main_app, AS_URGENCY_KIND_UNKNOWN);
-                       gs_app_set_size_download (main_app, 0);
+                       gs_app_set_size_download (main_app, GS_SIZE_TYPE_VALID, 0);
 
                /* needs download */
                } else {
@@ -1950,7 +1948,7 @@ gs_flatpak_add_updates (GsFlatpak *self,
                                 flatpak_ref_get_name (FLATPAK_REF (xref)));
 
                        /* get the current download size */
-                       if (gs_app_get_size_download (main_app) == 0) {
+                       if (gs_app_get_size_download (main_app, NULL) != GS_SIZE_TYPE_VALID) {
                                if (!flatpak_installation_fetch_remote_size_sync (installation,
                                                                                  gs_app_get_origin (app),
                                                                                  FLATPAK_REF (xref),
@@ -1961,9 +1959,9 @@ gs_flatpak_add_updates (GsFlatpak *self,
                                        g_warning ("failed to get download size: %s",
                                                   error_local->message);
                                        g_clear_error (&error_local);
-                                       gs_app_set_size_download (main_app, GS_APP_SIZE_UNKNOWABLE);
+                                       gs_app_set_size_download (main_app, GS_SIZE_TYPE_UNKNOWABLE, 0);
                                } else {
-                                       gs_app_set_size_download (main_app, download_size);
+                                       gs_app_set_size_download (main_app, GS_SIZE_TYPE_VALID, 
download_size);
                                }
                        }
                }
@@ -2741,8 +2739,9 @@ gs_plugin_refine_item_size (GsFlatpak *self,
                            GError **error)
 {
        gboolean ret;
-       guint64 download_size = GS_APP_SIZE_UNKNOWABLE;
-       guint64 installed_size = GS_APP_SIZE_UNKNOWABLE;
+       guint64 download_size = 0;
+       guint64 installed_size = 0;
+       GsSizeType size_type = GS_SIZE_TYPE_UNKNOWABLE;
 
        /* not applicable */
        if (gs_app_get_state (app) == GS_APP_STATE_AVAILABLE_LOCAL)
@@ -2753,11 +2752,11 @@ gs_plugin_refine_item_size (GsFlatpak *self,
        /* already set */
        if (gs_app_is_installed (app)) {
                /* only care about the installed size if the app is installed */
-               if (gs_app_get_size_installed (app) > 0)
+               if (gs_app_get_size_installed (app, NULL) == GS_SIZE_TYPE_VALID)
                        return TRUE;
        } else {
-               if (gs_app_get_size_installed (app) > 0 &&
-                   gs_app_get_size_download (app) > 0)
+               if (gs_app_get_size_installed (app, NULL) == GS_SIZE_TYPE_VALID &&
+                   gs_app_get_size_download (app, NULL) == GS_SIZE_TYPE_VALID)
                return TRUE;
        }
 
@@ -2804,8 +2803,7 @@ gs_plugin_refine_item_size (GsFlatpak *self,
                if (xref == NULL)
                        return FALSE;
                installed_size = flatpak_installed_ref_get_installed_size (xref);
-               if (installed_size == 0)
-                       installed_size = GS_APP_SIZE_UNKNOWABLE;
+               size_type = (installed_size > 0) ? GS_SIZE_TYPE_VALID : GS_SIZE_TYPE_UNKNOWABLE;
        } else {
                g_autoptr(FlatpakRef) xref = NULL;
                g_autoptr(GError) error_local = NULL;
@@ -2834,11 +2832,13 @@ gs_plugin_refine_item_size (GsFlatpak *self,
                        g_warning ("libflatpak failed to return application "
                                   "size: %s", error_local->message);
                        g_clear_error (&error_local);
+               } else {
+                       size_type = GS_SIZE_TYPE_VALID;
                }
        }
 
-       gs_app_set_size_installed (app, installed_size);
-       gs_app_set_size_download (app, download_size);
+       gs_app_set_size_installed (app, size_type, installed_size);
+       gs_app_set_size_download (app, size_type, download_size);
 
        return TRUE;
 }
@@ -3260,15 +3260,17 @@ gs_flatpak_refine_app_unlocked (GsFlatpak *self,
        if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE_DATA) != 0 &&
            gs_app_is_installed (app) &&
            gs_app_get_kind (app) != AS_COMPONENT_KIND_RUNTIME) {
-               if (gs_app_get_size_cache_data (app) == GS_APP_SIZE_UNKNOWABLE)
-                       gs_app_set_size_cache_data (app, gs_flatpak_get_app_directory_size (app, "cache", 
cancellable));
-               if (gs_app_get_size_user_data (app) == GS_APP_SIZE_UNKNOWABLE)
-                       gs_app_set_size_user_data (app, gs_flatpak_get_app_directory_size (app, "config", 
cancellable) +
-                                                       gs_flatpak_get_app_directory_size (app, "data", 
cancellable));
+               if (gs_app_get_size_cache_data (app, NULL) != GS_SIZE_TYPE_VALID)
+                       gs_app_set_size_cache_data (app, GS_SIZE_TYPE_VALID,
+                                                   gs_flatpak_get_app_directory_size (app, "cache", 
cancellable));
+               if (gs_app_get_size_user_data (app, NULL) != GS_SIZE_TYPE_VALID)
+                       gs_app_set_size_user_data (app, GS_SIZE_TYPE_VALID,
+                                                  gs_flatpak_get_app_directory_size (app, "config", 
cancellable) +
+                                                  gs_flatpak_get_app_directory_size (app, "data", 
cancellable));
 
                if (g_cancellable_is_cancelled (cancellable)) {
-                       gs_app_set_size_cache_data (app, GS_APP_SIZE_UNKNOWABLE);
-                       gs_app_set_size_user_data (app, GS_APP_SIZE_UNKNOWABLE);
+                       gs_app_set_size_cache_data (app, GS_SIZE_TYPE_UNKNOWABLE, 0);
+                       gs_app_set_size_user_data (app, GS_SIZE_TYPE_UNKNOWABLE, 0);
                }
        }
 
@@ -3530,7 +3532,7 @@ gs_flatpak_file_to_app_bundle (GsFlatpak *self,
 
        gs_flatpak_app_set_file_kind (app, GS_FLATPAK_APP_FILE_KIND_BUNDLE);
        gs_app_set_state (app, GS_APP_STATE_AVAILABLE_LOCAL);
-       gs_app_set_size_installed (app, flatpak_bundle_ref_get_installed_size (xref_bundle));
+       gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, flatpak_bundle_ref_get_installed_size 
(xref_bundle));
        gs_flatpak_set_metadata (self, app, FLATPAK_REF (xref_bundle));
        metadata = flatpak_bundle_ref_get_metadata (xref_bundle);
        if (!gs_flatpak_set_app_metadata (self, app,
@@ -3800,10 +3802,8 @@ gs_flatpak_file_to_app_ref (GsFlatpak *self,
        app = gs_flatpak_create_app (self, remote_name, FLATPAK_REF (remote_ref), NULL, interactive, 
cancellable);
 #else
        app = gs_flatpak_create_app (self, remote_name, parsed_ref, NULL, interactive, cancellable);
-       if (app_download_size != 0)
-               gs_app_set_size_download (app, app_download_size);
-       if (app_installed_size != 0)
-               gs_app_set_size_installed (app, app_installed_size);
+       gs_app_set_size_download (app, (app_download_size != 0) ? GS_SIZE_TYPE_VALID : GS_SIZE_TYPE_UNKNOWN, 
app_download_size);
+       gs_app_set_size_installed (app, (app_installed_size != 0) ? GS_SIZE_TYPE_VALID : 
GS_SIZE_TYPE_UNKNOWN, app_installed_size);
 #endif
 
        gs_app_add_quirk (app, GS_APP_QUIRK_HAS_SOURCE);
@@ -3831,11 +3831,9 @@ gs_flatpak_file_to_app_ref (GsFlatpak *self,
                        if (g_strcmp0 (runtime_ref, op_ref) == 0) {
                                guint64 installed_size = 0, download_size = 0;
                                download_size = flatpak_transaction_operation_get_download_size (op);
-                               if (download_size != 0)
-                                       gs_app_set_size_download (runtime, download_size);
+                               gs_app_set_size_download (runtime, (download_size != 0) ? GS_SIZE_TYPE_VALID 
: GS_SIZE_TYPE_UNKNOWN, download_size);
                                installed_size = flatpak_transaction_operation_get_installed_size (op);
-                               if (installed_size != 0)
-                                       gs_app_set_size_installed (runtime, installed_size);
+                               gs_app_set_size_installed (runtime, (installed_size != 0) ? 
GS_SIZE_TYPE_VALID : GS_SIZE_TYPE_UNKNOWN, installed_size);
                                break;
                        }
                }
diff --git a/plugins/fwupd/gs-fwupd-app.c b/plugins/fwupd/gs-fwupd-app.c
index c0faf0519..d275ae867 100644
--- a/plugins/fwupd/gs-fwupd-app.c
+++ b/plugins/fwupd/gs-fwupd-app.c
@@ -248,8 +248,8 @@ gs_fwupd_app_set_from_release (GsApp *app, FwupdRelease *rel)
                                fwupd_release_get_homepage (rel));
        }
        if (fwupd_release_get_size (rel) != 0) {
-               gs_app_set_size_installed (app, 0);
-               gs_app_set_size_download (app, fwupd_release_get_size (rel));
+               gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, 0);
+               gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, fwupd_release_get_size (rel));
        }
        if (fwupd_release_get_version (rel) != NULL)
                gs_app_set_update_version (app, fwupd_release_get_version (rel));
diff --git a/plugins/fwupd/gs-plugin-fwupd.c b/plugins/fwupd/gs-plugin-fwupd.c
index 66b76dfce..cac6a324a 100644
--- a/plugins/fwupd/gs-plugin-fwupd.c
+++ b/plugins/fwupd/gs-plugin-fwupd.c
@@ -538,7 +538,7 @@ gs_plugin_fwupd_new_app (GsPlugin *plugin, FwupdDevice *dev, GError **error)
 
        /* already downloaded, so overwrite */
        if (g_file_test (filename_cache, G_FILE_TEST_EXISTS))
-               gs_app_set_size_download (app, 0);
+               gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, 0);
 
        /* actually add the application */
        file = g_file_new_for_path (filename_cache);
@@ -1066,7 +1066,7 @@ gs_plugin_download_app (GsPlugin *plugin,
                if (!download_success)
                        return FALSE;
        }
-       gs_app_set_size_download (app, 0);
+       gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, 0);
        return TRUE;
 }
 
diff --git a/plugins/fwupd/gs-self-test.c b/plugins/fwupd/gs-self-test.c
index 6b56e6bd7..fe4bc5a2a 100644
--- a/plugins/fwupd/gs-self-test.c
+++ b/plugins/fwupd/gs-self-test.c
@@ -22,6 +22,8 @@ gs_plugins_fwupd_func (GsPluginLoader *plugin_loader)
        g_autoptr(GFile) file = NULL;
        g_autoptr(GsApp) app = NULL;
        g_autoptr(GsPluginJob) plugin_job = NULL;
+       GsSizeType size_download_type;
+       guint64 size_download_bytes;
 
        /* no fwupd, abort */
        if (!gs_plugin_loader_get_enabled (plugin_loader, "fwupd")) {
@@ -48,7 +50,9 @@ gs_plugins_fwupd_func (GsPluginLoader *plugin_loader)
        g_assert_cmpstr (gs_app_get_name (app), ==, "Chiron");
        g_assert_cmpstr (gs_app_get_summary (app), ==, "Single line synopsis");
        g_assert_cmpstr (gs_app_get_version (app), ==, "0.2");
-       g_assert_cmpint ((gint64) gs_app_get_size_download (app), ==, 32784);
+       size_download_type = gs_app_get_size_download (app, &size_download_bytes);
+       g_assert_cmpint (size_download_type, ==, GS_SIZE_TYPE_VALID);
+       g_assert_cmpuint (size_download_bytes, ==, 32784);
        g_assert_cmpstr (gs_app_get_description (app), ==,
                         "This is the first paragraph in the example "
                         "cab file.\n\nThis is the second paragraph.");
diff --git a/plugins/packagekit/gs-plugin-packagekit.c b/plugins/packagekit/gs-plugin-packagekit.c
index 863469b93..9f137ed73 100644
--- a/plugins/packagekit/gs-plugin-packagekit.c
+++ b/plugins/packagekit/gs-plugin-packagekit.c
@@ -844,8 +844,12 @@ gs_plugin_packagekit_add_updates (GsPlugin *plugin,
        for (guint i = 0; i < array->len; i++) {
                PkPackage *package = g_ptr_array_index (array, i);
                g_autoptr(GsApp) app = NULL;
+               guint64 size_download_bytes;
+
                app = gs_plugin_packagekit_build_update_app (plugin, package);
-               all_downloaded = all_downloaded && !gs_app_get_size_download (app);
+               all_downloaded = (all_downloaded &&
+                                 gs_app_get_size_download (app, &size_download_bytes) == GS_SIZE_TYPE_VALID 
&&
+                                 size_download_bytes == 0);
                if (all_downloaded && first_app == NULL)
                        first_app = g_object_ref (app);
                gs_app_list_add (list, app);
@@ -860,7 +864,7 @@ gs_plugin_packagekit_add_updates (GsPlugin *plugin,
                   way to verify the prepared-update file exists. */
                prepared_ids = pk_offline_get_prepared_ids (NULL);
                if (prepared_ids == NULL || prepared_ids[0] == NULL)
-                       gs_app_set_size_download (first_app, 1);
+                       gs_app_set_size_download (first_app, GS_SIZE_TYPE_VALID, 1);
        }
 
        return TRUE;
@@ -1196,10 +1200,10 @@ gs_plugin_refine_app_needs_details (GsPluginRefineFlags  flags,
            gs_app_get_url (app, AS_URL_KIND_HOMEPAGE) == NULL)
                return TRUE;
        if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE) > 0 &&
-           gs_app_get_size_installed (app) == 0)
+           gs_app_get_size_installed (app, NULL) != GS_SIZE_TYPE_VALID)
                return TRUE;
        if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE) > 0 &&
-           gs_app_get_size_download (app) == 0)
+           gs_app_get_size_download (app, NULL) != GS_SIZE_TYPE_VALID)
                return TRUE;
        return FALSE;
 }
@@ -2827,8 +2831,8 @@ gs_plugin_file_to_app (GsPlugin *plugin,
        gs_app_set_description (app, GS_APP_QUALITY_LOWEST,
                                pk_details_get_description (item));
        gs_app_set_url (app, AS_URL_KIND_HOMEPAGE, pk_details_get_url (item));
-       gs_app_set_size_installed (app, pk_details_get_size (item));
-       gs_app_set_size_download (app, 0);
+       gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, pk_details_get_size (item));
+       gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, 0);
        license_spdx = as_license_to_spdx_id (pk_details_get_license (item));
        gs_app_set_license (app, GS_APP_QUALITY_LOWEST, license_spdx);
        add_quirks_from_package_name (app, split[PK_PACKAGE_ID_NAME]);
@@ -3660,7 +3664,7 @@ _download_only (GsPluginPackagekit  *self,
        for (guint i = 0; i < gs_app_list_length (list); i++) {
                GsApp *app = gs_app_list_index (list, i);
                /* To indicate the app is already downloaded */
-               gs_app_set_size_download (app, 0);
+               gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, 0);
        }
        return TRUE;
 }
diff --git a/plugins/packagekit/packagekit-common.c b/plugins/packagekit/packagekit-common.c
index 2c11678ac..c4cbde895 100644
--- a/plugins/packagekit/packagekit-common.c
+++ b/plugins/packagekit/packagekit-common.c
@@ -394,10 +394,10 @@ gs_plugin_packagekit_set_metadata_from_package (GsPlugin *plugin,
        /* set unavailable state */
        if (pk_package_get_info (package) == PK_INFO_ENUM_UNAVAILABLE) {
                gs_app_set_state (app, GS_APP_STATE_UNAVAILABLE);
-               if (gs_app_get_size_installed (app) == 0)
-                       gs_app_set_size_installed (app, GS_APP_SIZE_UNKNOWABLE);
-               if (gs_app_get_size_download (app) == 0)
-                       gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE);
+               if (gs_app_get_size_installed (app, NULL) == GS_SIZE_TYPE_UNKNOWN)
+                       gs_app_set_size_installed (app, GS_SIZE_TYPE_UNKNOWABLE, 0);
+               if (gs_app_get_size_download (app, NULL) == GS_SIZE_TYPE_UNKNOWN)
+                       gs_app_set_size_download (app, GS_SIZE_TYPE_UNKNOWABLE, 0);
        }
        if (gs_app_get_version (app) == NULL)
                gs_app_set_version (app, pk_package_get_version (package));
@@ -551,20 +551,20 @@ gs_plugin_packagekit_refine_details_app (GsPlugin *plugin,
 
        /* the size is the size of all sources */
        if (gs_app_get_state (app) == GS_APP_STATE_UPDATABLE) {
-               if (install_size > 0 && gs_app_get_size_installed (app) == 0)
-                       gs_app_set_size_installed (app, install_size);
-               if (download_size > 0 && gs_app_get_size_download (app) == 0)
-                       gs_app_set_size_download (app, download_size);
+               if (install_size > 0 && gs_app_get_size_installed (app, NULL) != GS_SIZE_TYPE_VALID)
+                       gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, install_size);
+               if (download_size > 0 && gs_app_get_size_download (app, NULL) != GS_SIZE_TYPE_VALID)
+                       gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, download_size);
        } else if (gs_app_is_installed (app)) {
-               if (gs_app_get_size_download (app) == 0)
-                       gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE);
-               if (install_size > 0 && gs_app_get_size_installed (app) == 0)
-                       gs_app_set_size_installed (app, install_size);
+               if (gs_app_get_size_download (app, NULL) != GS_SIZE_TYPE_VALID)
+                       gs_app_set_size_download (app, GS_SIZE_TYPE_UNKNOWABLE, 0);
+               if (install_size > 0 && gs_app_get_size_installed (app, NULL) != GS_SIZE_TYPE_VALID)
+                       gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, install_size);
        } else {
-               if (gs_app_get_size_installed (app) == 0)
-                       gs_app_set_size_installed (app, install_size > 0 ? install_size : 
GS_APP_SIZE_UNKNOWABLE);
-               if (download_size > 0 && gs_app_get_size_download (app) == 0)
-                       gs_app_set_size_download (app, download_size);
+               if (install_size > 0 && gs_app_get_size_installed (app, NULL) != GS_SIZE_TYPE_VALID)
+                       gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, install_size);
+               if (download_size > 0 && gs_app_get_size_download (app, NULL) != GS_SIZE_TYPE_VALID)
+                       gs_app_set_size_download (app, GS_SIZE_TYPE_VALID, download_size);
        }
 }
 
diff --git a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
index fbada1919..30ba6a0b9 100644
--- a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
+++ b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
@@ -746,7 +746,7 @@ app_from_modified_pkg_variant (GsPlugin *plugin, GVariant *variant)
        gs_app_set_management_plugin (app, plugin);
        gs_app_add_quirk (app, GS_APP_QUIRK_NEEDS_REBOOT);
        app_set_rpm_ostree_packaging_format (app);
-       gs_app_set_size_download (app, 0);
+       gs_app_set_size_download (app, GS_SIZE_TYPE_UNKNOWN, 0);
        gs_app_set_kind (app, AS_COMPONENT_KIND_GENERIC);
        gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_PACKAGE);
        gs_app_set_scope (app, AS_COMPONENT_SCOPE_SYSTEM);
@@ -785,7 +785,7 @@ app_from_single_pkg_variant (GsPlugin *plugin, GVariant *variant, gboolean addit
        gs_app_set_management_plugin (app, plugin);
        gs_app_add_quirk (app, GS_APP_QUIRK_NEEDS_REBOOT);
        app_set_rpm_ostree_packaging_format (app);
-       gs_app_set_size_download (app, 0);
+       gs_app_set_size_download (app, GS_SIZE_TYPE_UNKNOWN, 0);
        gs_app_set_kind (app, AS_COMPONENT_KIND_GENERIC);
        gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_PACKAGE);
        gs_app_set_scope (app, AS_COMPONENT_SCOPE_SYSTEM);
@@ -2307,7 +2307,7 @@ gs_plugin_file_to_app (GsPlugin *plugin,
 
        /* set size */
        size = headerGetNumber (h, RPMTAG_SIZE);
-       gs_app_set_size_installed (app, size);
+       gs_app_set_size_installed (app, GS_SIZE_TYPE_VALID, size);
 
        /* set license */
        license = headerGetString (h, RPMTAG_LICENSE);
diff --git a/plugins/snap/gs-plugin-snap.c b/plugins/snap/gs-plugin-snap.c
index 8d5a9d911..1153b89a9 100644
--- a/plugins/snap/gs-plugin-snap.c
+++ b/plugins/snap/gs-plugin-snap.c
@@ -1429,9 +1429,12 @@ get_snaps_cb (GObject      *object,
                if (local_snap != NULL) {
                        SnapdApp *snap_app;
                        GDateTime *install_date;
+                       gint64 installed_size_bytes;
 
                        install_date = snapd_snap_get_install_date (local_snap);
-                       gs_app_set_size_installed (app, snapd_snap_get_installed_size (local_snap));
+                       installed_size_bytes = snapd_snap_get_installed_size (local_snap);
+
+                       gs_app_set_size_installed (app, (installed_size_bytes > 0) ? GS_SIZE_TYPE_VALID : 
GS_SIZE_TYPE_UNKNOWN, (guint64) installed_size_bytes);
                        gs_app_set_install_date (app, install_date != NULL ? g_date_time_to_unix 
(install_date) : GS_APP_INSTALL_DATE_UNKNOWN);
 
                        snap_app = get_primary_app (local_snap);
@@ -1445,9 +1448,13 @@ get_snaps_cb (GObject      *object,
 
                /* add information specific to store snaps */
                if (store_snap != NULL) {
+                       gint64 download_size_bytes;
+
                        gs_app_set_origin (app, self->store_name);
                        gs_app_set_origin_hostname (app, self->store_hostname);
-                       gs_app_set_size_download (app, snapd_snap_get_download_size (store_snap));
+
+                       download_size_bytes = snapd_snap_get_download_size (store_snap);
+                       gs_app_set_size_download (app, (download_size_bytes > 0) ? GS_SIZE_TYPE_VALID : 
GS_SIZE_TYPE_UNKNOWN, (guint64) download_size_bytes);
 
                        if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SCREENSHOTS && gs_app_get_screenshots 
(app)->len == 0)
                                refine_screenshots (app, store_snap);
@@ -1460,14 +1467,14 @@ get_snaps_cb (GObject      *object,
                if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE_DATA) != 0 &&
                    gs_app_is_installed (app) &&
                    gs_app_get_kind (app) != AS_COMPONENT_KIND_RUNTIME) {
-                       if (gs_app_get_size_cache_data (app) == GS_APP_SIZE_UNKNOWABLE)
-                               gs_app_set_size_cache_data (app, gs_snap_get_app_directory_size (snap_name, 
TRUE, cancellable));
-                       if (gs_app_get_size_user_data (app) == GS_APP_SIZE_UNKNOWABLE)
-                               gs_app_set_size_user_data (app, gs_snap_get_app_directory_size (snap_name, 
FALSE, cancellable));
+                       if (gs_app_get_size_cache_data (app, NULL) != GS_SIZE_TYPE_VALID)
+                               gs_app_set_size_cache_data (app, GS_SIZE_TYPE_VALID, 
gs_snap_get_app_directory_size (snap_name, TRUE, cancellable));
+                       if (gs_app_get_size_user_data (app, NULL) != GS_SIZE_TYPE_VALID)
+                               gs_app_set_size_user_data (app, GS_SIZE_TYPE_VALID, 
gs_snap_get_app_directory_size (snap_name, FALSE, cancellable));
 
                        if (g_cancellable_is_cancelled (cancellable)) {
-                               gs_app_set_size_cache_data (app, GS_APP_SIZE_UNKNOWABLE);
-                               gs_app_set_size_user_data (app, GS_APP_SIZE_UNKNOWABLE);
+                               gs_app_set_size_cache_data (app, GS_SIZE_TYPE_UNKNOWABLE, 0);
+                               gs_app_set_size_user_data (app, GS_SIZE_TYPE_UNKNOWABLE, 0);
                        }
                }
        }
diff --git a/plugins/snap/gs-self-test.c b/plugins/snap/gs-self-test.c
index 0cdb2cc4e..1f38b16e0 100644
--- a/plugins/snap/gs-self-test.c
+++ b/plugins/snap/gs-self-test.c
@@ -265,6 +265,8 @@ gs_plugins_snap_test_func (GsPluginLoader *plugin_loader)
        g_autoptr(GInputStream) icon_stream = NULL;
        g_autoptr(GdkPixbuf) pixbuf = NULL;
        g_autoptr(GError) error = NULL;
+       GsSizeType size_installed_type, size_download_type;
+       guint64 size_installed_bytes, size_download_bytes;
 
        /* no snap, abort */
        if (!gs_plugin_loader_get_enabled (plugin_loader, "snap")) {
@@ -304,8 +306,15 @@ gs_plugins_snap_test_func (GsPluginLoader *plugin_loader)
        g_assert_cmpint (as_image_get_height (image), ==, 768);
        icon = gs_app_get_icon_for_size (app, 64, 1, NULL);
        g_assert_null (icon);
-       g_assert_cmpint (gs_app_get_size_installed (app), ==, 0);
-       g_assert_cmpint (gs_app_get_size_download (app), ==, 500);
+
+       size_installed_type = gs_app_get_size_installed (app, &size_installed_bytes);
+       g_assert_cmpint (size_installed_type, ==, GS_SIZE_TYPE_VALID);
+       g_assert_cmpuint (size_installed_bytes, ==, 0);
+
+       size_download_type = gs_app_get_size_download (app, &size_download_bytes);
+       g_assert_cmpint (size_download_type, ==, GS_SIZE_TYPE_VALID);
+       g_assert_cmpuint (size_download_bytes, ==, 500);
+
        g_assert_cmpint (gs_app_get_install_date (app), ==, 0);
 
        g_object_unref (plugin_job);
@@ -318,7 +327,11 @@ gs_plugins_snap_test_func (GsPluginLoader *plugin_loader)
        g_assert_no_error (error);
        g_assert (ret);
        g_assert_cmpint (gs_app_get_state (app), ==, GS_APP_STATE_INSTALLED);
-       g_assert_cmpint (gs_app_get_size_installed (app), ==, 1000);
+
+       size_installed_type = gs_app_get_size_installed (app, &size_installed_bytes);
+       g_assert_cmpint (size_installed_type, ==, GS_SIZE_TYPE_VALID);
+       g_assert_cmpuint (size_installed_bytes, ==, 1000);
+
        g_assert_cmpint (gs_app_get_install_date (app), ==, g_date_time_to_unix (g_date_time_new_utc (2017, 
1, 2, 11, 23, 58)));
 
        icon = gs_app_get_icon_for_size (app, 128, 1, NULL);
diff --git a/src/gs-app-context-bar.c b/src/gs-app-context-bar.c
index 18f29b341..d7ea20449 100644
--- a/src/gs-app-context-bar.c
+++ b/src/gs-app-context-bar.c
@@ -121,21 +121,25 @@ update_storage_tile (GsAppContextBar *self)
        const gchar *title;
        g_autofree gchar *description = NULL;
        guint64 size_bytes;
+       GsSizeType size_type;
 
        g_assert (self->app != NULL);
 
        if (gs_app_is_installed (self->app)) {
-               guint64 size_installed = gs_app_get_size_installed (self->app);
-               guint64 size_user_data = gs_app_get_size_user_data (self->app);
-               guint64 size_cache_data = gs_app_get_size_cache_data (self->app);
+               guint64 size_installed, size_user_data, size_cache_data;
+               GsSizeType size_installed_type, size_user_data_type, size_cache_data_type;
                g_autofree gchar *size_user_data_str = NULL;
                g_autofree gchar *size_cache_data_str = NULL;
 
+               size_installed_type = gs_app_get_size_installed (self->app, &size_installed);
+               size_user_data_type = gs_app_get_size_user_data (self->app, &size_user_data);
+               size_cache_data_type = gs_app_get_size_cache_data (self->app, &size_cache_data);
+
                /* Treat `0` sizes as `unknown`, to not show `0 bytes` in the text. */
                if (size_user_data == 0)
-                       size_user_data = GS_APP_SIZE_UNKNOWABLE;
+                       size_user_data_type = GS_SIZE_TYPE_UNKNOWN;
                if (size_cache_data == 0)
-                       size_cache_data = GS_APP_SIZE_UNKNOWABLE;
+                       size_cache_data_type = GS_SIZE_TYPE_UNKNOWN;
 
                /* If any installed sizes are unknowable, ignore them. This
                 * means the stated installed size is a lower bound on the
@@ -144,9 +148,10 @@ update_storage_tile (GsAppContextBar *self)
                 * because uninstalling the app won’t reclaim that space unless
                 * it’s the last app using those dependencies. */
                size_bytes = size_installed;
-               if (size_user_data != GS_APP_SIZE_UNKNOWABLE)
+               size_type = size_installed_type;
+               if (size_user_data_type == GS_SIZE_TYPE_VALID)
                        size_bytes += size_user_data;
-               if (size_cache_data != GS_APP_SIZE_UNKNOWABLE)
+               if (size_cache_data_type == GS_SIZE_TYPE_VALID)
                        size_bytes += size_cache_data;
 
                size_user_data_str = g_format_size (size_user_data);
@@ -156,30 +161,35 @@ update_storage_tile (GsAppContextBar *self)
                 * This is displayed in a context tile, so the string should be short. */
                title = _("Installed Size");
 
-               if (size_user_data != GS_APP_SIZE_UNKNOWABLE && size_cache_data != GS_APP_SIZE_UNKNOWABLE)
+               if (size_user_data_type == GS_SIZE_TYPE_VALID && size_cache_data_type == GS_SIZE_TYPE_VALID)
                        description = g_strdup_printf (_("Includes %s of data and %s of cache"),
                                                       size_user_data_str, size_cache_data_str);
-               else if (size_user_data != GS_APP_SIZE_UNKNOWABLE)
+               else if (size_user_data_type == GS_SIZE_TYPE_VALID)
                        description = g_strdup_printf (_("Includes %s of data"),
                                                       size_user_data_str);
-               else if (size_cache_data != GS_APP_SIZE_UNKNOWABLE)
+               else if (size_cache_data_type == GS_SIZE_TYPE_VALID)
                        description = g_strdup_printf (_("Includes %s of cache"),
                                                       size_cache_data_str);
                else
                        description = g_strdup (_("Cache and data usage unknown"));
        } else {
-               guint64 app_download_size_bytes = gs_app_get_size_download (self->app);
-               guint64 dependencies_download_size_bytes = gs_app_get_size_download_dependencies (self->app);
+               guint64 app_download_size_bytes, dependencies_download_size_bytes;
+               GsSizeType app_download_size_type, dependencies_download_size_type;
+
+               app_download_size_type = gs_app_get_size_download (self->app, &app_download_size_bytes);
+               dependencies_download_size_type = gs_app_get_size_download_dependencies (self->app, 
&dependencies_download_size_bytes);
 
                size_bytes = app_download_size_bytes;
+               size_type = app_download_size_type;
 
                /* Translators: The download size of an application.
                 * This is displayed in a context tile, so the string should be short. */
                title = _("Download Size");
 
-               if (dependencies_download_size_bytes == 0) {
+               if (dependencies_download_size_type == GS_SIZE_TYPE_VALID &&
+                   dependencies_download_size_bytes == 0) {
                        description = g_strdup (_("Needs no additional system downloads"));
-               } else if (dependencies_download_size_bytes == GS_APP_SIZE_UNKNOWABLE) {
+               } else if (dependencies_download_size_type != GS_SIZE_TYPE_VALID) {
                        description = g_strdup (_("Needs an unknown size of additional system downloads"));
                } else {
                        g_autofree gchar *size = g_format_size (dependencies_download_size_bytes);
@@ -189,7 +199,7 @@ update_storage_tile (GsAppContextBar *self)
                }
        }
 
-       if (size_bytes == 0 || size_bytes == GS_APP_SIZE_UNKNOWABLE) {
+       if (size_type != GS_SIZE_TYPE_VALID) {
                /* Translators: This is displayed for the download size in an
                 * app’s context tile if the size is unknown. It should be short
                 * (at most a couple of characters wide). */
diff --git a/src/gs-app-row.c b/src/gs-app-row.c
index ec007d7d1..e9ec818af 100644
--- a/src/gs-app-row.c
+++ b/src/gs-app-row.c
@@ -276,7 +276,8 @@ gs_app_row_actually_refresh (GsAppRow *app_row)
        GString *str = NULL;
        const gchar *tmp;
        gboolean missing_search_result;
-       guint64 size = 0;
+       guint64 size_installed_bytes = 0;
+       GsSizeType size_installed_type = GS_SIZE_TYPE_UNKNOWN;
        g_autoptr(GIcon) icon = NULL;
 
        if (priv->app == NULL)
@@ -485,11 +486,11 @@ gs_app_row_actually_refresh (GsAppRow *app_row)
 
        /* show the right size */
        if (priv->show_installed_size) {
-               size = gs_app_get_size_installed (priv->app);
+               size_installed_type = gs_app_get_size_installed (priv->app, &size_installed_bytes);
        }
-       if (size != GS_APP_SIZE_UNKNOWABLE && size != 0) {
+       if (size_installed_type == GS_SIZE_TYPE_VALID && size_installed_bytes > 0) {
                g_autofree gchar *sizestr = NULL;
-               sizestr = g_format_size (size);
+               sizestr = g_format_size (size_installed_bytes);
                gtk_label_set_label (GTK_LABEL (priv->label_app_size), sizestr);
                gtk_widget_show (priv->label_app_size);
        } else {
diff --git a/src/gs-storage-context-dialog.c b/src/gs-storage-context-dialog.c
index c8df3db72..7ca2e29d9 100644
--- a/src/gs-storage-context-dialog.c
+++ b/src/gs-storage-context-dialog.c
@@ -73,6 +73,7 @@ typedef enum {
 static void
 add_size_row (GtkListBox   *list_box,
               GtkSizeGroup *lozenge_size_group,
+              GsSizeType    size_type,
               guint64       size_bytes,
               const gchar  *title,
               const gchar  *description)
@@ -81,7 +82,7 @@ add_size_row (GtkListBox   *list_box,
        g_autofree gchar *size_bytes_str = NULL;
        gboolean is_markup = FALSE;
 
-       if (size_bytes == GS_APP_SIZE_UNKNOWABLE)
+       if (size_type != GS_SIZE_TYPE_VALID)
                /* Translators: This is shown in a bubble if the storage
                 * size of an application is not known. The bubble is small,
                 * so the string should be as short as possible. */
@@ -105,6 +106,7 @@ add_size_row (GtkListBox   *list_box,
 static void
 update_sizes_list (GsStorageContextDialog *self)
 {
+       GsSizeType title_size_type;
        guint64 title_size_bytes;
        g_autofree gchar *title_size_bytes_str = NULL;
        const gchar *title;
@@ -118,66 +120,77 @@ update_sizes_list (GsStorageContextDialog *self)
                return;
 
        if (gs_app_is_installed (self->app)) {
-               guint64 size_installed;
-               guint64 size_user_data;
-               guint64 size_cache_data;
+               guint64 size_installed_bytes, size_user_data_bytes, size_cache_data_bytes;
+               GsSizeType size_installed_type, size_user_data_type, size_cache_data_type;
 
                /* Don’t list the size of the dependencies as that space likely
                 * won’t be reclaimed unless many other apps are removed. */
-               size_installed = gs_app_get_size_installed (self->app);
-               size_user_data = gs_app_get_size_user_data (self->app);
-               size_cache_data = gs_app_get_size_cache_data (self->app);
+               size_installed_type = gs_app_get_size_installed (self->app, &size_installed_bytes);
+               size_user_data_type = gs_app_get_size_user_data (self->app, &size_user_data_bytes);
+               size_cache_data_type = gs_app_get_size_cache_data (self->app, &size_cache_data_bytes);
 
                title = _("Installed Size");
-               title_size_bytes = size_installed;
+               title_size_bytes = size_installed_bytes;
+               title_size_type = size_installed_type;
 
-               add_size_row (self->sizes_list, self->lozenge_size_group, size_installed,
+               add_size_row (self->sizes_list, self->lozenge_size_group,
+                             size_installed_type, size_installed_bytes,
                              _("Application Data"),
                              _("Data needed for the application to run"));
 
-               if (size_user_data != GS_APP_SIZE_UNKNOWABLE) {
-                       add_size_row (self->sizes_list, self->lozenge_size_group, size_user_data,
+               if (size_user_data_type == GS_SIZE_TYPE_VALID) {
+                       add_size_row (self->sizes_list, self->lozenge_size_group,
+                                     size_user_data_type, size_user_data_bytes,
                                      _("User Data"),
                                      _("Data created by you in the application"));
-                       title_size_bytes += size_user_data;
+                       title_size_bytes += size_user_data_bytes;
                }
 
-               if (size_cache_data != GS_APP_SIZE_UNKNOWABLE) {
-                       add_size_row (self->sizes_list, self->lozenge_size_group, size_cache_data,
+               if (size_cache_data_type == GS_SIZE_TYPE_VALID) {
+                       add_size_row (self->sizes_list, self->lozenge_size_group,
+                                     size_cache_data_type, size_cache_data_bytes,
                                      _("Cache Data"),
                                      _("Temporary cached data"));
-                       title_size_bytes += size_cache_data;
+                       title_size_bytes += size_cache_data_bytes;
                        cache_row_added = TRUE;
                }
        } else {
-               guint64 size_download;
-               guint64 size_download_dependencies;
+               guint64 size_download_bytes, size_download_dependencies_bytes;
+               GsSizeType size_download_type, size_download_dependencies_type;
 
-               size_download = gs_app_get_size_download (self->app);
-               size_download_dependencies = gs_app_get_size_download_dependencies (self->app);
+               size_download_type = gs_app_get_size_download (self->app, &size_download_bytes);
+               size_download_dependencies_type = gs_app_get_size_download_dependencies (self->app, 
&size_download_dependencies_bytes);
 
                title = _("Download Size");
-               title_size_bytes = size_download;
+               title_size_bytes = size_download_bytes;
+               title_size_type = size_download_type;
 
-               add_size_row (self->sizes_list, self->lozenge_size_group, size_download,
+               add_size_row (self->sizes_list, self->lozenge_size_group,
+                             size_download_type, size_download_bytes,
                              gs_app_get_name (self->app),
                              _("The application itself"));
 
-               if (size_download_dependencies != GS_APP_SIZE_UNKNOWABLE) {
-                       add_size_row (self->sizes_list, self->lozenge_size_group, size_download_dependencies,
+               if (size_download_dependencies_type == GS_SIZE_TYPE_VALID) {
+                       add_size_row (self->sizes_list, self->lozenge_size_group,
+                                     size_download_dependencies_type, size_download_dependencies_bytes,
                                      _("Required Dependencies"),
                                      _("Shared system components required by this application"));
-                       title_size_bytes += size_download_dependencies;
+                       title_size_bytes += size_download_dependencies_bytes;
                }
 
                /* FIXME: Addons, Potential Additional Downloads */
        }
 
-       title_size_bytes_str = gs_utils_format_size (title_size_bytes, &is_markup);
+       if (title_size_type == GS_SIZE_TYPE_VALID)
+               title_size_bytes_str = gs_utils_format_size (title_size_bytes, &is_markup);
+       else
+               title_size_bytes_str = g_strdup (C_("Download size", "Unknown"));
+
        if (is_markup)
                gtk_label_set_markup (self->lozenge_content, title_size_bytes_str);
        else
                gtk_label_set_text (self->lozenge_content, title_size_bytes_str);
+
        gtk_label_set_text (self->title, title);
 
        /* Update the Manage Storage label. */
diff --git a/src/gs-update-monitor.c b/src/gs-update-monitor.c
index bf7dbf683..d3bf7adde 100644
--- a/src/gs-update-monitor.c
+++ b/src/gs-update-monitor.c
@@ -124,6 +124,7 @@ check_updates_kind (GsAppList *apps,
 
        for (ii = 0; ii < len && (!has_important || all_downloaded || !any_downloaded); ii++) {
                gboolean is_important;
+               guint64 size_download_bytes;
 
                app = gs_app_list_index (apps, ii);
 
@@ -132,7 +133,8 @@ check_updates_kind (GsAppList *apps,
 
                /* took from gs-updates-section.c: _all_offline_updates_downloaded();
                   the app is considered downloaded, when its download size is 0 */
-               if (gs_app_get_size_download (app)) {
+               if (gs_app_get_size_download (app, &size_download_bytes) != GS_SIZE_TYPE_VALID ||
+                   size_download_bytes != 0) {
                        all_downloaded = FALSE;
                } else {
                        any_downloaded = TRUE;
@@ -553,9 +555,12 @@ get_updates_finished_cb (GObject *object, GAsyncResult *res, gpointer data)
                        "security-timestamp", "x", &security_timestamp_old);
        for (guint i = 0; i < gs_app_list_length (apps); i++) {
                GsApp *app = gs_app_list_index (apps, i);
+               guint64 size_download_bytes;
+               GsSizeType size_download_type = gs_app_get_size_download (app, &size_download_bytes);
+
                if (gs_app_get_update_urgency (app) == AS_URGENCY_KIND_CRITICAL &&
-                   gs_app_get_size_download (app) > 0 &&
-                   gs_app_get_size_download (app) != GS_APP_SIZE_UNKNOWABLE) {
+                   size_download_type == GS_SIZE_TYPE_VALID &&
+                   size_download_bytes > 0) {
                        security_timestamp = (guint64) g_get_monotonic_time ();
                        break;
                }
diff --git a/src/gs-updates-section.c b/src/gs-updates-section.c
index 9e23fbdf6..ca39e6fab 100644
--- a/src/gs-updates-section.c
+++ b/src/gs-updates-section.c
@@ -288,11 +288,15 @@ _all_offline_updates_downloaded (GsUpdatesSection *self)
        /* use the download size to figure out what is downloaded and what not */
        for (guint i = 0; i < gs_app_list_length (self->list); i++) {
                GsApp *app = gs_app_list_index (self->list, i);
-               guint64 size = gs_app_get_size_download (app);
-               if (size != 0)
+               GsSizeType size_type;
+               guint64 size_bytes;
+
+               size_type = gs_app_get_size_download (app, &size_bytes);
+               if (size_type != GS_SIZE_TYPE_VALID || size_bytes != 0)
                        return FALSE;
-               size = gs_app_get_size_download_dependencies (app);
-               if (size != 0)
+
+               size_type = gs_app_get_size_download_dependencies (app, &size_bytes);
+               if (size_type != GS_SIZE_TYPE_VALID || size_bytes != 0)
                        return FALSE;
        }
 
diff --git a/src/gs-upgrade-banner.c b/src/gs-upgrade-banner.c
index 8d7fc6d1f..f0b340726 100644
--- a/src/gs-upgrade-banner.c
+++ b/src/gs-upgrade-banner.c
@@ -75,6 +75,8 @@ gs_upgrade_banner_refresh (GsUpgradeBanner *self)
        const gchar *uri, *summary, *version;
        g_autofree gchar *str = NULL;
        guint percentage;
+       GsSizeType size_download_type;
+       guint64 size_download_bytes;
 
        if (priv->app == NULL)
                return;
@@ -134,16 +136,18 @@ gs_upgrade_banner_refresh (GsUpgradeBanner *self)
                gtk_label_set_text (GTK_LABEL (priv->label_upgrades_summary), summary);
 
        uri = gs_app_get_url (priv->app, AS_URL_KIND_HOMEPAGE);
+       size_download_type = gs_app_get_size_download (priv->app, &size_download_bytes);
+
        if (uri != NULL) {
                g_autofree gchar *link = NULL;
                link = g_markup_printf_escaped ("<a href=\"%s\">%s</a>", uri, _("Learn about the new 
version"));
                gtk_label_set_markup (GTK_LABEL (priv->label_download_info), link);
                gtk_widget_show (priv->label_download_info);
-       } else if (gs_app_get_size_download (priv->app) != GS_APP_SIZE_UNKNOWABLE &&
-                  gs_app_get_size_download (priv->app) != 0) {
+       } else if (size_download_type == GS_SIZE_TYPE_VALID &&
+                  size_download_bytes > 0) {
                g_autofree gchar *tmp = NULL;
                g_clear_pointer (&str, g_free);
-               tmp = g_format_size (gs_app_get_size_download (priv->app));
+               tmp = g_format_size (size_download_bytes);
                /* Translators: the '%s' is replaced with the download size, forming text like "2 GB 
download" */
                str = g_strdup_printf ("%s download", tmp);
                gtk_label_set_text (GTK_LABEL (priv->label_download_info), str);
@@ -167,15 +171,15 @@ gs_upgrade_banner_refresh (GsUpgradeBanner *self)
                        gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progressbar),
                                                       (gdouble) percentage / 100.f);
                        g_clear_pointer (&str, g_free);
-                       if (gs_app_get_size_download (priv->app) != GS_APP_SIZE_UNKNOWABLE &&
-                           gs_app_get_size_download (priv->app) != 0) {
+
+                       if (size_download_type == GS_SIZE_TYPE_VALID) {
                                g_autofree gchar *tmp = NULL;
                                g_autofree gchar *downloaded_tmp = NULL;
                                guint64 downloaded;
 
-                               downloaded = gs_app_get_size_download (priv->app) * percentage / 100.0;
+                               downloaded = size_download_bytes * percentage / 100.0;
                                downloaded_tmp = g_format_size (downloaded);
-                               tmp = g_format_size (gs_app_get_size_download (priv->app));
+                               tmp = g_format_size (size_download_bytes);
                                /* Translators: the first '%s' is replaced with the downloaded size, the 
second '%s'
                                   with the total download size, forming text like "135 MB of 2 GB 
downloaded" */
                                str = g_strdup_printf (_("%s of %s downloaded"), downloaded_tmp, tmp);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]