]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.kt
Switch the FragmentPagerAdapters to FragmentStateAdapters. https://redmine.stoutner...
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / dialogs / PinnedMismatchDialog.kt
1 /*
2  * Copyright 2017-2023 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.dialogs
21
22 import android.app.Dialog
23 import android.content.Context
24 import android.content.DialogInterface
25 import android.graphics.drawable.BitmapDrawable
26 import android.graphics.drawable.Drawable
27 import android.os.Bundle
28 import android.view.WindowManager
29
30 import androidx.appcompat.app.AlertDialog
31 import androidx.core.content.ContextCompat
32 import androidx.fragment.app.DialogFragment
33 import androidx.preference.PreferenceManager
34 import androidx.viewpager.widget.ViewPager
35
36 import com.google.android.material.tabs.TabLayout
37
38 import com.stoutner.privacybrowser.R
39 import com.stoutner.privacybrowser.activities.MainWebViewActivity
40 import com.stoutner.privacybrowser.adapters.PinnedMismatchPagerAdapter
41 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper
42 import com.stoutner.privacybrowser.views.NestedScrollWebView
43
44 // Define the class constants.
45 private const val WEBVIEW_FRAGMENT_ID = "webview_fragment_id"
46
47 class PinnedMismatchDialog : DialogFragment() {
48     companion object {
49         fun displayDialog(webViewFragmentId: Long): PinnedMismatchDialog {
50             // Create an arguments bundle.
51             val argumentsBundle = Bundle()
52
53             // Store the WebView fragment ID in the bundle.
54             argumentsBundle.putLong(WEBVIEW_FRAGMENT_ID, webViewFragmentId)
55
56             // Create a new instance of the pinned mismatch dialog.
57             val pinnedMismatchDialog = PinnedMismatchDialog()
58
59             // Add the arguments bundle to the new instance.
60             pinnedMismatchDialog.arguments = argumentsBundle
61
62             // Make it so.
63             return pinnedMismatchDialog
64         }
65     }
66
67     // Declare the class variables.
68     private lateinit var pinnedMismatchListener: PinnedMismatchListener
69
70     // The public interface is used to send information back to the parent activity.
71     interface PinnedMismatchListener {
72         fun pinnedErrorGoBack()
73     }
74
75     override fun onAttach(context: Context) {
76         // Run the default commands.
77         super.onAttach(context)
78
79         // Get a handle for the listener from the launching context.
80         pinnedMismatchListener = context as PinnedMismatchListener
81     }
82
83     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
84         // Get the WebView fragment ID.
85         val webViewFragmentId = requireArguments().getLong(WEBVIEW_FRAGMENT_ID)
86
87         // Get the current position of this WebView fragment.
88         val webViewPosition = MainWebViewActivity.webViewStateAdapter!!.getPositionForId(webViewFragmentId)
89
90         // Get the WebView tab fragment.
91         val webViewTabFragment = MainWebViewActivity.webViewStateAdapter!!.getPageFragment(webViewPosition)
92
93         // Get the fragment view.
94         val fragmentView = webViewTabFragment.requireView()
95
96         // Get a handle for the current WebView.
97         val nestedScrollWebView = fragmentView.findViewById<NestedScrollWebView>(R.id.nestedscroll_webview)!!
98
99         // Use an alert dialog builder to create the alert dialog.
100         val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
101
102         // Get the favorite icon.
103         val favoriteIconBitmap = nestedScrollWebView.getFavoriteIcon()
104
105         // Get the default favorite icon drawable.  `ContextCompat` must be used until API >= 21.
106         val defaultFavoriteIconDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.world)
107
108         // Cast the favorite icon drawable to a bitmap drawable.
109         val defaultFavoriteIconBitmapDrawable = (defaultFavoriteIconDrawable as BitmapDrawable)
110
111         // Store the default icon bitmap.
112         val defaultFavoriteIconBitmap = defaultFavoriteIconBitmapDrawable.bitmap
113
114         // Set the favorite icon as the dialog icon if it exists.
115         if (favoriteIconBitmap.sameAs(defaultFavoriteIconBitmap)) {  // There is no website favorite icon.
116             // Set the icon.
117             dialogBuilder.setIcon(R.drawable.ssl_certificate)
118         } else {  // There is a favorite icon.
119             // Create a drawable version of the favorite icon.
120             val favoriteIconDrawable: Drawable = BitmapDrawable(resources, favoriteIconBitmap)
121
122             // Set the icon.
123             dialogBuilder.setIcon(favoriteIconDrawable)
124         }
125
126         // Set the title.
127         dialogBuilder.setTitle(R.string.pinned_mismatch)
128
129         // Set the layout.
130         dialogBuilder.setView(R.layout.pinned_mismatch_linearlayout)
131
132         // Set the update button listener.
133         dialogBuilder.setNeutralButton(R.string.update) { _: DialogInterface?, _: Int ->
134             // Get the current SSL certificate.
135             val currentSslCertificate = nestedScrollWebView.certificate!!
136
137             // Get the dates from the certificate.
138             val currentSslStartDate = currentSslCertificate.validNotBeforeDate
139             val currentSslEndDate = currentSslCertificate.validNotAfterDate
140
141             // Convert the dates into longs.  If the date is null, a long value of `0` will be stored in the domains database entry.
142             val currentSslStartDateLong: Long = currentSslStartDate?.time ?: 0
143             val currentSslEndDateLong: Long = currentSslEndDate?.time ?: 0
144
145             // Initialize the database handler.
146             val domainsDatabaseHelper = DomainsDatabaseHelper(requireContext())
147
148             // Update the SSL certificate if it is pinned.
149             if (nestedScrollWebView.hasPinnedSslCertificate()) {
150                 // Update the pinned SSL certificate in the domain database.
151                 domainsDatabaseHelper.updatePinnedSslCertificate(nestedScrollWebView.domainSettingsDatabaseId, currentSslCertificate.issuedTo.cName, currentSslCertificate.issuedTo.oName,
152                         currentSslCertificate.issuedTo.uName, currentSslCertificate.issuedBy.cName, currentSslCertificate.issuedBy.oName, currentSslCertificate.issuedBy.uName, currentSslStartDateLong,
153                         currentSslEndDateLong)
154
155                 // Update the pinned SSL certificate in the nested scroll WebView.
156                 nestedScrollWebView.setPinnedSslCertificate(currentSslCertificate.issuedTo.cName, currentSslCertificate.issuedTo.oName, currentSslCertificate.issuedTo.uName,
157                         currentSslCertificate.issuedBy.cName, currentSslCertificate.issuedBy.oName, currentSslCertificate.issuedBy.uName, currentSslStartDate, currentSslEndDate)
158             }
159
160             // Update the IP addresses if they are pinned.
161             if (nestedScrollWebView.pinnedIpAddresses != "") {
162                 // Update the pinned IP addresses in the domain database.
163                 domainsDatabaseHelper.updatePinnedIpAddresses(nestedScrollWebView.domainSettingsDatabaseId, nestedScrollWebView. currentIpAddresses)
164
165                 // Update the pinned IP addresses in the nested scroll WebView.
166                 nestedScrollWebView.pinnedIpAddresses = nestedScrollWebView.currentIpAddresses
167             }
168         }
169
170         // Set the back button listener.
171         dialogBuilder.setNegativeButton(R.string.back) { _: DialogInterface?, _: Int ->
172             if (nestedScrollWebView.canGoBack()) {  // There is a back page in the history.
173                 // Invoke the navigate history listener in the calling activity.  These commands cannot be run here because they need access to `applyDomainSettings()`.
174                 pinnedMismatchListener.pinnedErrorGoBack()
175             } else {  // There are no pages to go back to.
176                 // Load a blank page
177                 nestedScrollWebView.loadUrl("")
178             }
179         }
180
181         // Set the proceed button listener.
182         dialogBuilder.setPositiveButton(R.string.proceed) { _: DialogInterface?, _: Int ->
183             // Do not check the pinned information for this domain again until the domain changes.
184             nestedScrollWebView.ignorePinnedDomainInformation = true
185         }
186
187         // Create an alert dialog from the alert dialog builder.
188         val alertDialog = dialogBuilder.create()
189
190         // Get a handle for the shared preferences.
191         val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
192
193         // Get the screenshot preference.
194         val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
195
196         // Disable screenshots if not allowed.
197         if (!allowScreenshots) {
198             // Disable screenshots.
199             alertDialog.window!!.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
200         }
201
202         // The alert dialog must be shown before items in the layout can be modified.
203         alertDialog.show()
204
205         //  Get handles for the views.
206         val viewPager = alertDialog.findViewById<ViewPager>(R.id.pinned_ssl_certificate_mismatch_viewpager)!!
207         val tabLayout = alertDialog.findViewById<TabLayout>(R.id.pinned_ssl_certificate_mismatch_tablayout)!!
208
209         // Initialize the pinned mismatch pager adapter.
210         val pinnedMismatchPagerAdapter = PinnedMismatchPagerAdapter(requireContext(), layoutInflater, webViewFragmentId)
211
212         // Set the view pager adapter.
213         viewPager.adapter = pinnedMismatchPagerAdapter
214
215         // Connect the tab layout to the view pager.
216         tabLayout.setupWithViewPager(viewPager)
217
218         // Return the alert dialog.
219         return alertDialog
220     }
221 }