简体   繁体   中英

Content provider query() not being called (Android TV)

I'm trying to include my app into the Android TV global search, according to the documentation I have to create the following:

  • ContentProvider
  • Searchable.xml

And of course include them into the manifest. So that's what I did, my contentprovider is extemely simple. It doesn't return any data, but when it gets the query() call it will print some lines in the log, which it has not done yet.

public class VideoContentProvider extends ContentProvider {
private static String TAG = "VideoContentProvider";
public static String AUTHORITY = "test.tvsearch";

// UriMatcher stuff
private static final int SEARCH_SUGGEST = 0;
private static final int REFRESH_SHORTCUT = 1;
private static final UriMatcher URI_MATCHER = buildUriMatcher();

//private VideoDatabase mVideoDatabase;

/**
 * Builds up a UriMatcher for search suggestion and shortcut refresh queries.
 */
private static UriMatcher buildUriMatcher() {
    UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    // to get suggestions...
    Log.d(TAG, "suggest_uri_path_query: " + SearchManager.SUGGEST_URI_PATH_QUERY);
    matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
    matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST);
    return matcher;
}

@Override
public boolean onCreate() {
    Log.d(TAG, "onCreate");
    //mVideoDatabase = new VideoDatabase(getContext());
    return true;
}

/**
 * Handles all the video searches and suggestion queries from the Search Manager.
 * When requesting a specific word, the uri alone is required.
 * When searching all of the video for matches, the selectionArgs argument must carry
 * the search query as the first element.
 * All other arguments are ignored.
 */
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                    String sortOrder) {
    // Use the UriMatcher to see what kind of query we have and format the db query accordingly
    switch (URI_MATCHER.match(uri)) {
        case SEARCH_SUGGEST:
            Log.d(TAG, "search suggest: " + selectionArgs[0] + " URI: " + uri);
            if (selectionArgs == null) {
                throw new IllegalArgumentException(
                        "selectionArgs must be provided for the Uri: " + uri);
            }
            Log.i("...", "WORKED");
            return null;
        default:
            throw new IllegalArgumentException("Unknown Uri: " + uri);
    }
}

/**
 * This method is required in order to query the supported types.
 * It's also useful in our own query() method to determine the type of Uri received.
 */
@Override
public String getType(Uri uri) {
    switch (URI_MATCHER.match(uri)) {
        case SEARCH_SUGGEST:
            return SearchManager.SUGGEST_MIME_TYPE;
        case REFRESH_SHORTCUT:
            return SearchManager.SHORTCUT_MIME_TYPE;
        default:
            throw new IllegalArgumentException("Unknown URL " + uri);
    }
}

// Other required implementations...

@Override
public Uri insert(Uri uri, ContentValues values) {
    throw new UnsupportedOperationException();
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    throw new UnsupportedOperationException();
}

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    throw new UnsupportedOperationException();
}

}

Searchable.xml:

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="test leanback api demo"
    android:hint="searching for videos test"
    android:searchSettingsDescription="settings text desc"
    android:searchSuggestAuthority="test.tvsearch"
    android:searchSuggestIntentAction="android.intent.action.VIEW"
    android:searchSuggestSelection=" ?"
    android:searchSuggestThreshold="1"
    android:includeInGlobalSearch="true"
    >

This code comes nearly direct from the Android TV leanback example, I extracted this part because it's the only part which handles the global searching.

I included the provider and intent filter for the searchable.xml also in the manifest:

<activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
            <category android:name="android.intent.category.LEANBACK_LAUNCHER" />

            <action android:name="android.intent.action.SEARCH" />

        </intent-filter>

        <!-- Points to searchable meta data. -->
        <meta-data
            android:name="android.app.searchable"
            android:resource="@xml/searchable" />

    </activity>

    <provider
        android:name=".VideoContentProvider"
        android:authorities="test.tvsearch"
        android:exported="true" >...

As I've seen the ContentProvider does get the onCreate call, so it is correctly in the manifest. However the problem is that Android TV when searching doesn't go through my app, the query method does not get called.

I've also seen that the app does not get listed in the Android TV settings > Preferences > Searching > Searchable apps which I think is really weird, because in the searchable.xml it is said to include the provider in the global search. Because this code is nearly copied from the leanback example I'm out of ideas, the example works perfectly and when copied it breaks immediately.

Any help will be appreciated!

If you open this you will see that both android:label and android:hint have to be "string resource" (@string/something) and I thought that build system (or lint tool or whatever) catch that cases now (I spent couple of hours on the exact issue like yours three or four years back), but no, it seems that developers pull hair of their head even now, so simply replace:

android:label="test leanback api demo"
android:hint="searching for videos test"

with:

android:label="@string/search_label"
android:hint="@string/search_hint"

I am not sure about android:searchSettingsDescription since in one place it says: "string resource" but in detailed description it is simple "string"

For anybody else struggling, what Google does not include in their tutorial is that you have to enable your app as searchable in device settings. Otherwise your content provider is created but never queried. Found this in searchable configuration :

android:includeInGlobalSearch Boolean. (Required to provide search suggestions in Quick Search Box.) Set to "true" if you want your suggestions to be included in the globally accessible Quick Search Box. The user must still enable your application as a searchable item in the system search settings before your suggestions will appear in Quick Search Box.

Important to have in one of your Activities in manifest next code, it helped me:

<intent-filter>
            <action android:name="android.intent.action.SEARCH"/>

 <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable"/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM