[url_launcher_linux] file resource URI support for canLaunch (#4491)

diff --git a/.ci/Dockerfile b/.ci/Dockerfile
index 60f82eb..e9e34fa 100644
--- a/.ci/Dockerfile
+++ b/.ci/Dockerfile
@@ -41,6 +41,7 @@
 RUN echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | sudo tee /etc/apt/sources.list.d/google-chrome.list
 RUN apt-get update && apt-get install -y --no-install-recommends google-chrome-stable
 
-# Make Chrome the default so http: has a handler for url_launcher tests.
+# Make Chrome the default so http: and file: has a handler for url_launcher tests.
 RUN apt-get install -y xdg-utils
 RUN xdg-settings set default-web-browser google-chrome.desktop
+RUN xdg-mime default google-chrome.desktop inode/directory
diff --git a/packages/url_launcher/url_launcher_linux/CHANGELOG.md b/packages/url_launcher/url_launcher_linux/CHANGELOG.md
index 7079a4e..a641f83 100644
--- a/packages/url_launcher/url_launcher_linux/CHANGELOG.md
+++ b/packages/url_launcher/url_launcher_linux/CHANGELOG.md
@@ -1,7 +1,8 @@
-## NEXT
+## 2.0.3
 
 * Updates code for new analysis options.
 * Fix minor memory leak in Linux url_launcher tests.
+* Fixes canLaunch detection for URIs addressing on local or network file systems
 
 ## 2.0.2
 
diff --git a/packages/url_launcher/url_launcher_linux/linux/test/url_launcher_linux_test.cc b/packages/url_launcher/url_launcher_linux/linux/test/url_launcher_linux_test.cc
index 775e2fa..2aa37aa 100644
--- a/packages/url_launcher/url_launcher_linux/linux/test/url_launcher_linux_test.cc
+++ b/packages/url_launcher/url_launcher_linux/linux/test/url_launcher_linux_test.cc
@@ -39,6 +39,31 @@
                              expected));
 }
 
+TEST(UrlLauncherPlugin, CanLaunchFileSuccess) {
+  g_autoptr(FlValue) args = fl_value_new_map();
+  fl_value_set_string_take(args, "url", fl_value_new_string("file:///"));
+  g_autoptr(FlMethodResponse) response = can_launch(nullptr, args);
+  ASSERT_NE(response, nullptr);
+  ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
+  g_autoptr(FlValue) expected = fl_value_new_bool(true);
+  EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result(
+                                 FL_METHOD_SUCCESS_RESPONSE(response)),
+                             expected));
+}
+
+TEST(UrlLauncherPlugin, CanLaunchFailureInvalidFileExtension) {
+  g_autoptr(FlValue) args = fl_value_new_map();
+  fl_value_set_string_take(
+      args, "url", fl_value_new_string("file:///madeup.madeupextension"));
+  g_autoptr(FlMethodResponse) response = can_launch(nullptr, args);
+  ASSERT_NE(response, nullptr);
+  ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
+  g_autoptr(FlValue) expected = fl_value_new_bool(false);
+  EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result(
+                                 FL_METHOD_SUCCESS_RESPONSE(response)),
+                             expected));
+}
+
 // For consistency with the established mobile implementations,
 // an invalid URL should return false, not an error.
 TEST(UrlLauncherPlugin, CanLaunchFailureInvalidUrl) {
diff --git a/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc b/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc
index d3f454e..d0f6168 100644
--- a/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc
+++ b/packages/url_launcher/url_launcher_linux/linux/url_launcher_plugin.cc
@@ -45,6 +45,16 @@
   return g_strdup(fl_value_get_string(url_value));
 }
 
+// Checks if URI has launchable file resource.
+static gboolean can_launch_uri_with_file_resource(FlUrlLauncherPlugin* self,
+                                                  const gchar* url) {
+  g_autoptr(GError) error = nullptr;
+  g_autoptr(GFile) file = g_file_new_for_uri(url);
+  g_autoptr(GAppInfo) app_info =
+      g_file_query_default_handler(file, NULL, &error);
+  return app_info != nullptr;
+}
+
 // Called to check if a URL can be launched.
 FlMethodResponse* can_launch(FlUrlLauncherPlugin* self, FlValue* args) {
   g_autoptr(GError) error = nullptr;
@@ -60,6 +70,10 @@
     g_autoptr(GAppInfo) app_info =
         g_app_info_get_default_for_uri_scheme(scheme);
     is_launchable = app_info != nullptr;
+
+    if (!is_launchable) {
+      is_launchable = can_launch_uri_with_file_resource(self, url);
+    }
   }
 
   g_autoptr(FlValue) result = fl_value_new_bool(is_launchable);
diff --git a/packages/url_launcher/url_launcher_linux/pubspec.yaml b/packages/url_launcher/url_launcher_linux/pubspec.yaml
index 9602168..a759779 100644
--- a/packages/url_launcher/url_launcher_linux/pubspec.yaml
+++ b/packages/url_launcher/url_launcher_linux/pubspec.yaml
@@ -2,7 +2,7 @@
 description: Linux implementation of the url_launcher plugin.
 repository: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_linux
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22
-version: 2.0.2
+version: 2.0.3
 
 environment:
   sdk: ">=2.12.0 <3.0.0"