19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.HandlerThread;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>A filter constrains data with a filtering pattern.</p>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Filters are usually created by {@link android.widget.Filterable}
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * classes.</p>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Filtering operations performed by calling {@link #filter(CharSequence)} or
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #filter(CharSequence, android.widget.Filter.FilterListener)} are
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * performed asynchronously. When these methods are called, a filtering request
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is posted in a request queue and processed later. Any call to one of these
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * methods will cancel any previous non-executed filtering request.</p>
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see android.widget.Filterable
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class Filter {
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String LOG_TAG = "Filter";
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String THREAD_NAME = "Filter";
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int FILTER_TOKEN = 0xD0D0F00D;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int FINISH_TOKEN = 0xDEADBEEF;
45b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Handler mThreadHandler;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Handler mResultHandler;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
498bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen    private Delayer mDelayer;
508bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen
51b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project    private final Object mLock = new Object();
52b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Creates a new asynchronous filter.</p>
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Filter() {
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mResultHandler = new ResultsHandler();
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
618bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen     * Provide an interface that decides how long to delay the message for a given query.  Useful
628bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen     * for heuristics such as posting a delay for the delete key to avoid doing any work while the
638bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen     * user holds down the delete key.
648bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen     *
658bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen     * @param delayer The delayer.
668bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen     * @hide
678bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen     */
688bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen    public void setDelayer(Delayer delayer) {
698bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen        synchronized (mLock) {
708bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen            mDelayer = delayer;
718bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen        }
728bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen    }
738bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen
748bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen    /**
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Starts an asynchronous filtering operation. Calling this method
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * cancels all previous non-executed filtering requests and posts a new
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * filtering request that will be executed later.</p>
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param constraint the constraint used to filter the data
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #filter(CharSequence, android.widget.Filter.FilterListener)
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final void filter(CharSequence constraint) {
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        filter(constraint, null);
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Starts an asynchronous filtering operation. Calling this method
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * cancels all previous non-executed filtering requests and posts a new
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * filtering request that will be executed later.</p>
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Upon completion, the listener is notified.</p>
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param constraint the constraint used to filter the data
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param listener a listener notified upon completion of the operation
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #filter(CharSequence)
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #performFiltering(CharSequence)
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #publishResults(CharSequence, android.widget.Filter.FilterResults)
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final void filter(CharSequence constraint, FilterListener listener) {
102b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project        synchronized (mLock) {
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mThreadHandler == null) {
104ab3ef104cd507c06eac34fc436b39340f6e9d680Karl Rosaen                HandlerThread thread = new HandlerThread(
105ab3ef104cd507c06eac34fc436b39340f6e9d680Karl Rosaen                        THREAD_NAME, android.os.Process.THREAD_PRIORITY_BACKGROUND);
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                thread.start();
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mThreadHandler = new RequestHandler(thread.getLooper());
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1098bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen
1108bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen            final long delay = (mDelayer == null) ? 0 : mDelayer.getPostingDelay(constraint);
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Message message = mThreadHandler.obtainMessage(FILTER_TOKEN);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            RequestArguments args = new RequestArguments();
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // make sure we use an immutable copy of the constraint, so that
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // it doesn't change while the filter operation is in progress
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            args.constraint = constraint != null ? constraint.toString() : null;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            args.listener = listener;
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            message.obj = args;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mThreadHandler.removeMessages(FILTER_TOKEN);
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mThreadHandler.removeMessages(FINISH_TOKEN);
1238bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen            mThreadHandler.sendMessageDelayed(message, delay);
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Invoked in a worker thread to filter the data according to the
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * constraint. Subclasses must implement this method to perform the
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * filtering operation. Results computed by the filtering operation
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * must be returned as a {@link android.widget.Filter.FilterResults} that
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * will then be published in the UI thread through
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #publishResults(CharSequence,
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * android.widget.Filter.FilterResults)}.</p>
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p><strong>Contract:</strong> When the constraint is null, the original
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * data must be restored.</p>
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param constraint the constraint used to filter the data
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the results of the filtering operation
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #filter(CharSequence, android.widget.Filter.FilterListener)
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #publishResults(CharSequence, android.widget.Filter.FilterResults)
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.widget.Filter.FilterResults
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected abstract FilterResults performFiltering(CharSequence constraint);
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Invoked in the UI thread to publish the filtering results in the
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * user interface. Subclasses must implement this method to display the
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * results computed in {@link #performFiltering}.</p>
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param constraint the constraint used to filter the data
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param results the results of the filtering operation
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #filter(CharSequence, android.widget.Filter.FilterListener)
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #performFiltering(CharSequence)
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.widget.Filter.FilterResults
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected abstract void publishResults(CharSequence constraint,
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            FilterResults results);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Converts a value from the filtered set into a CharSequence. Subclasses
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * should override this method to convert their results. The default
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * implementation returns an empty String for null values or the default
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * String representation of the value.</p>
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param resultValue the value to convert to a CharSequence
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a CharSequence representing the value
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public CharSequence convertResultToString(Object resultValue) {
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return resultValue == null ? "" : resultValue.toString();
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Holds the results of a filtering operation. The results are the values
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * computed by the filtering operation and the number of these values.</p>
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected static class FilterResults {
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public FilterResults() {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // nothing to see here
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>Contains all the values computed by the filtering operation.</p>
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Object values;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>Contains the number of values computed by the filtering
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * operation.</p>
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int count;
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Listener used to receive a notification upon completion of a filtering
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * operation.</p>
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static interface FilterListener {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>Notifies the end of a filtering operation.</p>
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param count the number of values computed by the filter
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onFilterComplete(int count);
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Worker thread handler. When a new filtering request is posted from
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link android.widget.Filter#filter(CharSequence, android.widget.Filter.FilterListener)},
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * it is sent to this handler.</p>
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class RequestHandler extends Handler {
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public RequestHandler(Looper looper) {
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(looper);
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>Handles filtering requests by calling
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * {@link Filter#performFiltering} and then sending a message
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * with the results to the results handler.</p>
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param msg the filtering request
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int what = msg.what;
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Message message;
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (what) {
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case FILTER_TOKEN:
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    RequestArguments args = (RequestArguments) msg.obj;
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        args.results = performFiltering(args.constraint);
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (Exception e) {
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        args.results = new FilterResults();
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Log.w(LOG_TAG, "An exception occured during performFiltering()!", e);
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } finally {
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        message = mResultHandler.obtainMessage(what);
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        message.obj = args;
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        message.sendToTarget();
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
244b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    synchronized (mLock) {
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (mThreadHandler != null) {
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            Message finishMessage = mThreadHandler.obtainMessage(FINISH_TOKEN);
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mThreadHandler.sendMessageDelayed(finishMessage, 3000);
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case FINISH_TOKEN:
252b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    synchronized (mLock) {
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (mThreadHandler != null) {
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mThreadHandler.getLooper().quit();
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mThreadHandler = null;
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Handles the results of a filtering operation. The results are
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * handled in the UI thread.</p>
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class ResultsHandler extends Handler {
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>Messages received from the request handler are processed in the
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * UI thread. The processing involves calling
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * {@link Filter#publishResults(CharSequence,
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * android.widget.Filter.FilterResults)}
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * to post the results back in the UI and then notifying the listener,
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * if any.</p>
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param msg the filtering results
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            RequestArguments args = (RequestArguments) msg.obj;
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            publishResults(args.constraint, args.results);
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (args.listener != null) {
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int count = args.results != null ? args.results.count : -1;
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                args.listener.onFilterComplete(count);
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Holds the arguments of a filtering request as well as the results
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of the request.</p>
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static class RequestArguments {
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>The constraint used to filter the data.</p>
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharSequence constraint;
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>The listener to notify upon completion. Can be null.</p>
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        FilterListener listener;
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>The results of the filtering operation.</p>
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        FilterResults results;
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3108bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen
3118bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen    /**
3128bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen     * @hide
3138bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen     */
3148bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen    public interface Delayer {
3158bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen
3168bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen        /**
3178bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen         * @param constraint The constraint passed to {@link Filter#filter(CharSequence)}
3188bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen         * @return The delay that should be used for
3198bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen         *         {@link Handler#sendMessageDelayed(android.os.Message, long)}
3208bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen         */
3218bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen        long getPostingDelay(CharSequence constraint);
3228bf92e003d89be00c7cb9209b3ffba2658523734Karl Rosaen    }
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
324