diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 08e1ad7..af7732f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -14,9 +14,18 @@
> system-level interaction with the user.
-->
+
+
+
+
+
+
+
+
+
= Build.VERSION_CODES.TIRAMISU) {
+ providerInfo = pm.resolveContentProvider(
+ authority,
+ PackageManager.ComponentInfoFlags.of(0L)
+ );
+ } else {
+ providerInfo = pm.resolveContentProvider(authority, 0);
+ }
+
+ if (providerInfo != null) {
+ // Verify the ContentProvider is actually accessible by trying a test query
+ // This is important for Android 11+ where package visibility restrictions
+ // may prevent access even if the provider is found
+ Uri testUri = Uri.parse("content://" + authority + "/decks");
+ try {
+ Cursor testCursor = resolver.query(testUri, new String[]{"_id"}, null, null, null);
+ if (testCursor != null) {
+ testCursor.close();
+ Log.d(TAG, "Found accessible AnkiDroid ContentProvider with authority: " + authority + ", package: " + providerInfo.packageName);
+ cachedAuthority = authority;
+ return cachedAuthority;
+ } else {
+ Log.d(TAG, "Authority " + authority + " found but test query returned null cursor");
+ }
+ } catch (IllegalArgumentException e) {
+ Log.d(TAG, "Authority " + authority + " found but URI not supported: " + e.getMessage());
+ // Continue to next authority
+ } catch (SecurityException e) {
+ Log.d(TAG, "Authority " + authority + " found but access denied: " + e.getMessage());
+ // Continue to next authority
+ } catch (Exception e) {
+ Log.d(TAG, "Authority " + authority + " found but test query failed: " + e.getMessage());
+ // Continue to next authority
+ }
+ }
+ } catch (Exception e) {
+ Log.d(TAG, "Error checking authority " + authority + ": " + e.getMessage());
+ }
+ }
+
+ Log.e(TAG, "Could not find any accessible AnkiDroid ContentProvider authority");
+ return null;
+ }
+
+ /**
+ * Find cards using a search query.
+ * Uses Ankidroid's ContentProvider cards endpoint with Collection.findCards()
+ *
+ * @param query The search query (same syntax as Anki browser)
+ * @return List of card IDs matching the query
+ */
+ public List findCards(String query) {
+ List cardIds = new ArrayList<>();
+
+ // Find the correct authority (release or debug)
+ String authority = findAnkiDroidAuthority();
+ if (authority == null) {
+ Log.e(TAG, "Could not find AnkiDroid ContentProvider authority");
+ return cardIds;
+ }
+
+ // Use the new cards ContentProvider endpoint
+ // The selection parameter contains the search query
+ // Construct URI manually with the correct authority: content://AUTHORITY/cards
+ Uri authorityUri = Uri.parse("content://" + authority);
+ Uri cardsUri = Uri.withAppendedPath(authorityUri, "cards");
+ Log.d(TAG, "Querying cards with URI: " + cardsUri);
+
+ try {
+ Cursor cursor = resolver.query(
+ cardsUri,
+ new String[]{"_id"},
+ query,
+ null,
+ null
+ );
+
+ if (cursor != null) {
+ try {
+ int idColumnIndex = cursor.getColumnIndexOrThrow("_id");
+ while (cursor.moveToNext()) {
+ long cardId = cursor.getLong(idColumnIndex);
+ cardIds.add(cardId);
+ }
+ Log.d(TAG, "Successfully queried cards, found " + cardIds.size() + " card IDs");
+ } finally {
+ cursor.close();
+ }
+ } else {
+ Log.w(TAG, "Cursor is null for URI: " + cardsUri + ". ContentProvider may not be accessible.");
+ // Clear cache to force re-detection next time
+ cachedAuthority = null;
+ }
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "URI not supported: " + cardsUri + ". Error: " + e.getMessage());
+ // Clear cache to force re-detection next time
+ cachedAuthority = null;
+ } catch (SecurityException e) {
+ Log.e(TAG, "Security exception accessing ContentProvider: " + cardsUri + ". Error: " + e.getMessage());
+ // Clear cache to force re-detection next time
+ cachedAuthority = null;
+ } catch (Exception e) {
+ Log.e(TAG, "Error querying cards: " + e.getMessage(), e);
+ // Clear cache to force re-detection next time
+ cachedAuthority = null;
+ }
+
+ return cardIds;
+ }
+
+ /**
+ * Get card information for a list of card IDs.
+ * Returns data in Anki-Connect format for compatibility.
+ * Optimized for large collections by batching note lookups.
+ *
+ * @param cardIds List of card IDs
+ * @return List of card info maps (serialized as Map for JSON compatibility)
+ */
+ public List