diff --git a/.idea/copyright/E_Foundation.xml b/.idea/copyright/E_Foundation.xml
deleted file mode 100644
index 6f4df2f8aa77284b5d434416c743a35087d4f281..0000000000000000000000000000000000000000
--- a/.idea/copyright/E_Foundation.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/copyright/MURENA.xml b/.idea/copyright/MURENA.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0c0ee9579c9773827c14bb0998f39ee27eeb7cbf
--- /dev/null
+++ b/.idea/copyright/MURENA.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 323a1186847bcfcbacd53cb15e2cfef118f4de19..12d11590dd8d6788e2e5e2e814af27829b875fda 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -132,7 +132,7 @@ dependencies {
implementation project(':trackers')
- implementation 'foundation.e:privacymodule.tor:1.6.0-dev-orbot-16.6.2'
+ implementation 'foundation.e:privacymodule.tor:1.7.0-orbot-16.6.2'
implementation 'foundation.e:elib:0.0.1-alpha11'
diff --git a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
index f241e6738f1158500ffbefcc32da33297fc218ec..e6d4c42ebae3fade002f8436349e715591ec97fe 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/DependencyContainer.kt
@@ -143,9 +143,17 @@ class DependencyContainer(val app: Application) {
getQuickPrivacyStateUseCase,
trackersStatisticsUseCase,
)
+
+ Notifications.startListening(
+ context,
+ getQuickPrivacyStateUseCase,
+ permissionsModule,
+ GlobalScope
+ )
}
}
+@Suppress("LongParameterList")
class ViewModelsFactory(
private val getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase,
private val trackersStatisticsUseCase: TrackersStatisticsUseCase,
diff --git a/app/src/main/java/foundation/e/privacycentralapp/Notifications.kt b/app/src/main/java/foundation/e/privacycentralapp/Notifications.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0df3e180e928a794871b16ec5f3c679ce865a295
--- /dev/null
+++ b/app/src/main/java/foundation/e/privacycentralapp/Notifications.kt
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2022 MURENA SAS
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see .
+ */
+
+package foundation.e.privacycentralapp
+
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import androidx.annotation.StringRes
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import foundation.e.privacycentralapp.domain.entities.InternetPrivacyMode
+import foundation.e.privacycentralapp.domain.entities.MainFeatures
+import foundation.e.privacycentralapp.domain.usecases.GetQuickPrivacyStateUseCase
+import foundation.e.privacycentralapp.main.MainActivity
+import foundation.e.privacymodules.permissions.PermissionsPrivacyModule
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+
+object Notifications {
+ const val CHANNEL_FIRST_BOOT = "first_boot_notification"
+ const val CHANNEL_FAKE_LOCATION_FLAG = "fake_location_flag"
+ const val CHANNEL_IPSCRAMBLING_FLAG = "ipscrambling_flag"
+
+ const val NOTIFICATION_FIRST_BOOT = 1000
+ const val NOTIFICATION_FAKE_LOCATION_FLAG = NOTIFICATION_FIRST_BOOT + 1
+ const val NOTIFICATION_IPSCRAMBLING_FLAG = NOTIFICATION_FAKE_LOCATION_FLAG + 1
+
+ fun showFirstBootNotification(context: Context) {
+ createNotificationFirstBootChannel(context)
+ val notificationBuilder: NotificationCompat.Builder = notificationBuilder(
+ context,
+ NotificationContent(
+ channelId = CHANNEL_FIRST_BOOT,
+ icon = R.drawable.ic_notification_logo,
+ title = R.string.first_notification_title,
+ description = R.string.first_notification_summary,
+ destinationIntent =
+ context.packageManager.getLaunchIntentForPackage(context.packageName)
+ )
+ )
+ .setAutoCancel(true)
+
+ NotificationManagerCompat.from(context).notify(
+ NOTIFICATION_FIRST_BOOT, notificationBuilder.build()
+ )
+ }
+
+ fun startListening(
+ appContext: Context,
+ getQuickPrivacyStateUseCase: GetQuickPrivacyStateUseCase,
+ permissionsPrivacyModule: PermissionsPrivacyModule,
+ appScope: CoroutineScope
+ ) {
+ createNotificationFlagChannel(
+ context = appContext,
+ permissionsPrivacyModule = permissionsPrivacyModule,
+ channelId = CHANNEL_FAKE_LOCATION_FLAG,
+ channelName = R.string.notifications_fake_location_channel_name,
+ channelDescription = R.string.notifications_fake_location_channel_description
+ )
+
+ createNotificationFlagChannel(
+ context = appContext,
+ permissionsPrivacyModule = permissionsPrivacyModule,
+ channelId = CHANNEL_IPSCRAMBLING_FLAG,
+ channelName = R.string.notifications_ipscrambling_channel_name,
+ channelDescription = R.string.notifications_ipscrambling_channel_description
+ )
+
+ getQuickPrivacyStateUseCase.isLocationHidden.onEach {
+ if (it) {
+ showFlagNotification(appContext, MainFeatures.FAKE_LOCATION)
+ } else {
+ hideFlagNotification(appContext, MainFeatures.FAKE_LOCATION)
+ }
+ }.launchIn(appScope)
+
+ getQuickPrivacyStateUseCase.ipScramblingMode.map {
+ it != InternetPrivacyMode.REAL_IP
+ }.distinctUntilChanged().onEach {
+ if (it) {
+ showFlagNotification(appContext, MainFeatures.IP_SCRAMBLING)
+ } else {
+ hideFlagNotification(appContext, MainFeatures.IP_SCRAMBLING)
+ }
+ }.launchIn(appScope)
+ }
+
+ private fun createNotificationFirstBootChannel(context: Context) {
+ val channel = NotificationChannel(
+ CHANNEL_FIRST_BOOT,
+ context.getString(R.string.notifications_first_boot_channel_name),
+ NotificationManager.IMPORTANCE_HIGH
+ )
+ NotificationManagerCompat.from(context).createNotificationChannel(channel)
+ }
+
+ private fun createNotificationFlagChannel(
+ context: Context,
+ permissionsPrivacyModule: PermissionsPrivacyModule,
+ channelId: String,
+ @StringRes channelName: Int,
+ @StringRes channelDescription: Int,
+ ) {
+ val channel = NotificationChannel(
+ channelId, context.getString(channelName), NotificationManager.IMPORTANCE_LOW
+ )
+ channel.description = context.getString(channelDescription)
+ permissionsPrivacyModule.setBlockable(channel)
+ NotificationManagerCompat.from(context).createNotificationChannel(channel)
+ }
+
+ private fun showFlagNotification(context: Context, feature: MainFeatures) {
+ when (feature) {
+ MainFeatures.FAKE_LOCATION -> showFlagNotification(
+ context = context,
+ id = NOTIFICATION_FAKE_LOCATION_FLAG,
+ content = NotificationContent(
+ channelId = CHANNEL_FAKE_LOCATION_FLAG,
+ icon = R.drawable.ic_fmd_bad,
+ title = R.string.notifications_fake_location_title,
+ description = R.string.notifications_fake_location_content,
+ destinationIntent = MainActivity.createFakeLocationIntent(context),
+ )
+ )
+ MainFeatures.IP_SCRAMBLING -> showFlagNotification(
+ context = context,
+ id = NOTIFICATION_IPSCRAMBLING_FLAG,
+ content = NotificationContent(
+ channelId = CHANNEL_IPSCRAMBLING_FLAG,
+ icon = R.drawable.ic_language,
+ title = R.string.notifications_ipscrambling_title,
+ description = R.string.notifications_ipscrambling_content,
+ destinationIntent = MainActivity.createIpScramblingIntent(context),
+ )
+ )
+ else -> {}
+ }
+ }
+
+ private fun showFlagNotification(
+ context: Context,
+ id: Int,
+ content: NotificationContent,
+ ) {
+ val builder = notificationBuilder(context, content)
+ .setPriority(NotificationCompat.PRIORITY_LOW)
+ .setOngoing(true)
+
+ NotificationManagerCompat.from(context).notify(id, builder.build())
+ }
+
+ private fun hideFlagNotification(context: Context, feature: MainFeatures) {
+ val id = when (feature) {
+ MainFeatures.FAKE_LOCATION -> NOTIFICATION_FAKE_LOCATION_FLAG
+ MainFeatures.IP_SCRAMBLING -> NOTIFICATION_IPSCRAMBLING_FLAG
+ else -> return
+ }
+ NotificationManagerCompat.from(context).cancel(id)
+ }
+
+ private data class NotificationContent(
+ val channelId: String,
+ val icon: Int,
+ val title: Int,
+ val description: Int,
+ val destinationIntent: Intent?
+ )
+
+ private fun notificationBuilder(
+ context: Context,
+ content: NotificationContent
+ ): NotificationCompat.Builder {
+ val builder = NotificationCompat.Builder(context, content.channelId)
+ .setSmallIcon(content.icon)
+ .setPriority(NotificationCompat.PRIORITY_LOW)
+ .setContentTitle(context.getString(content.title))
+ .setStyle(NotificationCompat.BigTextStyle().bigText(context.getString(content.description)))
+
+ content.destinationIntent?.let {
+ it.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ val pendingIntent: PendingIntent = PendingIntent.getActivity(
+ context, 0, it, PendingIntent.FLAG_IMMUTABLE
+ )
+ builder.setContentIntent(pendingIntent)
+ }
+
+ return builder
+ }
+}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/common/BootCompletedReceiver.kt b/app/src/main/java/foundation/e/privacycentralapp/common/BootCompletedReceiver.kt
index f43c2cce55caa81e37b23399af784e5d3a0d167d..d7902ee56e2249f4543336bec1523c6fce29a90e 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/common/BootCompletedReceiver.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/common/BootCompletedReceiver.kt
@@ -17,57 +17,20 @@
package foundation.e.privacycentralapp.common
-import android.app.NotificationChannel
-import android.app.NotificationManager
-import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
-import androidx.core.app.NotificationCompat
-import foundation.e.privacycentralapp.R
+import foundation.e.privacycentralapp.Notifications
import foundation.e.privacycentralapp.data.repositories.LocalStateRepository
class BootCompletedReceiver : BroadcastReceiver() {
- companion object {
- const val FIRST_BOOT_NOTIFICATION_ID = 10
- }
-
override fun onReceive(context: Context, intent: Intent?) {
if (intent?.action == Intent.ACTION_BOOT_COMPLETED) {
val localStateRepository = LocalStateRepository(context)
if (localStateRepository.firstBoot) {
- showNotification(context)
+ Notifications.showFirstBootNotification(context)
localStateRepository.firstBoot = false
}
}
}
-
- private fun showNotification(context: Context) {
- val channelId = "first_boot_notification"
- val pendingIntent =
- PendingIntent.getActivity(
- context,
- 0,
- context.packageManager.getLaunchIntentForPackage(context.packageName),
- PendingIntent.FLAG_IMMUTABLE
- )
- val notificationBuilder: NotificationCompat.Builder =
- NotificationCompat.Builder(context, channelId)
- .setSmallIcon(R.drawable.ic_notification_logo)
- .setContentTitle(context.getString(R.string.first_notification_title))
- .setAutoCancel(true)
- .setContentIntent(pendingIntent)
- .setStyle(
- NotificationCompat.BigTextStyle()
- .bigText(context.getString(R.string.first_notification_summary))
- )
- val notificationManager =
- context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
-
- val name: CharSequence = "First Boot"
- val importance = NotificationManager.IMPORTANCE_HIGH
- val mChannel = NotificationChannel(channelId, name, importance)
- notificationManager.createNotificationChannel(mChannel)
- notificationManager.notify(FIRST_BOOT_NOTIFICATION_ID, notificationBuilder.build())
- }
}
diff --git a/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt b/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt
index a81f5b5fc7996a1aea599854d9b506190a39bc84..92dc326931bfc84f5df225e301c07a49829ab13f 100644
--- a/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt
+++ b/app/src/main/java/foundation/e/privacycentralapp/main/MainActivity.kt
@@ -26,6 +26,8 @@ import androidx.fragment.app.add
import androidx.fragment.app.commit
import foundation.e.privacycentralapp.R
import foundation.e.privacycentralapp.features.dashboard.DashboardFragment
+import foundation.e.privacycentralapp.features.internetprivacy.InternetPrivacyFragment
+import foundation.e.privacycentralapp.features.location.FakeLocationFragment
import foundation.e.privacycentralapp.features.trackers.TrackersFragment
open class MainActivity : FragmentActivity(R.layout.activity_main) {
@@ -50,6 +52,12 @@ open class MainActivity : FragmentActivity(R.layout.activity_main) {
ACTION_VIEW_TRACKERS -> {
add(R.id.container)
}
+ ACTION_VIEW_FAKE_LOCATION -> {
+ add(R.id.container)
+ }
+ ACTION_VIEW_IPSCRAMBLING -> {
+ add(R.id.container)
+ }
else -> add(R.id.container)
}
disallowAddToBackStack()
@@ -69,6 +77,8 @@ open class MainActivity : FragmentActivity(R.layout.activity_main) {
companion object {
private const val ACTION_HIGHLIGHT_LEAKS = "ACTION_HIGHLIGHT_LEAKS"
private const val ACTION_VIEW_TRACKERS = "ACTION_VIEW_TRACKERS"
+ private const val ACTION_VIEW_FAKE_LOCATION = "ACTION_VIEW_FAKE_LOCATION"
+ private const val ACTION_VIEW_IPSCRAMBLING = "ACTION_VIEW_IPSCRAMBLING"
fun createHighlightLeaksIntent(context: Context, highlightIndex: Int) =
Intent(context, MainActivity::class.java).apply {
@@ -80,5 +90,17 @@ open class MainActivity : FragmentActivity(R.layout.activity_main) {
Intent(context, MainActivity::class.java).apply {
action = ACTION_VIEW_TRACKERS
}
+
+ fun createFakeLocationIntent(context: Context): Intent {
+ return Intent(context, MainActivity::class.java).apply {
+ action = ACTION_VIEW_FAKE_LOCATION
+ }
+ }
+
+ fun createIpScramblingIntent(context: Context): Intent {
+ return Intent(context, MainActivity::class.java).apply {
+ action = ACTION_VIEW_IPSCRAMBLING
+ }
+ }
}
}
diff --git a/app/src/main/res/drawable/ic_fmd_bad.xml b/app/src/main/res/drawable/ic_fmd_bad.xml
new file mode 100644
index 0000000000000000000000000000000000000000..beeff3560857e9f20b769cc15a5eecd26ac56bfe
--- /dev/null
+++ b/app/src/main/res/drawable/ic_fmd_bad.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_language.xml b/app/src/main/res/drawable/ic_language.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ae37ec03b24e25179ada923caf234f19d279add7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_language.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4d6e1f941c9fe91d7d4116e39df152df72f2c0a3..b29bbcadab8a368f33994e89f60fd31e3c1a3713 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -102,6 +102,7 @@
This option uses the TOR network to hide your real IP address. Only use it for specific applications. While your IP is faked, your Internet speed is likely to be reduced.\nImportant: we advise disabling this feature for email services as your address may end into permanent ban from your provider.
I understand
+
@string/app_name
Your online privacy is protected
@@ -119,6 +120,20 @@
@string/dashboard_state_ipaddress_on
@string/dashboard_graph_trackers_legend
View
+
+
+ First Boot
Discover Advanced Privacy
Tap to find out how to easily block trackers, fake your location & hide your IP address.
+ Fake location flag
+ Highlight that location is currently faked by Advanced Privacy
+
+ Fake location is on
+ All apps using your location including your navigation app are now using this fake location.
+
+ Hide my IP flag
+ Highlight that IP is currently hidden by Advanced Privacy
+ Real IP hidden
+ This could impact the functioning of some applications.
+
diff --git a/build.gradle b/build.gradle
index 2abc73d2116ab02df9aadf0170ca052b40700733..83197c3000138a851615ad593983c3b1c94ac85f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -26,7 +26,7 @@ buildscript {
'targetSdk' : 31,
'version' : [
'major': 1,
- 'minor': 4,
+ 'minor': 7,
'patch': 0,
],
]
@@ -131,7 +131,6 @@ subprojects {
targetExclude('bin/**/*.kt')
targetExclude '**/spotless/*.kt'
ktlint(Versions.ktlint)
- licenseHeaderFile rootProject.file('spotless/copyright.kt')
}
format 'misc', {
// define the files to apply `misc` to
diff --git a/spotless/copyright.kt b/permissionse/libs/hidden-apis-stub/src/main/java/android/app/NotificationChannel.java
similarity index 59%
rename from spotless/copyright.kt
rename to permissionse/libs/hidden-apis-stub/src/main/java/android/app/NotificationChannel.java
index 698a46368867eb7eaff015ff4ebc1ff9714ecf50..9e8d65a9ab848020efe6bdebc59f0f8a5ae1ab8a 100644
--- a/spotless/copyright.kt
+++ b/permissionse/libs/hidden-apis-stub/src/main/java/android/app/NotificationChannel.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) $YEAR E FOUNDATION
+ * Copyright (C) 2022 MURENA SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,3 +15,20 @@
* along with this program. If not, see .
*/
+package android.app;
+
+import android.annotation.TargetApi;
+
+import androidx.annotation.DeprecatedSinceApi;
+
+public class NotificationChannel {
+
+ @TargetApi(29)
+ @DeprecatedSinceApi(api = 30, message = "Use setBlockable() instead.")
+ public void setBlockableSystem(boolean blockableSystem) {}
+
+ // Public in API 33.
+ @TargetApi(30)
+ public void setBlockable(boolean blockableSystem) {}
+
+}
diff --git a/permissionse/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt b/permissionse/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt
index 83711dd079c728372cd160b21e8e8102dcf9d95f..c07f367b531ebd2fb27178a1ca069a4dec557d8d 100644
--- a/permissionse/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt
+++ b/permissionse/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt
@@ -21,6 +21,7 @@ import android.annotation.TargetApi
import android.app.AppOpsManager
import android.app.AppOpsManager.OP_NONE
import android.app.AppOpsManager.strOpToOp
+import android.app.NotificationChannel
import android.content.Context
import android.net.IConnectivityManager
import android.net.VpnManager
@@ -191,4 +192,14 @@ class PermissionsPrivacyModule(context: Context) : APermissionsPrivacyModule(con
return null
}
}
+
+ override fun setBlockable(notificationChannel: NotificationChannel) {
+ when (Build.VERSION.SDK_INT) {
+ 29 -> notificationChannel.setBlockableSystem(true)
+ 30, 31, 32 -> notificationChannel.setBlockable(true)
+ else -> {
+ Log.e("Permissions-e", "Bad android sdk version")
+ }
+ }
+ }
}
diff --git a/permissionsstandalone/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt b/permissionsstandalone/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt
index 98ebdc3ba2ec80d1fca349db891eb795e9c72646..52dfd08b8b6920ffddd36a2a1eac8c2b61c2419a 100644
--- a/permissionsstandalone/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt
+++ b/permissionsstandalone/src/main/java/foundation/e/privacymodules/permissions/PermissionsPrivacyModule.kt
@@ -17,6 +17,7 @@
package foundation.e.privacymodules.permissions
+import android.app.NotificationChannel
import android.content.Context
import foundation.e.privacymodules.permissions.data.AppOpModes
import foundation.e.privacymodules.permissions.data.ApplicationDescription
@@ -48,4 +49,6 @@ class PermissionsPrivacyModule(context: Context) : APermissionsPrivacyModule(con
override fun getAlwaysOnVpnPackage(): String? {
return null
}
+
+ override fun setBlockable(notificationChannel: NotificationChannel) {}
}
diff --git a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/IPermissionsPrivacyModule.kt b/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/IPermissionsPrivacyModule.kt
index 6624798e079a63ba218a71c8848302e5ce9187d9..ff0b3d7c6a99d90ee9447062981c252cb2c4916c 100644
--- a/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/IPermissionsPrivacyModule.kt
+++ b/privacymodule-api/src/main/java/foundation/e/privacymodules/permissions/IPermissionsPrivacyModule.kt
@@ -17,6 +17,7 @@
package foundation.e.privacymodules.permissions
+import android.app.NotificationChannel
import android.content.pm.ApplicationInfo
import android.graphics.drawable.Drawable
import foundation.e.privacymodules.permissions.data.AppOpModes
@@ -128,4 +129,14 @@ interface IPermissionsPrivacyModule {
* Returns the package name of the currently set always-on VPN application, or null.
*/
fun getAlwaysOnVpnPackage(): String?
+
+ /**
+ * Allows users to block notifications sent through this channel, if this channel belongs to
+ * a package that is signed with the system signature.
+ *
+ * If the channel does not belong to a package that is signed with the system signature, this
+ * method does nothing, since such channels are blockable by default and cannot be set to be
+ * unblockable.
+ */
+ fun setBlockable(notificationChannel: NotificationChannel)
}