ソースを参照

Merge pull request #1965 from nextcloud/bugfix/noid/catch-npe-on-view-bindings

Catch NPEs on view bindings
Marcel Hibbe 3 年 前
コミット
cd2e9492f8

+ 10 - 4
app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt

@@ -701,10 +701,16 @@ class ChatController(args: Bundle) :
         showMicrophoneButton(true)
 
         binding.messageInputView.messageInput.doAfterTextChanged {
-            if (binding.messageInputView.messageInput.text.isEmpty()) {
-                showMicrophoneButton(true)
-            } else {
-                showMicrophoneButton(false)
+            try {
+                if (binding.messageInputView.messageInput.text.isEmpty()) {
+                    showMicrophoneButton(true)
+                } else {
+                    showMicrophoneButton(false)
+                }
+            } catch (npe: NullPointerException) {
+                // view binding can be null
+                // since this is called asynchronously and UI might have been destroyed in the meantime
+                Log.i(TAG, "UI destroyed - view binding already gone")
             }
         }
 

+ 14 - 8
app/src/main/java/com/nextcloud/talk/controllers/ProfileController.kt

@@ -93,7 +93,6 @@ import retrofit2.Response
 import java.io.File
 import java.io.FileOutputStream
 import java.io.IOException
-import java.util.ArrayList
 import java.util.LinkedList
 import java.util.Locale
 import javax.inject.Inject
@@ -341,13 +340,20 @@ class ProfileController : NewBaseController(R.layout.controller_profile) {
         if (activity == null) {
             return
         }
-        binding.emptyList.emptyListViewHeadline.text = headline
-        binding.emptyList.emptyListViewText.text = message
-        binding.emptyList.emptyListIcon.setImageResource(errorResource)
-        binding.emptyList.emptyListIcon.visibility = View.VISIBLE
-        binding.emptyList.emptyListViewText.visibility = View.VISIBLE
-        binding.userinfoList.visibility = View.GONE
-        binding.loadingContent.visibility = View.GONE
+
+        try {
+            binding.emptyList.emptyListViewHeadline.text = headline
+            binding.emptyList.emptyListViewText.text = message
+            binding.emptyList.emptyListIcon.setImageResource(errorResource)
+            binding.emptyList.emptyListIcon.visibility = View.VISIBLE
+            binding.emptyList.emptyListViewText.visibility = View.VISIBLE
+            binding.userinfoList.visibility = View.GONE
+            binding.loadingContent.visibility = View.GONE
+        } catch (npe: NullPointerException) {
+            // view binding can be null
+            // since this is called asynchronously and UI might have been destroyed in the meantime
+            Log.i(TAG, "UI destroyed - view binding already gone")
+        }
     }
 
     private fun createUserInfoDetails(userInfo: UserProfileData?): List<UserInfoDetailsItem> {

+ 24 - 15
app/src/main/java/com/nextcloud/talk/controllers/ServerSelectionController.kt

@@ -21,12 +21,14 @@
  */
 package com.nextcloud.talk.controllers
 
+import android.annotation.SuppressLint
 import android.content.Intent
 import android.content.pm.ActivityInfo
 import android.net.Uri
 import android.os.Bundle
 import android.security.KeyChain
 import android.text.TextUtils
+import android.util.Log
 import android.view.KeyEvent
 import android.view.View
 import android.view.inputmethod.EditorInfo
@@ -188,23 +190,30 @@ class ServerSelectionController :
         binding.certTextView.setOnClickListener { onCertClick() }
     }
 
+    @SuppressLint("LongLogTag")
     private fun checkServerAndProceed() {
         dispose()
-        var url: String = binding.serverEntryTextInputEditText.text.toString().trim { it <= ' ' }
-        binding.serverEntryTextInputEditText.isEnabled = false
-        showserverEntryProgressBar()
-        if (binding.helperTextView.visibility != View.INVISIBLE) {
-            binding.helperTextView.visibility = View.INVISIBLE
-            binding.certTextView.visibility = View.INVISIBLE
-        }
-        if (url.endsWith("/")) {
-            url = url.substring(0, url.length - 1)
-        }
-        val queryUrl = url + ApiUtils.getUrlPostfixForStatus()
-        if (UriUtils.hasHttpProtocollPrefixed(url)) {
-            checkServer(queryUrl, false)
-        } else {
-            checkServer("https://$queryUrl", true)
+        try {
+            var url: String = binding.serverEntryTextInputEditText.text.toString().trim { it <= ' ' }
+            binding.serverEntryTextInputEditText.isEnabled = false
+            showserverEntryProgressBar()
+            if (binding.helperTextView.visibility != View.INVISIBLE) {
+                binding.helperTextView.visibility = View.INVISIBLE
+                binding.certTextView.visibility = View.INVISIBLE
+            }
+            if (url.endsWith("/")) {
+                url = url.substring(0, url.length - 1)
+            }
+            val queryUrl = url + ApiUtils.getUrlPostfixForStatus()
+            if (UriUtils.hasHttpProtocollPrefixed(url)) {
+                checkServer(queryUrl, false)
+            } else {
+                checkServer("https://$queryUrl", true)
+            }
+        } catch (npe: NullPointerException) {
+            // view binding can be null
+            // since this is called asynchronously and UI might have been destroyed in the meantime
+            Log.i(TAG, "UI destroyed - view binding already gone")
         }
     }
 

+ 30 - 21
app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.kt

@@ -30,6 +30,7 @@ import android.os.Bundle
 import android.security.KeyChain
 import android.security.KeyChainException
 import android.text.TextUtils
+import android.util.Log
 import android.view.View
 import android.webkit.ClientCertRequest
 import android.webkit.CookieSyncManager
@@ -77,7 +78,6 @@ import java.net.URLDecoder
 import java.security.PrivateKey
 import java.security.cert.CertificateException
 import java.security.cert.X509Certificate
-import java.util.HashMap
 import java.util.Locale
 import javax.inject.Inject
 
@@ -183,32 +183,41 @@ class WebViewLoginController(args: Bundle? = null) : NewBaseController(
             }
 
             override fun onPageFinished(view: WebView, url: String) {
-                loginStep++
-                if (!basePageLoaded) {
-                    binding.progressBar.visibility = View.GONE
-                    binding.webview.visibility = View.VISIBLE
+                try {
+                    loginStep++
+                    if (!basePageLoaded) {
+                        binding.progressBar.visibility = View.GONE
+                        binding.webview.visibility = View.VISIBLE
 
-                    basePageLoaded = true
-                }
-                if (!TextUtils.isEmpty(username)) {
-                    if (loginStep == 1) {
-                        binding.webview.loadUrl("javascript: {document.getElementsByClassName('login')[0].click(); };")
-                    } else if (!automatedLoginAttempted) {
-                        automatedLoginAttempted = true
-                        if (TextUtils.isEmpty(password)) {
-                            binding.webview.loadUrl(
-                                "javascript:var justStore = document.getElementById('user').value = '$username';"
-                            )
-                        } else {
+                        basePageLoaded = true
+                    }
+                    if (!TextUtils.isEmpty(username)) {
+                        if (loginStep == 1) {
                             binding.webview.loadUrl(
-                                "javascript: {" +
-                                    "document.getElementById('user').value = '" + username + "';" +
-                                    "document.getElementById('password').value = '" + password + "';" +
-                                    "document.getElementById('submit').click(); };"
+                                "javascript: {document.getElementsByClassName('login')[0].click(); };"
                             )
+                        } else if (!automatedLoginAttempted) {
+                            automatedLoginAttempted = true
+                            if (TextUtils.isEmpty(password)) {
+                                binding.webview.loadUrl(
+                                    "javascript:var justStore = document.getElementById('user').value = '$username';"
+                                )
+                            } else {
+                                binding.webview.loadUrl(
+                                    "javascript: {" +
+                                        "document.getElementById('user').value = '" + username + "';" +
+                                        "document.getElementById('password').value = '" + password + "';" +
+                                        "document.getElementById('submit').click(); };"
+                                )
+                            }
                         }
                     }
+                } catch (npe: NullPointerException) {
+                    // view binding can be null
+                    // since this is called asynchronously and UI might have been destroyed in the meantime
+                    Log.i(TAG, "UI destroyed - view binding already gone")
                 }
+
                 super.onPageFinished(view, url)
             }