1 package host.exp.exponent.experience
2 
3 import android.app.Activity
4 import android.os.Bundle
5 import android.text.method.LinkMovementMethod
6 import android.view.LayoutInflater
7 import android.view.View
8 import android.view.ViewGroup
9 import androidx.core.text.HtmlCompat
10 import androidx.fragment.app.Fragment
11 import host.exp.exponent.Constants
12 import host.exp.exponent.analytics.EXL
13 import host.exp.expoview.R
14 import host.exp.expoview.databinding.ErrorFragmentBinding
15 import java.util.regex.Pattern
16 
17 class ErrorFragment : Fragment() {
18   private var _binding: ErrorFragmentBinding? = null
19   private val binding get() = _binding!!
20 
onClickHomenull21   private fun onClickHome() {
22     val activity: Activity? = activity
23     if (activity is ErrorActivity) {
24       activity.onClickHome()
25     }
26   }
27 
onClickReloadnull28   private fun onClickReload() {
29     val activity: Activity? = activity
30     if (activity is ErrorActivity) {
31       activity.onClickReload()
32     }
33   }
34 
onClickViewErrorLognull35   private fun onClickViewErrorLog() {
36     val activity: Activity? = activity
37     if (activity is ErrorActivity) {
38       activity.onClickViewErrorLog()
39     }
40   }
41 
onCreateViewnull42   override fun onCreateView(
43     inflater: LayoutInflater,
44     container: ViewGroup?,
45     savedInstanceState: Bundle?
46   ): View {
47     _binding = ErrorFragmentBinding.inflate(inflater, container, false)
48 
49     binding.homeButton.setOnClickListener { onClickHome() }
50     binding.reloadButton.setOnClickListener { onClickReload() }
51     binding.viewErrorLog.setOnClickListener { onClickViewErrorLog() }
52 
53     val bundle = arguments
54     val isDebugModeEnabled = bundle!!.getBoolean(ErrorActivity.DEBUG_MODE_KEY)
55     val userErrorMessage = bundle.getString(ErrorActivity.USER_ERROR_MESSAGE_KEY)
56     val developerErrorMessage = bundle.getString(ErrorActivity.DEVELOPER_ERROR_MESSAGE_KEY)
57     val errorHeader = bundle.getString(ErrorActivity.ERROR_HEADER_KEY)
58 
59     var defaultErrorMessage = userErrorMessage
60 
61     val manifestUrl = bundle.getString(ErrorActivity.MANIFEST_URL_KEY)
62     val isHomeError = bundle.getBoolean(ErrorActivity.IS_HOME_KEY, false)
63     val isShellApp = manifestUrl != null && manifestUrl == Constants.INITIAL_URL
64 
65     val userFacingErrorMessage = if (isShellApp) {
66       getString(R.string.error_default_shell)
67     } else {
68       getString(R.string.error_default_client)
69     }
70     if (defaultErrorMessage.isNullOrEmpty()) {
71       defaultErrorMessage = if (isDebugModeEnabled) {
72         developerErrorMessage
73       } else {
74         userFacingErrorMessage
75       }
76     }
77 
78     if (isHomeError || manifestUrl == null || manifestUrl == Constants.INITIAL_URL) {
79       // Cannot go home in any of these cases
80       binding.homeButton.visibility = View.GONE
81     }
82 
83     // Some errors are in HTML format and contain hyperlinks with instructions / more information (
84     // eq. EXPERIENCE_SDK_VERSION_OUTDATED). We detect HTML tags and render that text as HTML.
85     val htmlPattern = Pattern.compile("<([A-Za-z][A-Za-z0-9]*)\\b[^>]*>(.*?)</\\1>")
86 
87     if (htmlPattern.matcher(defaultErrorMessage).find()) {
88       binding.errorMessage.text = HtmlCompat.fromHtml(defaultErrorMessage!!, HtmlCompat.FROM_HTML_MODE_COMPACT)
89     } else {
90       binding.errorMessage.text = defaultErrorMessage
91     }
92 
93     binding.errorMessage.movementMethod = LinkMovementMethod.getInstance()
94 
95     if (errorHeader != null) {
96       binding.errorHeader.text = errorHeader
97     }
98 
99     EXL.e(TAG, "ErrorActivity message: $defaultErrorMessage")
100 
101     return binding.root
102   }
103 
104   companion object {
105     private val TAG = ErrorFragment::class.java.simpleName
106   }
107 }
108