expo-app-blocker 0.1.39 → 0.1.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,14 +4,20 @@ import android.app.AppOpsManager
4
4
  import android.content.Context
5
5
  import android.content.Intent
6
6
  import android.content.pm.ApplicationInfo
7
+ import android.graphics.Bitmap
8
+ import android.graphics.Canvas
9
+ import android.graphics.drawable.BitmapDrawable
10
+ import android.graphics.drawable.Drawable
7
11
  import android.net.Uri
8
12
  import android.os.Process
9
13
  import android.provider.Settings
14
+ import android.util.Base64
10
15
  import android.util.Log
11
16
  import androidx.core.app.NotificationManagerCompat
12
17
  import expo.modules.kotlin.exception.Exceptions
13
18
  import expo.modules.kotlin.modules.Module
14
19
  import expo.modules.kotlin.modules.ModuleDefinition
20
+ import java.io.ByteArrayOutputStream
15
21
 
16
22
  private const val TAG = "ExpoAppBlocker"
17
23
 
@@ -90,17 +96,46 @@ class ExpoAppBlockerModule : Module() {
90
96
 
91
97
  AsyncFunction("getInstalledApps") {
92
98
  val pm = context.packageManager
93
- val allApps = pm.getInstalledApplications(0)
94
- allApps.mapNotNull { appInfo ->
95
- if (appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) return@mapNotNull null
99
+ val intent = Intent(Intent.ACTION_MAIN).apply {
100
+ addCategory(Intent.CATEGORY_LAUNCHER)
101
+ }
102
+ val resolved = pm.queryIntentActivities(intent, 0)
103
+ val seen = HashSet<String>()
104
+ resolved.mapNotNull { resolveInfo ->
105
+ val appInfo = resolveInfo.activityInfo.applicationInfo
96
106
  if (appInfo.packageName == context.packageName) return@mapNotNull null
107
+ if (!seen.add(appInfo.packageName)) return@mapNotNull null
108
+
109
+ val iconBase64 = try {
110
+ val drawable = pm.getApplicationIcon(appInfo)
111
+ drawableToBase64Png(drawable)
112
+ } catch (e: Exception) {
113
+ Log.w(TAG, "Failed to load icon for ${appInfo.packageName}: ${e.message}")
114
+ null
115
+ }
97
116
 
98
117
  mapOf(
99
118
  "packageName" to appInfo.packageName,
100
- "name" to (pm.getApplicationLabel(appInfo)?.toString() ?: appInfo.packageName)
119
+ "name" to (pm.getApplicationLabel(appInfo)?.toString() ?: appInfo.packageName),
120
+ "iconBase64" to iconBase64
101
121
  )
102
- }.sortedBy { it["name"]?.lowercase() }
122
+ }.sortedBy { it["name"]?.toString()?.lowercase() }
103
123
  }
104
124
  }
105
125
 
126
+ private fun drawableToBase64Png(drawable: Drawable): String {
127
+ val size = 96
128
+ val bitmap = if (drawable is BitmapDrawable && drawable.bitmap != null) {
129
+ Bitmap.createScaledBitmap(drawable.bitmap, size, size, true)
130
+ } else {
131
+ val bmp = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
132
+ val canvas = Canvas(bmp)
133
+ drawable.setBounds(0, 0, canvas.width, canvas.height)
134
+ drawable.draw(canvas)
135
+ bmp
136
+ }
137
+ val stream = ByteArrayOutputStream()
138
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
139
+ return Base64.encodeToString(stream.toByteArray(), Base64.NO_WRAP)
140
+ }
106
141
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-app-blocker",
3
- "version": "0.1.39",
3
+ "version": "0.1.40",
4
4
  "description": "Expo module for cross-platform app blocking. Android: UsageStatsManager + Overlay. iOS: Screen Time API (FamilyControls + ManagedSettings + DeviceActivity).",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -27,6 +27,7 @@ export interface IOSPermissions {
27
27
  export interface AndroidBlockableApp {
28
28
  packageName: string;
29
29
  name: string;
30
+ iconBase64?: string | null;
30
31
  }
31
32
 
32
33
  export interface IOSBlockedItem {