This commit is contained in:
Philipp Heckel 2026-01-04 15:59:59 -05:00
parent 3e16dd6858
commit 4a51d04ec4
9 changed files with 94 additions and 112 deletions

View file

@ -63,19 +63,19 @@ class CertificateSettingsFragment : BasePreferenceFragment(),
// Trusted certificates header
val trustedCategory = PreferenceCategory(preferenceScreen.context)
trustedCategory.title = getString(R.string.settings_certificates_prefs_trusted_header)
trustedCategory.title = getString(R.string.settings_advanced_certificates_trusted_header)
preferenceScreen.addPreference(trustedCategory)
certs.forEach { trustedCert ->
try {
val cert = CertUtil.parseCertificate(trustedCert.pem)
val issuer = parseCommonName(cert.issuerX500Principal.name)
val pref = Preference(preferenceScreen.context)
pref.title = getDisplaySubject(cert)
pref.title = parseCommonName(cert.subjectX500Principal.name)
pref.summary = if (isValid(cert)) {
getString(R.string.settings_certificates_prefs_expires_after,
dateFormat.format(cert.notAfter))
getString(R.string.settings_advanced_certificates_trusted_item_summary_not_expired, issuer, dateFormat.format(cert.notAfter))
} else {
getString(R.string.settings_certificates_prefs_expired)
getString(R.string.settings_advanced_certificates_trusted_item_summary_expired, issuer)
}
pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
TrustedCertificateFragment.newInstanceView(trustedCert.fingerprint)
@ -90,8 +90,8 @@ class CertificateSettingsFragment : BasePreferenceFragment(),
// Add trusted certificate - launches file picker directly
val addTrustedPref = Preference(preferenceScreen.context)
addTrustedPref.title = getString(R.string.settings_certificates_prefs_trusted_add_title)
addTrustedPref.summary = getString(R.string.settings_certificates_prefs_trusted_add_summary)
addTrustedPref.title = getString(R.string.settings_advanced_certificates_trusted_add_title)
addTrustedPref.summary = getString(R.string.settings_advanced_certificates_trusted_add_summary)
addTrustedPref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
trustedCertFilePicker.launch("*/*")
true
@ -104,25 +104,22 @@ class CertificateSettingsFragment : BasePreferenceFragment(),
// Client certificates header
val clientCategory = PreferenceCategory(preferenceScreen.context)
clientCategory.title = getString(R.string.settings_certificates_prefs_client_header)
clientCategory.title = getString(R.string.settings_advanced_certificates_client_header)
preferenceScreen.addPreference(clientCategory)
certs.forEach { clientCert ->
val pref = Preference(preferenceScreen.context)
try {
val x509Cert = CertUtil.parsePkcs12Certificate(clientCert.p12Base64, clientCert.password)
pref.title = getDisplaySubject(x509Cert)
val expires = if (isValid(x509Cert)) {
getString(R.string.settings_certificates_prefs_expires_after,
dateFormat.format(x509Cert.notAfter))
val cert = CertUtil.parsePkcs12Certificate(clientCert.p12Base64, clientCert.password)
val issuer = parseCommonName(cert.issuerX500Principal.name)
pref.title = parseCommonName(cert.subjectX500Principal.name)
pref.summary = if (isValid(cert)) {
getString(R.string.settings_advanced_certificates_client_item_summary_not_expired, issuer, dateFormat.format(cert.notAfter), shortUrl(clientCert.baseUrl))
} else {
getString(R.string.settings_certificates_prefs_expired)
getString(R.string.settings_advanced_certificates_client_item_summary_expired, issuer, shortUrl(clientCert.baseUrl))
}
pref.summary = getString(R.string.settings_certificates_prefs_client_summary,
shortUrl(clientCert.baseUrl), expires)
} catch (e: Exception) {
} catch (_: Exception) {
pref.title = shortUrl(clientCert.baseUrl)
pref.summary = getString(R.string.settings_certificates_prefs_client_configured)
}
pref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
ClientCertificateFragment.newInstanceView(clientCert.baseUrl)
@ -134,8 +131,8 @@ class CertificateSettingsFragment : BasePreferenceFragment(),
// Add client certificate - launches file picker directly
val addClientPref = Preference(preferenceScreen.context)
addClientPref.title = getString(R.string.settings_certificates_prefs_client_add_title)
addClientPref.summary = getString(R.string.settings_certificates_prefs_client_add_summary)
addClientPref.title = getString(R.string.settings_advanced_certificates_client_add_title)
addClientPref.summary = getString(R.string.settings_advanced_certificates_client_add_summary)
addClientPref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
clientCertFilePicker.launch("*/*")
true
@ -153,11 +150,11 @@ class CertificateSettingsFragment : BasePreferenceFragment(),
TrustedCertificateFragment.newInstanceAdd(cert)
.show(childFragmentManager, TrustedCertificateFragment.TAG)
} else {
Toast.makeText(context, R.string.certificate_dialog_error_invalid_cert, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.settings_advanced_certificates_error_invalid_cert, Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Log.w(TAG, "Failed to read certificate file", e)
Toast.makeText(context, R.string.certificate_dialog_error_invalid_cert, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.settings_advanced_certificates_error_invalid_cert, Toast.LENGTH_SHORT).show()
}
}
@ -170,18 +167,17 @@ class CertificateSettingsFragment : BasePreferenceFragment(),
ClientCertificateFragment.newInstance(data)
.show(childFragmentManager, ClientCertificateFragment.TAG)
} else {
Toast.makeText(context, R.string.certificate_dialog_error_invalid_p12, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.settings_advanced_certificates_error_invalid_p12, Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Log.w(TAG, "Failed to read PKCS#12 file", e)
Toast.makeText(context, R.string.certificate_dialog_error_invalid_p12, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.settings_advanced_certificates_error_invalid_p12, Toast.LENGTH_SHORT).show()
}
}
private fun getDisplaySubject(cert: X509Certificate): String {
val subject = cert.subjectX500Principal.name
val cnMatch = Regex("CN=([^,]+)").find(subject)
return cnMatch?.groupValues?.get(1) ?: subject
private fun parseCommonName(name: String): String {
val cnMatch = Regex("CN=([^,]+)").find(name)
return cnMatch?.groupValues?.get(1) ?: name
}
private fun isValid(cert: X509Certificate): Boolean {

View file

@ -260,7 +260,7 @@ class ClientCertificateFragment : DialogFragment() {
val pwd = passwordText.text?.toString() ?: ""
if (!validUrl(url)) {
showError(getString(R.string.certificate_dialog_error_invalid_url))
showError(getString(R.string.client_certificate_dialog_error_invalid_url))
return
}
@ -289,13 +289,13 @@ class ClientCertificateFragment : DialogFragment() {
val p12Base64 = Base64.encodeToString(data, Base64.NO_WRAP)
repository.addClientCertificate(url, p12Base64, pwd)
withContext(Dispatchers.Main) {
Toast.makeText(context, R.string.certificate_dialog_added_toast, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.client_certificate_dialog_added_toast, Toast.LENGTH_SHORT).show()
listener?.onCertificateAdded()
dismiss()
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
showError(getString(R.string.certificate_dialog_error_invalid_p12_password))
showError(getString(R.string.client_certificate_dialog_error_invalid_p12_password))
}
}
}
@ -304,18 +304,18 @@ class ClientCertificateFragment : DialogFragment() {
private fun confirmDeleteCertificate() {
val url = baseUrl ?: return
MaterialAlertDialogBuilder(requireContext())
.setMessage(R.string.certificate_dialog_delete_confirm)
.setPositiveButton(R.string.certificate_dialog_button_delete) { _, _ ->
.setMessage(R.string.client_certificate_dialog_delete_confirm)
.setPositiveButton(R.string.client_certificate_dialog_button_delete) { _, _ ->
lifecycleScope.launch(Dispatchers.IO) {
repository.removeClientCertificate(url)
withContext(Dispatchers.Main) {
Toast.makeText(context, R.string.certificate_dialog_deleted_toast, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.client_certificate_dialog_deleted_toast, Toast.LENGTH_SHORT).show()
listener?.onCertificateDeleted()
dismiss()
}
}
}
.setNegativeButton(R.string.certificate_dialog_button_cancel, null)
.setNegativeButton(R.string.client_certificate_dialog_button_cancel, null)
.show()
}

View file

@ -215,11 +215,11 @@ class TrustedCertificateFragment : DialogFragment() {
val now = Date()
when {
now.after(certificate.notAfter) -> {
warningText.text = getString(R.string.certificate_trust_dialog_expired_warning)
warningText.text = getString(R.string.trusted_certificate_dialog_expired_warning)
warningText.isVisible = true
}
now.before(certificate.notBefore) -> {
warningText.text = getString(R.string.certificate_trust_dialog_not_yet_valid_warning)
warningText.text = getString(R.string.trusted_certificate_dialog_not_yet_valid_warning)
warningText.isVisible = true
}
else -> {
@ -235,7 +235,7 @@ class TrustedCertificateFragment : DialogFragment() {
val pem = CertUtil.encodeToPem(certificate)
repository.addTrustedCertificate(fp, pem)
withContext(Dispatchers.Main) {
Toast.makeText(context, R.string.certificate_dialog_added_toast, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.trusted_certificate_dialog_added_toast, Toast.LENGTH_SHORT).show()
listener?.onCertificateTrusted(certificate)
dismiss()
}
@ -247,7 +247,7 @@ class TrustedCertificateFragment : DialogFragment() {
lifecycleScope.launch(Dispatchers.IO) {
repository.removeTrustedCertificate(fp)
withContext(Dispatchers.Main) {
Toast.makeText(context, R.string.certificate_dialog_deleted_toast, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.trusted_certificate_dialog_deleted_toast, Toast.LENGTH_SHORT).show()
listener?.onCertificateDeleted()
dismiss()
}

View file

@ -154,7 +154,7 @@
android:id="@+id/client_certificate_subject_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/certificate_trust_dialog_subject"
android:text="@string/client_certificate_dialog_subject"
android:textSize="12sp"
android:textColor="?android:textColorSecondary"
android:paddingStart="4dp"
@ -175,7 +175,7 @@
android:id="@+id/client_certificate_issuer_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/certificate_trust_dialog_issuer"
android:text="@string/client_certificate_dialog_issuer"
android:textSize="12sp"
android:textColor="?android:textColorSecondary"
android:paddingStart="4dp"
@ -196,7 +196,7 @@
android:id="@+id/client_certificate_fingerprint_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/certificate_trust_dialog_fingerprint"
android:text="@string/client_certificate_dialog_fingerprint"
android:textSize="12sp"
android:textColor="?android:textColorSecondary"
android:paddingStart="4dp"
@ -229,7 +229,7 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/certificate_trust_dialog_valid_from"
android:text="@string/client_certificate_dialog_valid_from"
android:textSize="12sp"
android:textColor="?android:textColorSecondary"
android:paddingStart="4dp"
@ -254,7 +254,7 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/certificate_trust_dialog_valid_until"
android:text="@string/client_certificate_dialog_valid_until"
android:textSize="12sp"
android:textColor="?android:textColorSecondary"
android:paddingStart="4dp"

View file

@ -45,7 +45,7 @@
android:id="@+id/trusted_certificate_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/certificate_trust_dialog_description"
android:text="@string/trusted_certificate_dialog_description"
android:textSize="14sp"
android:paddingStart="4dp"
android:paddingEnd="4dp"
@ -75,7 +75,7 @@
android:id="@+id/trusted_certificate_subject_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/certificate_trust_dialog_subject"
android:text="@string/trusted_certificate_dialog_subject"
android:textSize="12sp"
android:textColor="?android:textColorSecondary"
android:paddingStart="4dp"
@ -102,7 +102,7 @@
android:id="@+id/trusted_certificate_issuer_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/certificate_trust_dialog_issuer"
android:text="@string/trusted_certificate_dialog_issuer"
android:textSize="12sp"
android:textColor="?android:textColorSecondary"
android:paddingStart="4dp"
@ -129,7 +129,7 @@
android:id="@+id/trusted_certificate_fingerprint_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/certificate_trust_dialog_fingerprint"
android:text="@string/trusted_certificate_dialog_fingerprint"
android:textSize="12sp"
android:textColor="?android:textColorSecondary"
android:paddingStart="4dp"
@ -157,7 +157,7 @@
android:id="@+id/trusted_certificate_valid_from_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/certificate_trust_dialog_valid_from"
android:text="@string/trusted_certificate_dialog_valid_from"
android:textSize="12sp"
android:textColor="?android:textColorSecondary"
android:paddingStart="4dp"
@ -185,7 +185,7 @@
android:id="@+id/trusted_certificate_valid_until_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/certificate_trust_dialog_valid_until"
android:text="@string/trusted_certificate_dialog_valid_until"
android:textSize="12sp"
android:textColor="?android:textColorSecondary"
android:paddingStart="4dp"

View file

@ -13,7 +13,7 @@
app:showAsAction="always" />
<item
android:id="@+id/client_certificate_action_delete"
android:title="@string/certificate_dialog_button_delete"
android:title="@string/client_certificate_dialog_button_delete"
android:visible="false"
app:showAsAction="always" />
</menu>

View file

@ -3,12 +3,12 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/trusted_certificate_action_trust"
android:title="@string/certificate_trust_dialog_button_trust"
android:title="@string/trusted_certificate_dialog_button_trust"
android:visible="false"
app:showAsAction="always" />
<item
android:id="@+id/trusted_certificate_action_delete"
android:title="@string/certificate_dialog_button_delete"
android:title="@string/trusted_certificate_dialog_button_delete"
android:visible="false"
app:showAsAction="always" />
</menu>

View file

@ -423,6 +423,20 @@
<string name="settings_advanced_exact_alarms_title">Exact alarms</string>
<string name="settings_advanced_exact_alarms_true">ntfy can schedule exact alarms. Exact alarms are required to reconnect WebSockets in the background. Click to revoke the permission.</string>
<string name="settings_advanced_exact_alarms_false">ntfy cannot schedule exact alarms. Exact alarms are required to reconnect WebSockets in the background. Click to grant the permission.</string>
<string name="settings_advanced_certificates_title">Manage certificates</string>
<string name="settings_advanced_certificates_summary">Trust self-signed server certificates and manage client certificates for mTLS</string>
<string name="settings_advanced_certificates_trusted_header">Trusted server certificates</string>
<string name="settings_advanced_certificates_trusted_item_summary_not_expired">Issued by %1$s, expires %2$s</string>
<string name="settings_advanced_certificates_trusted_item_summary_expired">Issued by %1$s, expired</string>
<string name="settings_advanced_certificates_trusted_add_title">Add a trusted certificate</string>
<string name="settings_advanced_certificates_trusted_add_summary">Import a server or CA certificate into the trust store (PEM). HTTPS and WebSocket connections will trust this certificate.</string>
<string name="settings_advanced_certificates_client_header">Client certificates (mTLS)</string>
<string name="settings_advanced_certificates_client_item_summary_not_expired">Issued by %1$s, expires %2$s, used by %3$s</string>
<string name="settings_advanced_certificates_client_item_summary_expired">Issued by %1$s, expired, used by %2$s</string>
<string name="settings_advanced_certificates_client_add_title">Add a client certificate</string>
<string name="settings_advanced_certificates_client_add_summary">Import certificate for mutual TLS authentication (PKCS#12). This certificate will be used when connecting to the server.</string>
<string name="settings_advanced_certificates_error_invalid_cert">Invalid certificate file</string>
<string name="settings_advanced_certificates_error_invalid_p12">Invalid PKCS#12 file</string>
<string name="settings_about_header">About</string>
<string name="settings_about_version_title">Version</string>
<string name="settings_about_version_format">ntfy %1$s (%2$s)</string>
@ -452,7 +466,7 @@
<string name="detail_settings_about_header">About</string>
<string name="detail_settings_about_topic_url_title">Topic URL</string>
<!-- User add/edit dialog -->
<!-- User add/edit dialog (UserFragment) -->
<string name="user_dialog_title_add">Add user</string>
<string name="user_dialog_title_edit">Edit user</string>
<string name="user_dialog_description_add">You can add a user here. All topics for the given server will use this user.</string>
@ -467,7 +481,7 @@
<string name="user_dialog_button_delete">Delete user</string>
<string name="user_dialog_button_save">Save</string>
<!-- Custom headers dialog -->
<!-- Custom headers dialog (CustomHeaderFragment) -->
<string name="custom_headers_dialog_title_add">Add custom header</string>
<string name="custom_headers_dialog_title_edit">Edit custom header</string>
<string name="custom_headers_dialog_base_url_hint">Service URL</string>
@ -483,73 +497,45 @@
<string name="custom_headers_dialog_button_save">Save</string>
<string name="custom_headers_dialog_button_delete">Delete</string>
<!-- Certificate trust dialog -->
<!-- Trusted certificate dialog (TrustedCertificateFragment) -->
<string name="trusted_certificate_dialog_title">Certificate details</string>
<string name="trusted_certificate_dialog_title_unknown">Unknown certificate</string>
<string name="trusted_certificate_dialog_title_add">Add trusted certificate</string>
<string name="trusted_certificate_dialog_description">The server\'s certificate could not be verified. This may happen with self-signed certificates or custom Certificate Authorities. Review the details below before trusting.</string>
<string name="trusted_certificate_dialog_description_unknown">The server\'s certificate could not be verified. This may happen with self-signed certificates or custom Certificate Authorities. Review the details below before trusting.</string>
<string name="trusted_certificate_dialog_description_add">You\'ve selected a certificate file. Please review the details below before adding it to your trusted certificates.</string>
<string name="certificate_trust_dialog_description">The server\'s certificate could not be verified. This may happen with self-signed certificates or custom Certificate Authorities. Review the details below before trusting.</string>
<string name="certificate_trust_dialog_subject">Subject</string>
<string name="certificate_trust_dialog_issuer">Issuer</string>
<string name="certificate_trust_dialog_fingerprint">SHA-256 Fingerprint</string>
<string name="certificate_trust_dialog_valid_from">Valid from</string>
<string name="certificate_trust_dialog_valid_until">Valid until</string>
<string name="certificate_trust_dialog_expired_warning">Warning: This certificate has expired!</string>
<string name="certificate_trust_dialog_not_yet_valid_warning">Warning: This certificate is not yet valid!</string>
<string name="certificate_trust_dialog_button_trust">Trust</string>
<string name="certificate_trust_dialog_button_cancel">Cancel</string>
<string name="trusted_certificate_dialog_subject">Subject</string>
<string name="trusted_certificate_dialog_issuer">Issuer</string>
<string name="trusted_certificate_dialog_fingerprint">SHA-256 fingerprint</string>
<string name="trusted_certificate_dialog_valid_from">Valid from</string>
<string name="trusted_certificate_dialog_valid_until">Valid until</string>
<string name="trusted_certificate_dialog_expired_warning">Warning: This certificate has expired.</string>
<string name="trusted_certificate_dialog_not_yet_valid_warning">Warning: This certificate is not yet valid.</string>
<string name="trusted_certificate_dialog_button_trust">Trust</string>
<string name="trusted_certificate_dialog_button_delete">Delete</string>
<string name="trusted_certificate_dialog_added_toast">Certificate added</string>
<string name="trusted_certificate_dialog_deleted_toast">Certificate deleted</string>
<!-- Certificate settings -->
<string name="settings_advanced_certificates_title">Manage certificates</string>
<string name="settings_advanced_certificates_summary">Trust self-signed server certificates and manage client certificates for mTLS</string>
<string name="settings_certificates_prefs_title">Certificates</string>
<string name="settings_certificates_prefs_trusted_header">Trusted server certificates</string>
<string name="settings_certificates_prefs_trusted_add">Add certificate</string>
<string name="settings_certificates_prefs_trusted_add_title">Add a trusted certificate</string>
<string name="settings_certificates_prefs_trusted_add_summary">Import a server or CA certificate into the trust store (PEM format). HTTPS and WebSocket connections will trust this certificate.</string>
<string name="settings_certificates_prefs_client_header">Client certificates (mTLS)</string>
<string name="settings_certificates_prefs_client_add">Add client certificate</string>
<string name="settings_certificates_prefs_client_add_title">Add a client certificate</string>
<string name="settings_certificates_prefs_client_add_summary">Import certificate for mutual TLS authentication (PKCS#12 format). ntfy will use this certificate when connecting to the server.</string>
<string name="settings_certificates_prefs_client_configured">Client certificate configured</string>
<string name="settings_certificates_prefs_expires">Expires %1$s</string>
<string name="settings_certificates_prefs_expired">Expired</string>
<string name="settings_certificates_prefs_expires_after">Expires %1$s</string>
<string name="settings_certificates_prefs_client_summary">Used by %1$s, %2$s</string>
<!-- Certificate dialog -->
<string name="certificate_dialog_title_view">Certificate details</string>
<string name="certificate_dialog_title_add_trusted">Add trusted certificate</string>
<string name="certificate_dialog_title_add_client">Add client certificate</string>
<string name="certificate_dialog_description_add_trusted">Add a trusted server or CA certificate. Connections to the service URL will trust this certificate.</string>
<string name="certificate_dialog_description_add_client">Add a client certificate for mTLS authentication (PEM). The certificate will be used when connecting to the service.</string>
<string name="certificate_dialog_base_url_hint">Service URL (e.g. https://ntfy.example.com)</string>
<string name="certificate_dialog_select_cert_file">Select certificate file (.pem, .crt)</string>
<string name="certificate_dialog_select_p12_file">Select client certificate (.p12)</string>
<string name="certificate_dialog_password_hint">Certificate password</string>
<string name="certificate_dialog_no_file_selected">No file selected</string>
<string name="certificate_dialog_button_add">Add</string>
<string name="certificate_dialog_button_delete">Delete</string>
<string name="certificate_dialog_button_cancel">Cancel</string>
<!-- Client certificate dialog (ClientCertificateFragment) -->
<string name="client_certificate_dialog_title">Client certificate</string>
<string name="client_certificate_dialog_title_add">Add client certificate</string>
<string name="client_certificate_dialog_button_next">Next</string>
<string name="client_certificate_dialog_button_save">Save</string>
<string name="client_certificate_dialog_description_page1">Enter the password for the PKCS#12 file and the server URL this certificate should be used for.</string>
<string name="client_certificate_dialog_description_page2">Review the certificate details and save to add this client certificate.</string>
<string name="client_certificate_dialog_password_hint">Password</string>
<string name="client_certificate_dialog_base_url_hint">Server URL (e.g. https://example.com)</string>
<string name="client_certificate_dialog_subject">Subject</string>
<string name="client_certificate_dialog_issuer">Issuer</string>
<string name="client_certificate_dialog_fingerprint">SHA-256 Fingerprint</string>
<string name="client_certificate_dialog_valid_from">Valid from</string>
<string name="client_certificate_dialog_valid_until">Valid until</string>
<string name="client_certificate_dialog_button_next">Next</string>
<string name="client_certificate_dialog_button_save">Save</string>
<string name="client_certificate_dialog_button_delete">Delete</string>
<string name="client_certificate_dialog_button_cancel">Cancel</string>
<string name="client_certificate_dialog_delete_confirm">Delete this certificate?</string>
<string name="client_certificate_dialog_added_toast">Certificate added</string>
<string name="client_certificate_dialog_deleted_toast">Certificate deleted</string>
<string name="client_certificate_dialog_error_wrong_password">Wrong password or invalid PKCS#12 file</string>
<string name="certificate_dialog_error_invalid_cert">Invalid certificate file</string>
<string name="certificate_dialog_error_invalid_p12">Invalid PKCS#12 file</string>
<string name="certificate_dialog_error_invalid_p12_password">Invalid password or corrupted PKCS#12 file</string>
<string name="certificate_dialog_error_missing_url">Please enter a service URL</string>
<string name="certificate_dialog_error_invalid_url">Invalid service URL</string>
<string name="certificate_dialog_error_missing_cert">Please select a certificate file</string>
<string name="certificate_dialog_error_missing_p12">Please select a PKCS#12 file</string>
<string name="certificate_dialog_error_missing_password">Please enter the certificate password</string>
<string name="certificate_dialog_delete_confirm">Delete this certificate?</string>
<string name="certificate_dialog_added_toast">Certificate added</string>
<string name="certificate_dialog_deleted_toast">Certificate deleted</string>
<string name="client_certificate_dialog_error_invalid_p12_password">Invalid password or corrupted PKCS#12 file</string>
<string name="client_certificate_dialog_error_invalid_url">Invalid service URL</string>
</resources>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
app:title="@string/settings_certificates_prefs_title">
app:title="@string/settings_advanced_certificates_title">
<!-- Categories and preferences are added dynamically in CertificateSettingsFragment -->
</PreferenceScreen>