Add release signing and German reel handling
This commit is contained in:
@@ -5,7 +5,10 @@
|
|||||||
app/build/
|
app/build/
|
||||||
build/
|
build/
|
||||||
local.properties
|
local.properties
|
||||||
|
keystore.properties
|
||||||
*.hprof
|
*.hprof
|
||||||
*.apk
|
*.apk
|
||||||
*.aab
|
*.aab
|
||||||
*.iml
|
*.iml
|
||||||
|
*.jks
|
||||||
|
*.keystore
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
|
import java.util.Properties
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
id("org.jetbrains.kotlin.plugin.compose")
|
id("org.jetbrains.kotlin.plugin.compose")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val keystorePropertiesFile = rootProject.file("keystore.properties")
|
||||||
|
val keystoreProperties = Properties().apply {
|
||||||
|
if (keystorePropertiesFile.exists()) {
|
||||||
|
keystorePropertiesFile.inputStream().use(::load)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val hasReleaseSigning = listOf("storeFile", "storePassword", "keyAlias", "keyPassword")
|
||||||
|
.all { keystoreProperties.getProperty(it).isNullOrBlank().not() }
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.example.instanoreels"
|
namespace = "com.example.instanoreels"
|
||||||
compileSdk = 36
|
compileSdk = 36
|
||||||
@@ -17,9 +28,23 @@ android {
|
|||||||
buildConfigField("String", "INSTAGRAM_PACKAGE", "\"com.instagram.android\"")
|
buildConfigField("String", "INSTAGRAM_PACKAGE", "\"com.instagram.android\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
if (hasReleaseSigning) {
|
||||||
|
create("release") {
|
||||||
|
storeFile = rootProject.file(keystoreProperties.getProperty("storeFile"))
|
||||||
|
storePassword = keystoreProperties.getProperty("storePassword")
|
||||||
|
keyAlias = keystoreProperties.getProperty("keyAlias")
|
||||||
|
keyPassword = keystoreProperties.getProperty("keyPassword")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
isMinifyEnabled = false
|
isMinifyEnabled = false
|
||||||
|
if (hasReleaseSigning) {
|
||||||
|
signingConfig = signingConfigs.getByName("release")
|
||||||
|
}
|
||||||
proguardFiles(
|
proguardFiles(
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
"proguard-rules.pro"
|
"proguard-rules.pro"
|
||||||
|
|||||||
+24
-9
@@ -10,6 +10,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.text.Normalizer
|
||||||
|
|
||||||
class InstagramBlockerAccessibilityService : AccessibilityService() {
|
class InstagramBlockerAccessibilityService : AccessibilityService() {
|
||||||
private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||||
@@ -192,16 +193,25 @@ class InstagramBlockerAccessibilityService : AccessibilityService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldBackOutOfDmViewer(area: InstagramArea, snapshot: InstagramScreenSnapshot): Boolean {
|
private fun shouldBackOutOfDmViewer(area: InstagramArea, snapshot: InstagramScreenSnapshot): Boolean {
|
||||||
val text = snapshot.searchableText
|
val text = snapshot.searchableText.foldForMatching()
|
||||||
val looksLikeDmReelViewer = text.contains("reply to") ||
|
val looksLikeDmReelViewer = listOf(
|
||||||
text.contains("reply to yourself") ||
|
"reply to",
|
||||||
text.contains("send to") ||
|
"reply to yourself",
|
||||||
text.contains("see more") ||
|
"send to",
|
||||||
text.contains("antworten") ||
|
"see more",
|
||||||
text.contains("senden an")
|
"antworten",
|
||||||
|
"senden an",
|
||||||
|
"an chat senden",
|
||||||
|
"an chats senden",
|
||||||
|
"teilen mit",
|
||||||
|
"weiterleiten",
|
||||||
|
).any { text.contains(it.foldForMatching()) }
|
||||||
|
|
||||||
|
// Any blocked Reel surface is safer to leave with Back. Instagram uses the
|
||||||
|
// middle-bottom area for different controls inside Reel viewers, so a
|
||||||
|
// coordinate tap there can hit "Send to" instead of the DM tab.
|
||||||
return area == InstagramArea.DM_THREAD ||
|
return area == InstagramArea.DM_THREAD ||
|
||||||
area == InstagramArea.REELS && inReelViewerFromDm ||
|
area == InstagramArea.REELS ||
|
||||||
looksLikeDmReelViewer
|
looksLikeDmReelViewer
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,10 +227,15 @@ class InstagramBlockerAccessibilityService : AccessibilityService() {
|
|||||||
get() = applicationContext.packageName
|
get() = applicationContext.packageName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun String.foldForMatching(): String {
|
||||||
|
return Normalizer.normalize(lowercase(), Normalizer.Form.NFD)
|
||||||
|
.replace(Regex("\\p{Mn}+"), "")
|
||||||
|
.replace("ß", "ss")
|
||||||
|
}
|
||||||
|
|
||||||
private fun InstagramArea.isRedirectableBlockedArea(): Boolean {
|
private fun InstagramArea.isRedirectableBlockedArea(): Boolean {
|
||||||
return this in setOf(
|
return this in setOf(
|
||||||
InstagramArea.HOME_FEED,
|
InstagramArea.HOME_FEED,
|
||||||
InstagramArea.REELS,
|
|
||||||
InstagramArea.EXPLORE,
|
InstagramArea.EXPLORE,
|
||||||
InstagramArea.SEARCH,
|
InstagramArea.SEARCH,
|
||||||
)
|
)
|
||||||
|
|||||||
+17
-2
@@ -3,6 +3,7 @@ package com.example.instanoreels.accessibility
|
|||||||
import com.example.instanoreels.data.BlockerSettings
|
import com.example.instanoreels.data.BlockerSettings
|
||||||
import com.example.instanoreels.model.BlockDecision
|
import com.example.instanoreels.model.BlockDecision
|
||||||
import com.example.instanoreels.model.InstagramArea
|
import com.example.instanoreels.model.InstagramArea
|
||||||
|
import java.text.Normalizer
|
||||||
|
|
||||||
class InstagramScreenClassifier {
|
class InstagramScreenClassifier {
|
||||||
fun classify(snapshot: InstagramScreenSnapshot): InstagramArea {
|
fun classify(snapshot: InstagramScreenSnapshot): InstagramArea {
|
||||||
@@ -111,10 +112,14 @@ class InstagramScreenClassifier {
|
|||||||
"suggested for you",
|
"suggested for you",
|
||||||
"for you",
|
"for you",
|
||||||
"vorgeschlagen",
|
"vorgeschlagen",
|
||||||
|
"vorschläge",
|
||||||
|
"vorschlaege",
|
||||||
|
"vorschlage",
|
||||||
|
"weitere reels",
|
||||||
"für dich",
|
"für dich",
|
||||||
"fur dich",
|
"fur dich",
|
||||||
)
|
)
|
||||||
val reelRecommendationKeywords = suggestedKeywords + listOf("more reels", "mehr reels")
|
val reelRecommendationKeywords = suggestedKeywords + listOf("more reels", "mehr reels", "weitere reels")
|
||||||
val homeKeywords = listOf("home", "startseite", "feed")
|
val homeKeywords = listOf("home", "startseite", "feed")
|
||||||
val dmInboxKeywords = listOf("messages", "direct", "inbox", "chats", "nachrichten", "postfach")
|
val dmInboxKeywords = listOf("messages", "direct", "inbox", "chats", "nachrichten", "postfach")
|
||||||
val dmInboxPreviewKeywords = listOf(
|
val dmInboxPreviewKeywords = listOf(
|
||||||
@@ -142,7 +147,17 @@ class InstagramScreenClassifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun String.containsAny(keywords: List<String>): Boolean {
|
private fun String.containsAny(keywords: List<String>): Boolean {
|
||||||
return keywords.any { contains(it.lowercase()) }
|
val foldedText = foldForMatching()
|
||||||
|
return keywords.any { keyword ->
|
||||||
|
val foldedKeyword = keyword.foldForMatching()
|
||||||
|
contains(keyword.lowercase()) || foldedText.contains(foldedKeyword)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.foldForMatching(): String {
|
||||||
|
return Normalizer.normalize(lowercase(), Normalizer.Form.NFD)
|
||||||
|
.replace(Regex("\\p{Mn}+"), "")
|
||||||
|
.replace("ß", "ss")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.looksLikeAuthScreen(): Boolean {
|
private fun String.looksLikeAuthScreen(): Boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user