</head>
<body>
- <h3>1.4 (version code 5)</h3>
- <p>18 October 2021 - minimum API 30, target API 30.</p>
+ <h3><a href="https://www.stoutner.com/privacy-cell-1-4/">1.4</a> (version code 5)</h3>
+ <p><a href="https://gitweb.stoutner.com/?p=PrivacyCell.git;a=commitdiff;h=a1d76c6e3ed465dd14385c5a37416ee30922021f">18 October 2021</a> - minimum API 30, target API 30.</p>
<ul>
<li>Fix problems with realtime monitoring <a href="https://redmine.stoutner.com/issues/764">crashing</a> or <a href="https://redmine.stoutner.com/issues/763">playing the wrong sound</a>.</li>
<li>Add a <a href="https://redmine.stoutner.com/issues/768">logcat activity</a>.</li>
</head>
<body>
- <h3>1.4 (versión del código 5)</h3>
- <p>18 de octubre de 2021 - API mínimo 30, API objetivo 30.</p>
+ <h3><a href="https://www.stoutner.com/privacy-cell-1-4/">1.4</a> (versión del código 5)</h3>
+ <p><a href="https://gitweb.stoutner.com/?p=PrivacyCell.git;a=commitdiff;h=a1d76c6e3ed465dd14385c5a37416ee30922021f">18 de octubre de 2021</a> - API mínimo 30, API objetivo 30.</p>
<ul>
<li>Solucionar los problemas de crash de la <a href="https://redmine.stoutner.com/issues/764">monitorización en tiempo real</a> o
<a href="https://redmine.stoutner.com/issues/763">de reproducción de un sonido incorrecto</a>.</li>
</head>
<body>
- <h3>1.4 (version de code 5)</h3>
- <p>18 October 2021 - API minimum 30, API cible 30.</p>
+ <h3><a href="https://www.stoutner.com/privacy-cell-1-4/">1.4</a> (version de code 5)</h3>
+ <p><a href="https://gitweb.stoutner.com/?p=PrivacyCell.git;a=commitdiff;h=a1d76c6e3ed465dd14385c5a37416ee30922021f">18 October 2021</a> - API minimum 30, API cible 30.</p>
<ul>
<li>Fix problems with realtime monitoring <a href="https://redmine.stoutner.com/issues/764">crashing</a> or <a href="https://redmine.stoutner.com/issues/763">playing the wrong sound</a>.</li>
<li>Add a <a href="https://redmine.stoutner.com/issues/768">logcat activity</a>.</li>
</head>
<body>
- <h3>1.4 (versione codice 5)</h3>
- <p>18 Ottobre 2021 - minima API 30, target API 30.</p>
+ <h3><a href="https://www.stoutner.com/privacy-cell-1-4/">1.4</a> (versione codice 5)</h3>
+ <p><a href="https://gitweb.stoutner.com/?p=PrivacyCell.git;a=commitdiff;h=a1d76c6e3ed465dd14385c5a37416ee30922021f">18 Ottobre 2021</a> - minima API 30, target API 30.</p>
<ul>
<li>Correzione di problemi relativi al monitoraggio in tempo reale che andava in <a href="https://redmine.stoutner.com/issues/764">crash</a> or
<a href="https://redmine.stoutner.com/issues/763">suonando il suono sbagliato</a>.</li>
</head>
<body>
- <h3>1.4 (код версии 5)</h3>
- <p>18 октября 2021 года - минимальный API 30, целевой API 30.</p>
+ <h3><a href="https://www.stoutner.com/privacy-cell-1-4/">1.4</a> (код версии 5)</h3>
+ <p><a href="https://gitweb.stoutner.com/?p=PrivacyCell.git;a=commitdiff;h=a1d76c6e3ed465dd14385c5a37416ee30922021f">18 октября 2021 года</a> - минимальный API 30, целевой API 30.</p>
<ul>
<li>Устранены проблемы, связанные со <a href="https://redmine.stoutner.com/issues/764">сбоем</a> мониторинга в реальном времени или
<a href="https://redmine.stoutner.com/issues/763">воспроизведением некорректного звука</a>.</li>
package com.stoutner.privacycell.fragments
+import android.Manifest
import android.content.Intent
import android.content.SharedPreferences
+import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.provider.Settings
+import androidx.core.app.ActivityCompat
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.work.WorkManager
val insecureNetworkNotificationPreference = findPreference<Preference>(getString(R.string.insecure_network_notification_key))!!
bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
- // Set the realtime monitoring preference icon.
- if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) {
- // Set the enabled icon.
- realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_enabled)
+ // Only enable the realtime monitoring preference if the READ_PHONE_STATE permission has been granted.
+ realtimeMonitoringPreference.isEnabled = (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
+
+ // Set the realtime monitoring icon according to the status.
+ if (realtimeMonitoringPreference.isEnabled) {
+ // Set the realtime monitoring preference icon.
+ if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) {
+ // Set the enabled icon.
+ realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_enabled)
+ } else {
+ // Set the disabled icon.
+ realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_disabled)
+ }
} else {
- // Set the disabled icon.
- realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_disabled)
+ // Set the ghosted icon.
+ realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_ghosted)
}
// Set the notification preferences to depend on the realtime monitoring preference.
package com.stoutner.privacycell.services
+import android.Manifest
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationChannelGroup
import android.app.Service
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.os.Binder
import android.os.IBinder
import android.telephony.PhoneStateListener
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyManager
+import androidx.core.app.ActivityCompat
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
}
}
- // Create a register realtime listener work request that fires every hour. For some reason, when the service launches it will initially register the listener and then unregister it.
- // This periodic request will fire shortly thereafter (it fires about every hour near the beginning of the hour) and will reregister the listener, which will stick this time.
- val registerRealtimeListenerWorkRequest = PeriodicWorkRequestBuilder<RegisterRealtimeListener>(1, TimeUnit.HOURS).build()
+ // Check to see if the read phone state permission has been granted.
+ if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
+ // Create a register realtime listener work request that fires every hour.
+ // This periodic request will fire shortly after being created (it fires about every hour near the beginning of the hour) and will reregister the listener if it gets garbage collected.
+ val registerRealtimeListenerWorkRequest = PeriodicWorkRequestBuilder<RegisterRealtimeListener>(1, TimeUnit.HOURS).build()
- // Register the realtime listener work request.
- WorkManager.getInstance(this).enqueueUniquePeriodicWork(getString(R.string.register_listener_work_request), ExistingPeriodicWorkPolicy.REPLACE, registerRealtimeListenerWorkRequest)
+ // Register the realtime listener work request.
+ WorkManager.getInstance(this).enqueueUniquePeriodicWork(getString(R.string.register_listener_work_request), ExistingPeriodicWorkPolicy.REPLACE, registerRealtimeListenerWorkRequest)
+ }
// Return a sticky service.
return START_STICKY
}
fun registerTelephonyManagerListener() {
- // Get a handle for the telephony manager.
- val 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) {
+ // Get a handle for the telephony manager.
+ val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
- // Cancel the current listener if it exists.
- telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE)
+ // Cancel the current listener if it exists.
+ telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE)
- // Listen for changes to the phone state.
- telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
+ // Listen for changes to the phone state.
+ telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
+ }
}
}
\ No newline at end of file
--- /dev/null
+<!--
+ This file is derived from `security` and `5g`, which are part of the Android Material icon set. They are released under the Apache License 2.0.
+
+ Changes copyright © 2016,2021 Soren Stoutner <soren@stoutner.com>. The resulting image is released under the GPLv3+ license.
+
+ 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 Cell. If not, see <http://www.gnu.org/licenses/>. -->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="256"
+ android:viewportWidth="256" >
+
+ <path
+ android:fillColor="@color/icon_ghosted"
+ android:pathData="M128,0 L23.273,46.545L23.273,116.364c-0,64.582 44.684,124.974 104.727,139.636 60.044,-14.662 104.727,-75.054 104.727,-139.636L232.727,46.545ZM54.852,76.633l48.656,0c4.541,0 8.109,3.569 8.109,8.11 0,4.541 -3.568,8.109 -8.109,8.109l-40.547,0l0,24.327l32.437,0c8.92,0 16.219,7.298 16.219,16.219l0,24.328c0,8.92 -7.298,16.219 -16.219,16.219l-40.546,0c-4.541,0 -8.11,-3.569 -8.11,-8.11 0,-4.541 3.569,-8.109 8.11,-8.109l40.546,0l0,-24.328l-40.546,0c-4.541,0 -8.11,-3.568 -8.11,-8.109l0,-40.546c0,-4.541 3.569,-8.11 8.11,-8.11zM144.054,76.633l56.765,0c4.541,0 8.109,3.569 8.109,8.11 0,4.541 -3.568,8.109 -8.109,8.109L144.054,92.852l0,64.874l48.656,0l0,-24.328l-24.328,0c-4.541,0 -8.109,-3.568 -8.109,-8.109 0,-4.541 3.568,-8.11 8.109,-8.11l32.437,0c4.541,0 8.109,3.569 8.109,8.11l0,32.437c0,8.92 -7.297,16.219 -16.218,16.219L144.054,173.945c-8.92,0 -16.219,-7.298 -16.219,-16.219L127.835,92.852c0,-8.92 7.298,-16.219 16.219,-16.219z" />
+</vector>
\ No newline at end of file
<resources>
<!-- Nicknamed colors. -->
<color name="blue_text">@color/violet_500</color>
- <color name="icon_enabled">@color/violet_500</color>
<color name="icon_disabled">@color/gray_500</color>
+ <color name="icon_enabled">@color/violet_500</color>
+ <color name="icon_ghosted">@color/gray_700</color>
<color name="logcat_icons">@color/white</color>
<color name="red_text">@color/salmon</color>
<color name="blue_700">#FF1976D2</color>
<color name="blue_900">#FF0D47A1</color>
+ <color name="gray_425">#FFB7B7B7</color>
<color name="gray_500">#FF9E9E9E</color>
<color name="gray_600">#FF757575</color>
+ <color name="gray_700">#FF616161</color>
<color name="gray_925">#FF202020</color>
<color name="red_600">#FFE53935</color>
<resources>
<!-- Nicknamed colors. -->
<color name="blue_text">@color/blue_700</color>
- <color name="icon_enabled">@color/blue_700</color>
<color name="icon_disabled">@color/gray_600</color>
+ <color name="icon_enabled">@color/blue_700</color>
+ <color name="icon_ghosted">@color/gray_425</color>
<color name="logcat_icons">@color/gray_925</color>
<color name="red_text">@color/red_700</color>
<color name="blue_700">#FF1976D2</color>
<color name="blue_900">#FF0D47A1</color>
+ <color name="gray_425">#FFB7B7B7</color>
<color name="gray_500">#FF9E9E9E</color>
<color name="gray_600">#FF757575</color>
+ <color name="gray_700">#FF616161</color>
<color name="gray_925">#FF202020</color>
<color name="red_600">#FFE53935</color>