Repository: coreproject-moe/CoreProject-Monorepo

Issue:
[ `Android` ] : Add `Caching`
https://stackoverflow.com/questions/34606785/how-to-enable-caching-in-webview-android
[ `Android` ] : Add `Hardware` `Acceleration`
https://stackoverflow.com/a/7528833


Discussion:

Resolving patch:
diff --git a/android/AnimeCore/main.py b/android/AnimeCore/main.py
new file mode 100644
--- /dev/null
+++ b/android/AnimeCore/main.py
@@ -0,0 +1,65 @@
+from kivy.app import App
+from kivy.core.window import Window
+from kivy.uix.boxlayout import BoxLayout
+from kivy.uix.button import Button
+from kivy.uix.label import Label
+from webview import WebView
+
+
+class BrowserApp(App):
+    def build(self):
+        self.browser = None
+        b1 = Button(
+            text="Tap for Figma (HomePage | Desktop)",
+            on_press=self.view_homepage_desktop,
+        )
+        b2 = Button(
+            text="Tap for Figma (HomePage | Laptop/Tablets)",
+            on_press=self.view_homepage_laptop_or_tablets,
+        )
+        b3 = Button(
+            text="Tap for Figma (HomePage | Mobile)",
+            on_press=self.view_homepage_mobile,
+        )
+
+        self.label = Label(text="")
+        box = BoxLayout(orientation="vertical")
+        box.add_widget(b1)
+        box.add_widget(b2)
+        box.add_widget(b3)
+        box.add_widget(self.label)
+        return box
+
+    def view_homepage_desktop(self, b):
+        self.browser = WebView(
+            "https://www.figma.com/proto/tNUUtsk20ltOrQICdEoggG/Core-Project?page-id=587%3A1423&node-id=690%3A686&viewport=552%2C423%2C0.21&scaling=contain&starting-point-node-id=690%3A686&show-proto-sidebar=1",
+            enable_javascript=True,
+            enable_zoom=False,
+        )
+
+    def view_homepage_laptop_or_tablets(self, b):
+        self.browser = WebView(
+            "https://www.figma.com/proto/tNUUtsk20ltOrQICdEoggG/Core-Project?page-id=587%3A1423&node-id=719%3A1262&viewport=552%2C423%2C0.21&scaling=contain&starting-point-node-id=719%3A1262&show-proto-sidebar=1",
+            enable_javascript=True,
+            enable_zoom=False,
+        )
+
+    def view_homepage_mobile(self, b):
+        self.browser = WebView(
+            "https://www.figma.com/proto/tNUUtsk20ltOrQICdEoggG/Core-Project?page-id=587%3A1423&node-id=719%3A2421&viewport=552%2C423%2C0.21&scaling=contain&starting-point-node-id=719%3A2421&show-proto-sidebar=1",
+            enable_javascript=True,
+            enable_zoom=False,
+        )
+
+    def on_pause(self):
+        if self.browser:
+            self.browser.pause()
+        return True
+
+    def on_resume(self):
+        if self.browser:
+            self.browser.resume()
+        pass
+
+
+BrowserApp().run()
diff --git a/android/AnimeCore/webview.py b/android/AnimeCore/webview.py
new file mode 100644
--- /dev/null
+++ b/android/AnimeCore/webview.py
@@ -0,0 +1,184 @@
+# Android **only** HTML viewer, always full screen.
+#
+# Back button or gesture has the usual browser behavior, except for the final
+# back event which returns the UI to the view before the browser was opened.
+#
+# Base Class:  https://kivy.org/doc/stable/api-kivy.uix.modalview.html
+#
+# Requires: android.permissions = INTERNET
+# Uses:     orientation = landscape, portrait, or all
+# Arguments:
+# url               : required string,  https://   file:// (content://  ?)
+# enable_javascript : optional boolean, defaults False
+# enable_downloads  : optional boolean, defaults False
+# enable_zoom       : optional boolean, defaults False
+#
+# Downloads are delivered to app storage see downloads_directory() below.
+#
+# Tested on api=27 and api=30
+#
+# Note:
+#    For api>27   http://  gives net::ERR_CLEARTEXT_NOT_PERMITTED
+#    This is Android implemented behavior.
+#
+# Source https://github.com/Android-for-Python/Webview-Example
+
+from android.runnable import run_on_ui_thread
+from jnius import PythonJavaClass, autoclass, cast, java_method
+from kivy.clock import Clock
+from kivy.uix.modalview import ModalView
+
+WebViewA = autoclass("android.webkit.WebView")
+WebViewClient = autoclass("android.webkit.WebViewClient")
+WebSettings = autoclass("android.webkit.WebSettings")
+LayoutParams = autoclass("android.view.ViewGroup$LayoutParams")
+LinearLayout = autoclass("android.widget.LinearLayout")
+KeyEvent = autoclass("android.view.KeyEvent")
+ViewGroup = autoclass("android.view.ViewGroup")
+DownloadManager = autoclass("android.app.DownloadManager")
+DownloadManagerRequest = autoclass("android.app.DownloadManager$Request")
+Uri = autoclass("android.net.Uri")
+Environment = autoclass("android.os.Environment")
+Context = autoclass("android.content.Context")
+PythonActivity = autoclass("org.kivy.android.PythonActivity")
+Color = autoclass("android.graphics.Color")
+View = autoclass("android.view.View")
+
+
+class DownloadListener(PythonJavaClass):
+    # https://stackoverflow.com/questions/10069050/download-file-inside-webview
+    __javacontext__ = "app"
+    __javainterfaces__ = ["android/webkit/DownloadListener"]
+
+    @java_method(
+        "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V"
+    )
+    def onDownloadStart(
+        self, url, userAgent, contentDisposition, mimetype, contentLength
+    ):
+        mActivity = PythonActivity.mActivity
+        context = mActivity.getApplicationContext()
+        visibility = DownloadManagerRequest.VISIBILITY_VISIBLE_NOTIFY_COMPLETED
+        dir_type = Environment.DIRECTORY_DOWNLOADS
+        uri = Uri.parse(url)
+        filepath = uri.getLastPathSegment()
+        request = DownloadManagerRequest(uri)
+        request.setNotificationVisibility(visibility)
+        request.setDestinationInExternalFilesDir(context, dir_type, filepath)
+        dm = cast(DownloadManager, mActivity.getSystemService(Context.DOWNLOAD_SERVICE))
+        dm.enqueue(request)
+
+
+class KeyListener(PythonJavaClass):
+    __javacontext__ = "app"
+    __javainterfaces__ = ["android/view/View$OnKeyListener"]
+
+    def __init__(self, listener):
+        super().__init__()
+        self.listener = listener
+
+    @java_method("(Landroid/view/View;ILandroid/view/KeyEvent;)Z")
+    def onKey(self, v, key_code, event):
+        if (
+            event.getAction() == KeyEvent.ACTION_DOWN
+            and key_code == KeyEvent.KEYCODE_BACK
+        ):
+            return self.listener()
+
+
+class WebView(ModalView):
+    # https://developer.android.com/reference/android/webkit/WebView
+
+    def __init__(
+        self,
+        url,
+        enable_javascript=False,
+        enable_downloads=False,
+        enable_zoom=False,
+        **kwargs
+    ):
+        super().__init__(**kwargs)
+        self.url = url
+        self.enable_javascript = enable_javascript
+        self.enable_downloads = enable_downloads
+        self.enable_zoom = enable_zoom
+        self.webview = None
+        self.enable_dismiss = True
+        self.open()
+
+    @run_on_ui_thread
+    def on_open(self):
+        mActivity = PythonActivity.mActivity
+        webview = WebViewA(mActivity)
+        webview.setWebViewClient(WebViewClient())
+        webview.getSettings().setJavaScriptEnabled(self.enable_javascript)
+        webview.getSettings().setBuiltInZoomControls(self.enable_zoom)
+        webview.getSettings().setDisplayZoomControls(False)
+        webview.getSettings().setAllowFileAccess(True)  # default False api>29
+        webview.getSettings().setCacheMode(
+            WebSettings.LOAD_CACHE_ELSE_NETWORK
+        )  # Enable Cache
+        webview.setLayerType(
+            View.LAYER_TYPE_HARDWARE, None
+        )  # Enable hardware acceleration
+        layout = LinearLayout(mActivity)
+        layout.setOrientation(LinearLayout.VERTICAL)
+        layout.addView(webview, self.width, self.height)
+        mActivity.addContentView(layout, LayoutParams(-1, -1))
+        webview.setOnKeyListener(KeyListener(self._back_pressed))
+        webview.setBackgroundColor(Color.BLACK)
+        if self.enable_downloads:
+            webview.setDownloadListener(DownloadListener())
+        self.webview = webview
+        self.layout = layout
+        try:
+            webview.loadUrl(self.url)
+        except Exception as e:
+            print("Webview.on_open(): " + str(e))
+            self.dismiss()
+
+    @run_on_ui_thread
+    def on_dismiss(self):
+        if self.enable_dismiss:
+            self.enable_dismiss = False
+            parent = cast(ViewGroup, self.layout.getParent())
+            if parent is not None:
+                parent.removeView(self.layout)
+            self.webview.clearHistory()
+            self.webview.clearCache(True)
+            self.webview.clearFormData()
+            self.webview.destroy()
+            self.layout = None
+            self.webview = None
+
+    @run_on_ui_thread
+    def on_size(self, instance, size):
+        if self.webview:
+            params = self.webview.getLayoutParams()
+            params.width = self.width
+            params.height = self.height
+            self.webview.setLayoutParams(params)
+
+    def pause(self):
+        if self.webview:
+            self.webview.pauseTimers()
+            self.webview.onPause()
+
+    def resume(self):
+        if self.webview:
+            self.webview.onResume()
+            self.webview.resumeTimers()
+
+    def downloads_directory(self):
+        # e.g. Android/data/org.test.myapp/files/Download
+        dir_type = Environment.DIRECTORY_DOWNLOADS
+        context = PythonActivity.mActivity.getApplicationContext()
+        directory = context.getExternalFilesDir(dir_type)
+        return str(directory.getPath())
+
+    def _back_pressed(self):
+        if self.webview.canGoBack():
+            self.webview.goBack()
+        else:
+            self.dismiss()
+        return True
diff --git a/backend/core/asgi.py b/backend/core/asgi.py
--- a/backend/core/asgi.py
+++ b/backend/core/asgi.py
@@ -1,5 +1,5 @@
 """
-ASGI config for dj project.
+ASGI config for core project.
 
 It exposes the ASGI callable as a module-level variable named ``application``.
 


Test patch: