Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 553a53ef authored by Ficus Kirkpatrick's avatar Ficus Kirkpatrick
Browse files

Make saveRecentQuery() async.

Bug: 3163612
Change-Id: Idd3c1925e0f1dc3272dd1303d8f2907c5c5fca8b
parent 9f142543
Loading
Loading
Loading
Loading
+62 −50
Original line number Diff line number Diff line
@@ -20,11 +20,12 @@ import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.SearchRecentSuggestionsProvider;
import android.database.Cursor;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

import java.util.concurrent.Semaphore;

/**
 * This is a utility class providing access to
 * {@link android.content.SearchRecentSuggestionsProvider}.
@@ -47,8 +48,6 @@ import android.util.Log;
public class SearchRecentSuggestions {
    // debugging support
    private static final String LOG_TAG = "SearchSuggestions";
    // DELETE ME (eventually)
    private static final int DBG_SUGGESTION_TIMESTAMPS = 0;

    // This is a superset of all possible column names (need not all be in table)
    private static class SuggestionColumns implements BaseColumns {
@@ -69,6 +68,7 @@ public class SearchRecentSuggestions {
        SuggestionColumns.QUERY,
        SuggestionColumns.DISPLAY1,
    };

    /* if you change column order you must also change indices below */
    /**
     * This is the database projection that can be used to view saved queries, when
@@ -92,11 +92,6 @@ public class SearchRecentSuggestions {
    /** Index into the provided query projections.  For use with Cursor.update methods. */
    public static final int QUERIES_PROJECTION_DISPLAY2_INDEX = 4;  // only when 2line active

    /* columns needed to determine whether to truncate history */
    private static final String[] TRUNCATE_HISTORY_PROJECTION = new String[] {
        SuggestionColumns._ID, SuggestionColumns.DATE
    };

    /*
     * Set a cap on the count of items in the suggestions table, to
     * prevent db and layout operations from dragging to a crawl. Revisit this
@@ -105,11 +100,13 @@ public class SearchRecentSuggestions {
    private static final int MAX_HISTORY_COUNT = 250;

    // client-provided configuration values
    private Context mContext;
    private String mAuthority;
    private boolean mTwoLineDisplay;
    private Uri mSuggestionsUri;
    private String[] mQueriesProjection;
    private final Context mContext;
    private final String mAuthority;
    private final boolean mTwoLineDisplay;
    private final Uri mSuggestionsUri;

    /** Released once per completion of async write.  Used for tests. */
    private static final Semaphore sWritesInProgress = new Semaphore(0);

    /**
     * Although provider utility classes are typically static, this one must be constructed
@@ -138,16 +135,11 @@ public class SearchRecentSuggestions {

        // derived values
        mSuggestionsUri = Uri.parse("content://" + mAuthority + "/suggestions");
        
        if (mTwoLineDisplay) {
            mQueriesProjection = QUERIES_PROJECTION_2LINE;
        } else {
            mQueriesProjection = QUERIES_PROJECTION_1LINE;
        }
    }

    /**
     * Add a query to the recent queries list.
     * Add a query to the recent queries list.  Returns immediately, performing the save
     * in the background.
     *
     * @param queryString The string as typed by the user.  This string will be displayed as
     * the suggestion, and if the user clicks on the suggestion, this string will be sent to your
@@ -159,7 +151,7 @@ public class SearchRecentSuggestions {
     * If you did not configure two-line mode, or if a given suggestion does not have any
     * additional text to display, you can pass null here.
     */
    public void saveRecentQuery(String queryString, String line2) {
    public void saveRecentQuery(final String queryString, final String line2) {
        if (TextUtils.isEmpty(queryString)) {
            return;
        }
@@ -167,6 +159,26 @@ public class SearchRecentSuggestions {
            throw new IllegalArgumentException();
        }

        new Thread("saveRecentQuery") {
            @Override
            public void run() {
                saveRecentQueryBlocking(queryString, line2);
                sWritesInProgress.release();
            }
        }.start();
    }

    // Visible for testing.
    void waitForSave() {
        // Acquire writes semaphore until there is nothing available.
        // This is to clean up after any previous callers to saveRecentQuery
        // who did not also call waitForSave().
        do {
            sWritesInProgress.acquireUninterruptibly();
        } while (sWritesInProgress.availablePermits() > 0);
    }

    private void saveRecentQueryBlocking(String queryString, String line2) {
        ContentResolver cr = mContext.getContentResolver();
        long now = System.currentTimeMillis();

+62 −74
Original line number Diff line number Diff line
@@ -14,27 +14,14 @@
 * limitations under the License.
 */

package android.content;
package android.provider;

import android.app.SearchManager;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.provider.SearchRecentSuggestions;
import android.test.ProviderTestCase2;
import android.test.suitebuilder.annotation.Suppress;

/**
 * Very simple provider that I can instantiate right here.
 */
class TestProvider extends SearchRecentSuggestionsProvider {
    final static String AUTHORITY = "android.content.TestProvider";
    final static int MODE = DATABASE_MODE_QUERIES + DATABASE_MODE_2LINES;
    
    public TestProvider() {
        super();
        setupSuggestions(AUTHORITY, MODE);
    }
}
import android.test.suitebuilder.annotation.MediumTest;

/**
 * ProviderTestCase that performs unit tests of SearchRecentSuggestionsProvider.
@@ -43,11 +30,10 @@ class TestProvider extends SearchRecentSuggestionsProvider {
 *
 * $ (cd tests/FrameworkTests/ && mm) && adb sync
 * $ adb shell am instrument -w \
 *     -e class android.content.SearchRecentSuggestionsProviderTest 
 *     -e class android.provider.SearchRecentSuggestionsProviderTest
 *     com.android.frameworktest.tests/android.test.InstrumentationTestRunner
 */
// Suppress these until bug http://b/issue?id=1416586 is fixed.
@Suppress
@MediumTest
public class SearchRecentSuggestionsProviderTest extends ProviderTestCase2<TestProvider> {

    // Elements prepared by setUp()
@@ -87,6 +73,7 @@ public class SearchRecentSuggestionsProviderTest extends ProviderTestCase2<TestP
        final String TEST_LINE1 = "test line 1";
        final String TEST_LINE2 = "test line 2";
        mSearchHelper.saveRecentQuery(TEST_LINE1, TEST_LINE2);
        mSearchHelper.waitForSave();

        // make sure that there are is exactly one entry returned by a non-filtering cursor
        checkOpenCursorCount(1);
@@ -282,6 +269,7 @@ public class SearchRecentSuggestionsProviderTest extends ProviderTestCase2<TestP
            final String line1 = line1Base + i;
            final String line2 = line2Base + i;
            mSearchHelper.saveRecentQuery(line1, line2);
            mSearchHelper.waitForSave();
        }
    }

+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.provider;

import android.content.SearchRecentSuggestionsProvider;

/**
 * Very simple provider that I can instantiate right here.
 */
public class TestProvider extends SearchRecentSuggestionsProvider {
    final static String AUTHORITY = "android.provider.TestProvider";
    final static int MODE = DATABASE_MODE_QUERIES + DATABASE_MODE_2LINES;

    public TestProvider() {
        super();
        setupSuggestions(AUTHORITY, MODE);
    }
}