From 135083ed1d09126bde43ded4befc444040a13ed8 Mon Sep 17 00:00:00 2001 From: Soren Stoutner <soren@stoutner.com> Date: Mon, 16 Aug 2021 22:38:29 -0700 Subject: [PATCH] Request the phone permission if needed. --- app/src/main/AndroidManifest.xml | 2 +- .../privacycell/activities/PrivacyCell.kt | 149 ++++++++++++------ .../dialogs/PhonePermissionDialog.kt | 71 +++++++++ .../main/res/drawable/phone_permission.xml | 12 ++ ...layout.xml => privacy_cell_scrollview.xml} | 8 +- app/src/main/res/values-night/colors.xml | 38 +++++ app/src/main/res/values-night/themes.xml | 7 +- app/src/main/res/values/colors.xml | 9 ++ app/src/main/res/values/strings.xml | 6 + app/src/main/res/values/themes.xml | 7 +- 10 files changed, 254 insertions(+), 55 deletions(-) create mode 100644 app/src/main/java/com/stoutner/privacycell/dialogs/PhonePermissionDialog.kt create mode 100644 app/src/main/res/drawable/phone_permission.xml rename app/src/main/res/layout/{privacy_cell_linearlayout.xml => privacy_cell_scrollview.xml} (92%) create mode 100644 app/src/main/res/values-night/colors.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d807db0..8922ae3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -30,7 +30,7 @@ <!-- Support Chromebooks that don't have a touch screen. --> <uses-feature android:name="android.hardware.touchscreen" android:required="false" /> - <!-- App data is automatically backed up to Google cloud servers unless `android:allowBackup="false"` and `android:fullBackupContent="false"` is set. TODO round icon and theme name. --> + <!-- App data is automatically backed up to Google cloud servers unless `android:allowBackup="false"` and `android:fullBackupContent="false"` is set. --> <application android:label="@string/privacy_cell" android:icon="@mipmap/privacy_cell" diff --git a/app/src/main/java/com/stoutner/privacycell/activities/PrivacyCell.kt b/app/src/main/java/com/stoutner/privacycell/activities/PrivacyCell.kt index b457018..c8c7712 100644 --- a/app/src/main/java/com/stoutner/privacycell/activities/PrivacyCell.kt +++ b/app/src/main/java/com/stoutner/privacycell/activities/PrivacyCell.kt @@ -24,6 +24,7 @@ import android.content.Context import android.content.pm.PackageManager import android.os.Bundle import android.telephony.PhoneStateListener +import android.telephony.ServiceState import android.telephony.TelephonyDisplayInfo import android.telephony.TelephonyManager import android.widget.ImageView @@ -32,58 +33,96 @@ import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.content.res.AppCompatResources import androidx.core.app.ActivityCompat +import androidx.fragment.app.DialogFragment import com.stoutner.privacycell.R +import com.stoutner.privacycell.dialogs.PhonePermissionDialog + +class PrivacyCell : AppCompatActivity(), PhonePermissionDialog.StoragePermissionDialogListener { + // Declare the class variables. + private lateinit var context: Context + private lateinit var telephonyManager: TelephonyManager + + // Declare the views. + lateinit var secureFromStingrayImageView: ImageView + lateinit var secureFromStingrayTextView: TextView + lateinit var voiceNetworkTextView: TextView + lateinit var voiceNetworkDetailsTextView: TextView + lateinit var dataNetworkTextView: TextView + lateinit var dataNetworkDetailsTextView: TextView + lateinit var additionalNetworkInfoTextView: TextView + lateinit var additionalNetworkInfoDetailsTextView: TextView -class PrivacyCell : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { // Run the default commands. super.onCreate(savedInstanceState) // Set the content view. - setContentView(R.layout.privacy_cell_linearlayout) + setContentView(R.layout.privacy_cell_scrollview) // Get handles for the views. - val secureFromStingrayImageView = findViewById<ImageView>(R.id.secure_from_stingray_imageview) - val secureFromStingrayTextView = findViewById<TextView>(R.id.secure_from_stingray_textview) - val voiceNetworkTextView = findViewById<TextView>(R.id.voice_network) - val voiceNetworkDetailsTextView = findViewById<TextView>(R.id.voice_network_details) - val dataNetworkTextView = findViewById<TextView>(R.id.data_network) - val dataNetworkDetailsTextView = findViewById<TextView>(R.id.data_network_details) - val additionalNetworkInfoTextView = findViewById<TextView>(R.id.additional_network_info) - val additionalNetworkInfoDetailsTextView = findViewById<TextView>(R.id.additional_network_info_details) - - // TODO. - if (ActivityCompat.checkSelfPermission( - this, - Manifest.permission.READ_PHONE_STATE - ) != PackageManager.PERMISSION_GRANTED - ) { - // TODO: Consider calling - // ActivityCompat#requestPermissions - // here to request the missing permissions, and then overriding - // public void onRequestPermissionsResult(int requestCode, String[] permissions, - // int[] grantResults) - // to handle the case where the user grants the permission. See the documentation - // for ActivityCompat#requestPermissions for more details. - return + secureFromStingrayImageView = findViewById(R.id.secure_from_stingray_imageview) + secureFromStingrayTextView = findViewById(R.id.secure_from_stingray_textview) + voiceNetworkTextView = findViewById(R.id.voice_network) + voiceNetworkDetailsTextView = findViewById(R.id.voice_network_details) + dataNetworkTextView = findViewById(R.id.data_network) + dataNetworkDetailsTextView = findViewById(R.id.data_network_details) + additionalNetworkInfoTextView = findViewById(R.id.additional_network_info) + additionalNetworkInfoDetailsTextView = findViewById(R.id.additional_network_info_details) + + // Get handles for the context and the telephony manager. + context = this + telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager + + // Check to see if the read phone state permission has been granted. + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { // The storage permission has been granted. + // Populate Privacy Cell. + populatePrivacyCell() + } else { // The phone permission has not been granted. + // Check if the user has previously denied the storage permission. + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_PHONE_STATE)) { // Show a dialog explaining the request first. + // Check to see if a phone permission dialog is already displayed. This happens if the app is restarted when the dialog is shown. + if (supportFragmentManager.findFragmentByTag(getString(R.string.phone_permission)) == null) { // No dialog is currently shown. + // Instantiate the phone permission dialog fragment. + val phonePermissionDialogFragment: DialogFragment = PhonePermissionDialog() + + // Show the phone permission alert dialog. The permission will be requested when the dialog is closed. + phonePermissionDialogFragment.show(supportFragmentManager, getString(R.string.phone_permission)) + } + } else { // Show the permission request directly. + // Request the read phone state permission. There is only one permission request in the app, so it has a request code of 0. + ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0) + } } + } - // Get a handle for the the telephone Manager and the context. - val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager - val context: Context = this - - // Get the voice network type. - val voiceNetworkType = getNetworkType(telephonyManager.voiceNetworkType) + override fun onCloseStoragePermissionDialog() { + // Request the read phone state permission. There is only one permission request in the app, so it has a request code of 0. + ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0) + } - // Populate the voice network text views. - voiceNetworkTextView.text = getString(R.string.voice_network, voiceNetworkType[0]) - voiceNetworkDetailsTextView.text = voiceNetworkType[1] + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { + // Run the default commands. + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + + //Only process the results if they exist (this method is triggered when a dialog is presented the first time for an app, but no grant results are included). + if (grantResults.isNotEmpty()) { + // Check to see if the read phone state permission was granted. If the dialog was canceled the grant results will be empty. + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // The read phone state permission was granted. + // Populate Privacy Cell. + populatePrivacyCell() + } else { // The read phone state permission was denied. + // Display the phone permission text on the main activity. + secureFromStingrayTextView.text = getString(R.string.phone_permission_text) + } + } + } + private fun populatePrivacyCell() { // Listen to changes in the cell network state. telephonyManager.listen(object : PhoneStateListener() { - override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {// Populate the secure from stingray text view. <https://source.android.com/devices/tech/connect/acts-5g-testing> - // Populate the stingray security information. + override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) { + // Populate the stingray security information. <https://source.android.com/devices/tech/connect/acts-5g-testing> if (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_NR) { // This is a secure 5G NR SA network. // Populate the image view. secureFromStingrayImageView.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.secure_5g_nr_sa)) @@ -92,7 +131,7 @@ class PrivacyCell : AppCompatActivity() { secureFromStingrayTextView.text = getString(R.string.secure_from_stingray) // Set the text color. - secureFromStingrayTextView.setTextColor(getColor(R.color.blue_700)) + secureFromStingrayTextView.setTextColor(getColor(R.color.blue_text)) } else { // This is not a secure 5G NR SA network. // Populate the image view. secureFromStingrayImageView.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.not_secure)) @@ -101,26 +140,38 @@ class PrivacyCell : AppCompatActivity() { secureFromStingrayTextView.text = getString(R.string.not_secure_from_stingray) // Set the text color. - secureFromStingrayTextView.setTextColor(getColor(R.color.red_700)) + secureFromStingrayTextView.setTextColor(getColor(R.color.red_text)) - // Get the strings that correspond to the network information. - val dataNetworkType = getNetworkType(telephonyDisplayInfo.networkType) - val additionalNetworkInfo = getAdditionalNetworkInfo(telephonyDisplayInfo.overrideNetworkType) + // Get the strings that correspond to the network information. + val dataNetworkType = getNetworkType(telephonyDisplayInfo.networkType) + val additionalNetworkInfo = getAdditionalNetworkInfo(telephonyDisplayInfo.overrideNetworkType) - // Populate the data network text views. - dataNetworkTextView.text = getString(R.string.data_network, dataNetworkType[0]) - dataNetworkDetailsTextView.text = dataNetworkType[1] - additionalNetworkInfoTextView.text = getString(R.string.additional_network_info, additionalNetworkInfo[0]) - additionalNetworkInfoDetailsTextView.text = additionalNetworkInfo[1] + // Populate the data network text views. + dataNetworkTextView.text = getString(R.string.data_network, dataNetworkType[0]) + dataNetworkDetailsTextView.text = dataNetworkType[1] + additionalNetworkInfoTextView.text = getString(R.string.additional_network_info, additionalNetworkInfo[0]) + additionalNetworkInfoDetailsTextView.text = additionalNetworkInfo[1] } } - }, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) + + override fun onServiceStateChanged(serviceState: ServiceState) { + // Get the network registration info for the voice network, which is the second of the three entries (the first appears to be Wi-Fi and the third appears to be the cell data network). + val networkRegistrationInfo = serviceState.networkRegistrationInfoList[1] + + // Get the voice network type. + val voiceNetworkType = getNetworkType(networkRegistrationInfo.accessNetworkTechnology) + + // Populate the voice network text views. + voiceNetworkTextView.text = getString(R.string.voice_network, voiceNetworkType[0]) + voiceNetworkDetailsTextView.text = voiceNetworkType[1] + } + }, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED or PhoneStateListener.LISTEN_SERVICE_STATE) } private fun getNetworkType(networkType: Int) : Array<String> { // Return the string that corresponds to the network type. return when(networkType) { - TelephonyManager.NETWORK_TYPE_UNKNOWN -> arrayOf(getString(R.string.unknown), getString(R.string.unknown)) + TelephonyManager.NETWORK_TYPE_UNKNOWN -> arrayOf(getString(R.string.unknown), "") TelephonyManager.NETWORK_TYPE_GPRS -> arrayOf(getString(R.string.gprs), getString(R.string.gprs_detal)) TelephonyManager.NETWORK_TYPE_EDGE -> arrayOf(getString(R.string.edge), getString(R.string.edge_detail)) TelephonyManager.NETWORK_TYPE_UMTS -> arrayOf(getString(R.string.umts), getString(R.string.umts_detail)) @@ -140,7 +191,7 @@ class PrivacyCell : AppCompatActivity() { TelephonyManager.NETWORK_TYPE_TD_SCDMA -> arrayOf(getString(R.string.td_scdma), getString(R.string.td_scdma_detail)) TelephonyManager.NETWORK_TYPE_IWLAN -> arrayOf(getString(R.string.iwlan), getString(R.string.iwlan_detail)) TelephonyManager.NETWORK_TYPE_NR -> arrayOf(getString(R.string.nr), getString(R.string.nr_detail)) - else -> arrayOf(getString(R.string.error), getString(R.string.error)) + else -> arrayOf(getString(R.string.error), "") } } diff --git a/app/src/main/java/com/stoutner/privacycell/dialogs/PhonePermissionDialog.kt b/app/src/main/java/com/stoutner/privacycell/dialogs/PhonePermissionDialog.kt new file mode 100644 index 0000000..f6a0d38 --- /dev/null +++ b/app/src/main/java/com/stoutner/privacycell/dialogs/PhonePermissionDialog.kt @@ -0,0 +1,71 @@ +/* + * Copyright © 2021 Soren Stoutner <soren@stoutner.com>. + * + * This file is part of Privacy Cell <https://www.stoutner.com/privacy-cell>. + * + * Privacy Cell is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Privacy Cell is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. + */ + +package com.stoutner.privacycell.dialogs + +import android.app.Dialog +import android.content.Context +import android.content.DialogInterface +import android.os.Bundle + +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.DialogFragment + +import com.stoutner.privacycell.R + +class PhonePermissionDialog : DialogFragment() { + // Declare the listener. + private lateinit var storagePermissionDialogListener: StoragePermissionDialogListener + + // The public interface is used to send information back to the parent activity. + interface StoragePermissionDialogListener { + fun onCloseStoragePermissionDialog() + } + + override fun onAttach(context: Context) { + // Run the default commands. + super.onAttach(context) + + // Get a handle for the listener from the launching context. + storagePermissionDialogListener = context as StoragePermissionDialogListener + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + // Use a builder to create the alert dialog. + val dialogBuilder: AlertDialog.Builder = AlertDialog.Builder(requireContext(), R.style.Theme_PrivacyCellAlertDialog) + + // Set the icon. + dialogBuilder.setIcon(R.drawable.phone_permission) + + // Set the title. + dialogBuilder.setTitle(R.string.phone_permission) + + // Set the text. + dialogBuilder.setMessage(R.string.phone_permission_text) + + // Set the close button listener. + dialogBuilder.setNegativeButton(R.string.ok) { _: DialogInterface, _: Int -> + // Call the storage permission dialog listener. + storagePermissionDialogListener.onCloseStoragePermissionDialog() + } + + // Return the alert dialog. + return dialogBuilder.create() + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/phone_permission.xml b/app/src/main/res/drawable/phone_permission.xml new file mode 100644 index 0000000..983dd21 --- /dev/null +++ b/app/src/main/res/drawable/phone_permission.xml @@ -0,0 +1,12 @@ +<!-- This file comes from the Android Material icon set, where it is called `phone_android`. It is released under the Apache License 2.0. --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="24dp" + android:width="24dp" + android:viewportHeight="24" + android:viewportWidth="24"> + + <path + android:fillColor="@color/icon" + android:pathData="M16,1L8,1C6.34,1 5,2.34 5,4v16c0,1.66 1.34,3 3,3h8c1.66,0 3,-1.34 3,-3L19,4c0,-1.66 -1.34,-3 -3,-3zM14,21h-4v-1h4v1zM17.25,18L6.75,18L6.75,4h10.5v14z" /> +</vector> diff --git a/app/src/main/res/layout/privacy_cell_linearlayout.xml b/app/src/main/res/layout/privacy_cell_scrollview.xml similarity index 92% rename from app/src/main/res/layout/privacy_cell_linearlayout.xml rename to app/src/main/res/layout/privacy_cell_scrollview.xml index 167ae8f..77ad82f 100644 --- a/app/src/main/res/layout/privacy_cell_linearlayout.xml +++ b/app/src/main/res/layout/privacy_cell_scrollview.xml @@ -38,6 +38,7 @@ android:layout_gravity="center_horizontal" tools:ignore="ContentDescription" /> + <!-- The text color primary is only displayed if the read phone state permission is not granted. --> <TextView android:id="@+id/secure_from_stingray_textview" android:layout_height="wrap_content" @@ -45,6 +46,7 @@ android:layout_gravity="center_horizontal" android:textAlignment="center" android:layout_marginTop="10dp" + android:textColor="?android:textColorPrimary" android:textSize="20sp" android:textStyle="bold" /> @@ -56,7 +58,7 @@ android:layout_gravity="center_horizontal" android:textAlignment="center" android:layout_marginTop="30dp" - android:textColor="@color/blue_700" + android:textColor="@color/blue_text" android:textSize="18sp" android:textStyle="bold" /> @@ -75,7 +77,7 @@ android:layout_width="wrap_content" android:layout_gravity="center_horizontal" android:textAlignment="center" - android:textColor="@color/blue_700" + android:textColor="@color/blue_text" android:textSize="18sp" android:textStyle="bold" /> @@ -94,7 +96,7 @@ android:layout_width="wrap_content" android:layout_gravity="center_horizontal" android:textAlignment="center" - android:textColor="@color/blue_700" + android:textColor="@color/blue_text" android:textSize="18sp" android:textStyle="bold" /> diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml new file mode 100644 index 0000000..2293934 --- /dev/null +++ b/app/src/main/res/values-night/colors.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + Copyright © 2021 Soren Stoutner <soren@stoutner.com>. + + This file is part of Privacy Cell <https://www.stoutner.com/privacy-cell>. + + Privacy Cell is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Privacy Cell is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. --> + +<resources> + <!-- Nicknamed colors. --> + <color name="blue_text">@color/violet_500</color> + <color name="icon">@color/violet_500</color> + <color name="red_text">@color/salmon</color> + + <!-- Raw colors. --> + <color name="black">#FF000000</color> + <color name="blue_500">#FF2196F3</color> + <color name="blue_700">#FF1976D2</color> + <color name="blue_900">#FF0D47A1</color> + <color name="red_600">#FFE53935</color> + <color name="red_700">#FFD32F2F</color> + <color name="salmon">#FFFC684E</color> + <color name="soft_red">#FFC73625</color> + <color name="violet_500">#FF8AB4F8</color> + <color name="white">#FFFFFFFF</color> +</resources> \ No newline at end of file diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index 674e26c..b8e34ae 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. --> -<resources xmlns:tools="http://schemas.android.com/tools"> +<resources> <style name="Theme.PrivacyCell" parent="Theme.AppCompat.DayNight"> <!-- Main items. --> <item name="android:navigationBarColor">?android:attr/colorBackground</item> @@ -24,4 +24,9 @@ <item name="android:windowLightNavigationBar">false</item> <item name="android:windowLightStatusBar">false</item> </style> + + <style name="Theme.PrivacyCellAlertDialog" parent="Theme.AppCompat.DayNight.Dialog.Alert"> + <!-- Colors. --> + <item name="colorAccent">@color/violet_500</item> + </style> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 7bcc782..d6d743b 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -19,11 +19,20 @@ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. --> <resources> + <!-- Nicknamed colors. --> + <color name="blue_text">@color/blue_700</color> + <color name="icon">@color/blue_700</color> + <color name="red_text">@color/red_700</color> + + <!-- Raw colors. --> <color name="black">#FF000000</color> <color name="blue_500">#FF2196F3</color> <color name="blue_700">#FF1976D2</color> <color name="blue_900">#FF0D47A1</color> <color name="red_600">#FFE53935</color> <color name="red_700">#FFD32F2F</color> + <color name="salmon">#FFFC684E</color> + <color name="soft_red">#FFC73625</color> + <color name="violet_500">#FF8AB4F8</color> <color name="white">#FFFFFFFF</color> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5a461af..66cb8e5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -80,6 +80,12 @@ <string name="lte_nr_nsa_mmwave_detail">Long Term Evolution New Radio Non-Standalone millimeter Wave</string> <!-- Stingray. --> + <!-- The `\n\n` code inserts a line break and should be maintained in translations. --> <string name="secure_from_stingray">Your device is connected to a standalone 5G network.\n\nIt is secure from stingray IMSI man-in-the-middle attacks.</string> <string name="not_secure_from_stingray">Your device is not connected to a standalone 5G network.\n\nIt is not secure from stingray IMSI man-in-the-middle attacks.</string> + + <!-- Phone permission dialog. --> + <string name="phone_permission">Phone Permission</string> + <string name="phone_permission_text">Privacy Cell needs the Read Phone State permission to determine the safety level of your cell connection.</string> + <string name="ok">OK</string> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index e4e0d1b..ccc9324 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. --> -<resources xmlns:tools="http://schemas.android.com/tools"> +<resources> <style name="Theme.PrivacyCell" parent="Theme.AppCompat.DayNight"> <!-- Main items. --> <item name="android:navigationBarColor">?android:attr/colorBackground</item> @@ -24,4 +24,9 @@ <item name="android:windowLightNavigationBar">true</item> <item name="android:windowLightStatusBar">true</item> </style> + + <style name="Theme.PrivacyCellAlertDialog" parent="Theme.AppCompat.DayNight.Dialog.Alert"> + <!-- Colors. --> + <item name="colorAccent">@color/blue_700</item> + </style> </resources> \ No newline at end of file -- 2.47.2