Skip to content

Enhance widget integration, build stability, and MLKit fallback - #72

Merged
knownassurajit merged 6 commits into
stagefrom
develop
May 24, 2026
Merged

Enhance widget integration, build stability, and MLKit fallback#72
knownassurajit merged 6 commits into
stagefrom
develop

Conversation

@knownassurajit

Copy link
Copy Markdown
Owner

No description provided.

justachillgirl and others added 6 commits May 14, 2026 22:22
Build fixes:
- Raise compileSdk 35→36 to match targetSdk=36; eliminates
  targetSdk > compileSdk mismatch that caused AGP lint failures
- Update android.suppressUnsupportedCompileSdk=36 accordingly
- Add ProGuard keep rules for com.google.mlkit.genai.**,
  Guava ListenableFuture, and Kotlin coroutines internals to
  prevent R8 from stripping reflection-loaded classes that caused
  corrupt/crashing release packages

Widget screen (integrated flavor):
- Replace static grayscale preview bitmaps with live AppWidgetHostView
  instances embedded via AndroidView; touch events pass directly to
  each widget so PendingIntents fire natively (opens the app)
- Add BIND_APPWIDGET permission to AndroidManifest.xml
- Add widgetAllocatedIds: Set<String> to Prefs.kt to persist the
  provider→appWidgetId mapping across launches
- WidgetsViewModel now owns AppWidgetHost (WIDGET_HOST_ID=1024);
  binds each widget on pin via bindAppWidgetIdIfAllowed(); releases
  IDs on unpin via deleteAppWidgetId(); migrates orphaned pins from
  the old version by dropping those without allocated IDs
- WidgetsScreen uses DisposableEffect for startListening/stopListening
  lifecycle, LazyColumn for full-screen scrollable widget list, and a
  per-widget × button instead of the long-press resize/remove dialog
- AndroidView factory wrapped in try-catch so a removed provider
  degrades to a blank FrameLayout rather than crashing

AiSummarizer (integrated flavor):
- fallbackSummarize() (Tier 3 — no on-device AI) now produces
  minimum-token output: "Title: body[0..70]" or truncates at 80
  chars instead of dumping full notification text verbatim

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: paromitaslg98-source <paromitaslg98@gmail.com>
Remove the old app module sources and resources (activities, fragments, adapters, helpers, layouts, drawables, menus, navigation, etc.) and clean up related Kotlin/Java files. Update README to document building integrated/disintegrated debug APK flavors and their output locations. Also include build-system adjustments (Gradle properties, libs, daemon JVM props, proguard) and updates to AndroidManifests / NotificationService implementations to align with the integrated/disintegrated flavor structure.
Add feature gating and disintegrated stubs, consolidate helpers, and refactor major UI screens. Introduces FeatureAvailability to gate integrated vs disintegrated features and adds an AiSummarizer stub for the disintegrated flavor. Moves the integrated PrivateSpaceHelper into src/main and guards it with FeatureAvailability; removes the disintegrated PrivateSpaceHelper and several disintegrated notification/summary screens. Adds a project knowledge base (.gemini/KNOWLEDGE.md).

Refactors AppDrawerScreen by extracting search bar, app list and item composables, improving private-space handling (immediate load on unlock), safer broadcast registration, stable list keys (including pinned shortcuts), and UI/behavior cleanups. Renames disintegrated WidgetsScreen to a generic FeatureUnavailableScreen and centralizes messaging for unavailable features. HomeScreen receives a large rewrite: consolidated gesture handling, improved drag-to-reorder logic, global dragging state, app picker sheet, and date click now opens the calendar via helper. MainActivity updated to import openCalendar and to navigate/handle notification panel behavior changes.
@knownassurajit knownassurajit self-assigned this May 24, 2026
@knownassurajit knownassurajit added bug Something isn't working documentation Improvements or additions to documentation labels May 24, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances build stability by aligning SDK versions and adding ProGuard rules to prevent MLKit class stripping. A major highlight is the complete rewrite of the widget screen, which now hosts live, interactive system widgets instead of static previews. Feedback identifies a critical bug in widget height calculation where raw pixel values are used instead of DP. Furthermore, the reviewer suggests extending widget discovery and binding logic to support cross-profile scenarios, such as Private Space and Work Profiles, to ensure full compatibility with modern Android features.

Comment on lines +336 to +338
val widgetHeightDp = remember(widget.provider) {
maxOf(widget.provider.minHeight, 100).dp
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The AppWidgetProviderInfo.minHeight field is defined in pixels at runtime, not DP. Direct conversion using .dp will result in incorrect widget sizing on devices with different screen densities. You should use LocalDensity to convert the pixel value to DP correctly.

Suggested change
val widgetHeightDp = remember(widget.provider) {
maxOf(widget.provider.minHeight, 100).dp
}
val density = LocalDensity.current
val widgetHeightDp = remember(widget.provider, density) {
with(density) { maxOf(widget.provider.minHeight.toDp(), 100.dp) }
}

Comment on lines +94 to +104
val all = manager.installedProviders.mapNotNull { info ->
try {
val label = info.loadLabel(pm)
val appName = try {
pm.getApplicationLabel(pm.getApplicationInfo(info.provider.packageName, 0)).toString()
} catch (_: Exception) { info.provider.packageName }
WidgetInfo(provider = info, label = label, previewImage = null, appName = appName)
} catch (_: Exception) { null }
}.sortedBy { it.appName }
_allWidgets.value = all
refreshPinnedAndIds(all)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current implementation of loadWidgets only queries widget providers for the current user profile. To fully support Private Space (Android 15) and Work Profiles, you should iterate through all available profiles using LauncherApps.getProfiles() and query AppWidgetManager.getInstalledProvidersForProfile(UserHandle) for each.

val appWidgetId = appWidgetHost.allocateAppWidgetId()

return try {
val bound = manager.bindAppWidgetIdIfAllowed(appWidgetId, widget.provider.provider)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This call to bindAppWidgetIdIfAllowed does not specify a UserHandle. This will fail for widgets belonging to other profiles (like Private Space or Work Profile). Since the project targets SDK 36 and supports Private Space, you should use the overload that accepts a UserHandle to ensure cross-profile widgets can be bound correctly.

@knownassurajit
knownassurajit marked this pull request as ready for review May 24, 2026 18:24
@knownassurajit
knownassurajit merged commit 68cab2e into stage May 24, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants