Convert the views and data classes to Kotlin. https://redmine.stoutner.com/issues/744
[PrivacyBrowser.git] / app / src / main / java / com / stoutner / privacybrowser / adapters / PinnedMismatchPagerAdapter.kt
1 /*
2  * Copyright © 2021 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
5  *
6  * Privacy Browser is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacybrowser.adapters
21
22 import android.content.Context
23 import android.content.res.Configuration
24 import android.net.Uri
25 import android.text.SpannableStringBuilder
26 import android.text.Spanned
27 import android.text.style.ForegroundColorSpan
28 import android.view.LayoutInflater
29 import android.view.View
30 import android.view.ViewGroup
31 import android.widget.TextView
32
33 import androidx.viewpager.widget.PagerAdapter
34
35 import com.stoutner.privacybrowser.R
36 import com.stoutner.privacybrowser.activities.MainWebViewActivity
37 import com.stoutner.privacybrowser.views.NestedScrollWebView
38
39 import java.text.DateFormat
40 import java.util.Date
41
42 // This adapter uses a PagerAdapter instead of a FragmentPagerAdapter because dialogs fragments really don't like having a nested FragmentPagerAdapter inside of them.
43 class PinnedMismatchPagerAdapter(private val context: Context, private val layoutInflater: LayoutInflater, private val webViewFragmentId: Long) : PagerAdapter() {
44     override fun isViewFromObject(view: View, `object`: Any): Boolean {
45         // Check to see if the view and the object are the same.
46         return view === `object`
47     }
48
49     // Get the number of tabs.
50     override fun getCount(): Int {
51         // There are two tabs.
52         return 2
53     }
54
55     // Get the name of each tab.  Tab numbers start at 0.
56     override fun getPageTitle(tabNumber: Int): CharSequence {
57         return when (tabNumber) {
58             0 -> context.getString(R.string.current)
59             1 -> context.getString(R.string.pinned)
60             else -> ""
61         }
62     }
63
64     // Setup each tab.
65     override fun instantiateItem(container: ViewGroup, tabNumber: Int): Any {
66         // Get the current position of this WebView fragment.
67         val webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(webViewFragmentId)
68
69         // Get the WebView tab fragment.
70         val webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition)
71
72         // Get the WebView fragment view.
73         val webViewFragmentView = webViewTabFragment.requireView()
74
75         // Get a handle for the current WebView.
76         val nestedScrollWebView = webViewFragmentView.findViewById<NestedScrollWebView>(R.id.nestedscroll_webview)!!
77
78         // Inflate the scroll view for this tab.
79         val tabLayout = layoutInflater.inflate(R.layout.pinned_mismatch_tab_linearlayout, container, false) as ViewGroup
80
81         // Get handles for the views.
82         val domainNameTextView = tabLayout.findViewById<TextView>(R.id.domain_name)
83         val ipAddressesTextView = tabLayout.findViewById<TextView>(R.id.ip_addresses)
84         val issuedToCNameTextView = tabLayout.findViewById<TextView>(R.id.issued_to_cname)
85         val issuedToONameTextView = tabLayout.findViewById<TextView>(R.id.issued_to_oname)
86         val issuedToUNameTextView = tabLayout.findViewById<TextView>(R.id.issued_to_uname)
87         val issuedByCNameTextView = tabLayout.findViewById<TextView>(R.id.issued_by_cname)
88         val issuedByONameTextView = tabLayout.findViewById<TextView>(R.id.issued_by_oname)
89         val issuedByUNameTextView = tabLayout.findViewById<TextView>(R.id.issued_by_uname)
90         val startDateTextView = tabLayout.findViewById<TextView>(R.id.start_date)
91         val endDateTextView = tabLayout.findViewById<TextView>(R.id.end_date)
92
93         // Setup the labels.
94         val domainNameLabel = context.getString(R.string.domain_label) + "  "
95         val ipAddressesLabel = context.getString(R.string.ip_addresses) + "  "
96         val cNameLabel = context.getString(R.string.common_name) + "  "
97         val oNameLabel = context.getString(R.string.organization) + "  "
98         val uNameLabel = context.getString(R.string.organizational_unit) + "  "
99         val startDateLabel = context.getString(R.string.start_date) + "  "
100         val endDateLabel = context.getString(R.string.end_date) + "  "
101
102         // Convert the URL to a URI.
103         val currentUri = Uri.parse(nestedScrollWebView.url)
104
105         // Get the current host from the URI.
106         val domainName = currentUri.host
107
108         // Get the current website SSL certificate.
109         val sslCertificate = nestedScrollWebView.certificate
110
111         // Initialize the SSL certificate variables.
112         var currentSslIssuedToCName = ""
113         var currentSslIssuedToOName = ""
114         var currentSslIssuedToUName = ""
115         var currentSslIssuedByCName = ""
116         var currentSslIssuedByOName = ""
117         var currentSslIssuedByUName = ""
118         var currentSslStartDate: Date? = null
119         var currentSslEndDate: Date? = null
120
121         // Extract the individual pieces of information from the current website SSL certificate if it is not null.
122         if (sslCertificate != null) {
123             currentSslIssuedToCName = sslCertificate.issuedTo.cName
124             currentSslIssuedToOName = sslCertificate.issuedTo.oName
125             currentSslIssuedToUName = sslCertificate.issuedTo.uName
126             currentSslIssuedByCName = sslCertificate.issuedBy.cName
127             currentSslIssuedByOName = sslCertificate.issuedBy.oName
128             currentSslIssuedByUName = sslCertificate.issuedBy.uName
129             currentSslStartDate = sslCertificate.validNotBeforeDate
130             currentSslEndDate = sslCertificate.validNotAfterDate
131         }
132
133         // Get the pinned SSL certificate.
134         val pinnedSslCertificateArrayList = nestedScrollWebView.getPinnedSslCertificate()
135
136         // Extract the arrays from the array list.
137         val pinnedSslCertificateStringArray = pinnedSslCertificateArrayList[0] as Array<*>
138         val pinnedSslCertificateDateArray = pinnedSslCertificateArrayList[1] as Array<*>
139
140         // Setup the domain name spannable string builder.
141         val domainNameStringBuilder = SpannableStringBuilder(domainNameLabel + domainName)
142
143         // Initialize the spannable string builders.
144         val ipAddressesStringBuilder: SpannableStringBuilder
145         val issuedToCNameStringBuilder: SpannableStringBuilder
146         val issuedToONameStringBuilder: SpannableStringBuilder
147         val issuedToUNameStringBuilder: SpannableStringBuilder
148         val issuedByCNameStringBuilder: SpannableStringBuilder
149         val issuedByONameStringBuilder: SpannableStringBuilder
150         val issuedByUNameStringBuilder: SpannableStringBuilder
151         val startDateStringBuilder: SpannableStringBuilder
152         val endDateStringBuilder: SpannableStringBuilder
153
154         // Setup the spannable string builders for each tab.
155         if (tabNumber == 0) {  // Setup the current settings tab.
156             // Create the string builders.
157             ipAddressesStringBuilder = SpannableStringBuilder(ipAddressesLabel + nestedScrollWebView.currentIpAddresses)
158             issuedToCNameStringBuilder = SpannableStringBuilder(cNameLabel + currentSslIssuedToCName)
159             issuedToONameStringBuilder = SpannableStringBuilder(oNameLabel + currentSslIssuedToOName)
160             issuedToUNameStringBuilder = SpannableStringBuilder(uNameLabel + currentSslIssuedToUName)
161             issuedByCNameStringBuilder = SpannableStringBuilder(cNameLabel + currentSslIssuedByCName)
162             issuedByONameStringBuilder = SpannableStringBuilder(oNameLabel + currentSslIssuedByOName)
163             issuedByUNameStringBuilder = SpannableStringBuilder(uNameLabel + currentSslIssuedByUName)
164
165             // Set the dates if they aren't null.  Formatting a null date causes a crash.
166             startDateStringBuilder = if (currentSslStartDate == null) {
167                 SpannableStringBuilder(startDateLabel)
168             } else {
169                 SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslStartDate))
170             }
171
172             endDateStringBuilder = if (currentSslEndDate == null) {
173                 SpannableStringBuilder(endDateLabel)
174             } else {
175                 SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslEndDate))
176             }
177         } else {  // Setup the pinned settings tab.
178             // Create the string builders.
179             ipAddressesStringBuilder = SpannableStringBuilder(ipAddressesLabel + nestedScrollWebView.pinnedIpAddresses)
180             issuedToCNameStringBuilder = SpannableStringBuilder(cNameLabel + pinnedSslCertificateStringArray[0])
181             issuedToONameStringBuilder = SpannableStringBuilder(oNameLabel + pinnedSslCertificateStringArray[1])
182             issuedToUNameStringBuilder = SpannableStringBuilder(uNameLabel + pinnedSslCertificateStringArray[2])
183             issuedByCNameStringBuilder = SpannableStringBuilder(cNameLabel + pinnedSslCertificateStringArray[3])
184             issuedByONameStringBuilder = SpannableStringBuilder(oNameLabel + pinnedSslCertificateStringArray[4])
185             issuedByUNameStringBuilder = SpannableStringBuilder(uNameLabel + pinnedSslCertificateStringArray[5])
186
187             // Set the dates if they aren't null.  Formatting a null date causes a crash.
188             startDateStringBuilder = if (pinnedSslCertificateDateArray[0] == null) {
189                 SpannableStringBuilder(startDateLabel)
190             } else {
191                 SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(pinnedSslCertificateDateArray[0]))
192             }
193
194             endDateStringBuilder = if (pinnedSslCertificateDateArray[1] == null) {
195                 SpannableStringBuilder(endDateLabel)
196             } else {
197                 SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(pinnedSslCertificateDateArray[1]))
198             }
199         }
200
201         // Define the color spans.
202         val blueColorSpan: ForegroundColorSpan
203         val redColorSpan: ForegroundColorSpan
204
205         // Get the current theme status.
206         val currentThemeStatus = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
207
208         // Set the color spans according to the theme.  The deprecated `resources` must be used until the minimum API >= 23.
209         if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
210             @Suppress("DEPRECATION")
211             blueColorSpan = ForegroundColorSpan(context.resources.getColor(R.color.blue_700))
212             @Suppress("DEPRECATION")
213             redColorSpan = ForegroundColorSpan(context.resources.getColor(R.color.red_a700))
214         } else {
215             @Suppress("DEPRECATION")
216             blueColorSpan = ForegroundColorSpan(context.resources.getColor(R.color.violet_700))
217             @Suppress("DEPRECATION")
218             redColorSpan = ForegroundColorSpan(context.resources.getColor(R.color.red_900))
219         }
220
221         // Set the domain name to be blue.
222         domainNameStringBuilder.setSpan(blueColorSpan, domainNameLabel.length, domainNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
223
224         // Color coordinate the IP addresses if they are pinned.
225         if (!nestedScrollWebView.pinnedIpAddresses.equals("")) {
226             if (nestedScrollWebView.currentIpAddresses == nestedScrollWebView.pinnedIpAddresses) {
227                 ipAddressesStringBuilder.setSpan(blueColorSpan, ipAddressesLabel.length, ipAddressesStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
228             } else {
229                 ipAddressesStringBuilder.setSpan(redColorSpan, ipAddressesLabel.length, ipAddressesStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
230             }
231         }
232
233         // Color coordinate the SSL certificate fields if they are pinned.
234         if (nestedScrollWebView.hasPinnedSslCertificate()) {
235             if (currentSslIssuedToCName == pinnedSslCertificateStringArray[0]) {
236                 issuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, issuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
237             } else {
238                 issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, issuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
239             }
240
241             if (currentSslIssuedToOName == pinnedSslCertificateStringArray[1]) {
242                 issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, issuedToONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
243             } else {
244                 issuedToONameStringBuilder.setSpan(redColorSpan, oNameLabel.length, issuedToONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
245             }
246
247             if (currentSslIssuedToUName == pinnedSslCertificateStringArray[2]) {
248                 issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, issuedToUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
249             } else {
250                 issuedToUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length, issuedToUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
251             }
252
253             if (currentSslIssuedByCName == pinnedSslCertificateStringArray[3]) {
254                 issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, issuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
255             } else {
256                 issuedByCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, issuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
257             }
258
259             if (currentSslIssuedByOName == pinnedSslCertificateStringArray[4]) {
260                 issuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, issuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
261             } else {
262                 issuedByONameStringBuilder.setSpan(redColorSpan, oNameLabel.length, issuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
263             }
264
265             if (currentSslIssuedByUName == pinnedSslCertificateStringArray[5]) {
266                 issuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, issuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
267             } else {
268                 issuedByUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length, issuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
269             }
270
271             if (currentSslStartDate != null && currentSslStartDate == pinnedSslCertificateDateArray[0]) {
272                 startDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length, startDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
273             } else {
274                 startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length, startDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
275             }
276
277             if (currentSslEndDate != null && currentSslEndDate == pinnedSslCertificateDateArray[1]) {
278                 endDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length, endDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
279             } else {
280                 endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length, endDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
281             }
282         }
283
284         // Display the strings.
285         domainNameTextView.text = domainNameStringBuilder
286         ipAddressesTextView.text = ipAddressesStringBuilder
287         issuedToCNameTextView.text = issuedToCNameStringBuilder
288         issuedToONameTextView.text = issuedToONameStringBuilder
289         issuedToUNameTextView.text = issuedToUNameStringBuilder
290         issuedByCNameTextView.text = issuedByCNameStringBuilder
291         issuedByONameTextView.text = issuedByONameStringBuilder
292         issuedByUNameTextView.text = issuedByUNameStringBuilder
293         startDateTextView.text = startDateStringBuilder
294         endDateTextView.text = endDateStringBuilder
295
296         // Add the tab layout to the container.  This needs to be manually done for pager adapters.
297         container.addView(tabLayout)
298
299         // Return the tab layout.
300         return tabLayout
301     }
302 }