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