19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 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
197b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbyeimport android.annotation.ArrayRes;
207b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbyeimport android.annotation.IdRes;
217b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbyeimport android.annotation.LayoutRes;
22417ee5ba89f7e0fe5efd34fce74bf1ee5923d976Tor Norbyeimport android.annotation.NonNull;
239e623b64b939944fa336264e2c8a555b817e4c2fAlan Viveretteimport android.annotation.Nullable;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
25b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viveretteimport android.content.res.Resources;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
27b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viveretteimport android.view.ContextThemeWrapper;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.LayoutInflater;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
348c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauerimport java.util.Collection;
35c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Projectimport java.util.Collections;
36be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunneimport java.util.Comparator;
37be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunneimport java.util.List;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
40d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * You can use this adapter to provide views for an {@link AdapterView},
41d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * Returns a view for each object in a collection of data objects you
42d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * provide, and can be used with list-based user interface widgets such as
43d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * {@link ListView} or {@link Spinner}.
44d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * <p>
45d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * By default, the array adapter creates a view by calling {@link Object#toString()} on each
46d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * data object in the collection you provide, and places the result in a TextView.
47d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * You may also customize what type of view is used for the data object in the collection.
48d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * To customize what type of view is used for the data object,
49d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * override {@link #getView(int, View, ViewGroup)}
50d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * and inflate a view resource.
51d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * For a code example, see
52d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * the <a href="https://developer.android.com/samples/CustomChoiceList/index.html">
53d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * CustomChoiceList</a> sample.
54d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * </p>
55d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * <p>
56d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * For an example of using an array adapter with a ListView, see the
57d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * <a href="{@docRoot}guide/topics/ui/declaring-layout.html#AdapterViews">
58d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * Adapter Views</a> guide.
59d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * </p>
60d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * <p>
61d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * For an example of using an array adapter with a Spinner, see the
62d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * <a href="{@docRoot}guide/topics/ui/controls/spinner.html">Spinners</a> guide.
63d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * </p>
64d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * <p class="note"><strong>Note:</strong>
65d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * If you are considering using array adapter with a ListView, consider using
66d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * {@link android.support.v7.widget.RecyclerView} instead.
67d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * RecyclerView offers similar features with better performance and more flexibility than
68d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * ListView provides.
69d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * See the
70d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * <a href="https://developer.android.com/guide/topics/ui/layout/recyclerview.html">
71d7ef95af6069fcbd563aa9862a3d931e569cb54eJoe Fernandez * Recycler View</a> guide.</p>
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
732add9bcf8c33c59f300551bdb0671bbff0b55794Alan Viverettepublic class ArrayAdapter<T> extends BaseAdapter implements Filterable, ThemedSpinnerAdapter {
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Lock used to modify the content of {@link #mObjects}. Any write operation
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * performed on the array should be synchronized on this lock. This lock is also
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * used by the filter (see {@link #getFilter()} to make a synchronized copy of
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the original array of data.
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Object mLock = new Object();
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
827d5967e55edc8c3dfdf72aea263b5543a2b6e801Alan Viverette    private final LayoutInflater mInflater;
837d5967e55edc8c3dfdf72aea263b5543a2b6e801Alan Viverette
849e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    private final Context mContext;
857d5967e55edc8c3dfdf72aea263b5543a2b6e801Alan Viverette
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The resource indicating what views to inflate to display the content of this
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * array adapter.
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
909e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    private final int mResource;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The resource indicating what views to inflate to display the content of this
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * array adapter in a drop down widget.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mDropDownResource;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
999e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     * Contains the list of objects that represent the data of this ArrayAdapter.
1009e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     * The content of this list is referred to as "the array" in the documentation.
1019e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     */
1029e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    private List<T> mObjects;
1039e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette
1049e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    /**
1057e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme     * Indicates whether the contents of {@link #mObjects} came from static resources.
1067e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme     */
1077e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme    private boolean mObjectsFromResources;
1087e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme
1097e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme    /**
1109e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     * If the inflated resource is not a TextView, {@code mFieldId} is used to find
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a TextView inside the inflated views hierarchy. This field must contain the
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * identifier that matches the one defined in the resource file.
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mFieldId = 0;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Indicates whether or not {@link #notifyDataSetChanged()} must be called whenever
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #mObjects} is modified.
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mNotifyOnChange = true;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
122be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne    // A copy of the original mObjects array, initialized from and then used instead as soon as
123be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne    // the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayList<T> mOriginalValues;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayFilter mFilter;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
127b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette    /** Layout inflater used for {@link #getDropDownView(int, View, ViewGroup)}. */
128b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette    private LayoutInflater mDropDownInflater;
129b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructor
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context The current context.
1349c5d1b17bfae81c282cec8954e66963c86c81438Romain Guy     * @param resource The resource ID for a layout file containing a TextView to use when
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                 instantiating views.
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1379e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource) {
1389e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette        this(context, resource, 0, new ArrayList<>());
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructor
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context The current context.
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param resource The resource ID for a layout file containing a layout to use when
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                 instantiating views.
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param textViewResourceId The id of the TextView within the layout resource to be populated
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1499e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
1509e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette            @IdRes int textViewResourceId) {
1519e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette        this(context, resource, textViewResourceId, new ArrayList<>());
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructor
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context The current context.
1589c5d1b17bfae81c282cec8954e66963c86c81438Romain Guy     * @param resource The resource ID for a layout file containing a TextView to use when
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                 instantiating views.
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param objects The objects to represent in the ListView.
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1629e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull T[] objects) {
163b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        this(context, resource, 0, Arrays.asList(objects));
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructor
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context The current context.
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param resource The resource ID for a layout file containing a layout to use when
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                 instantiating views.
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param textViewResourceId The id of the TextView within the layout resource to be populated
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param objects The objects to represent in the ListView.
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1759e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
1769e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette            @IdRes int textViewResourceId, @NonNull T[] objects) {
177b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        this(context, resource, textViewResourceId, Arrays.asList(objects));
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructor
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context The current context.
1849c5d1b17bfae81c282cec8954e66963c86c81438Romain Guy     * @param resource The resource ID for a layout file containing a TextView to use when
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                 instantiating views.
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param objects The objects to represent in the ListView.
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1889e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
1899e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette            @NonNull List<T> objects) {
190b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        this(context, resource, 0, objects);
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructor
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context The current context.
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param resource The resource ID for a layout file containing a layout to use when
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                 instantiating views.
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param textViewResourceId The id of the TextView within the layout resource to be populated
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param objects The objects to represent in the ListView.
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2029e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
2039e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette            @IdRes int textViewResourceId, @NonNull List<T> objects) {
2047e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme        this(context, resource, textViewResourceId, objects, false);
2057e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme    }
2067e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme
2077e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme    private ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
2087e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme            @IdRes int textViewResourceId, @NonNull List<T> objects, boolean objsFromResources) {
209b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        mContext = context;
210b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        mInflater = LayoutInflater.from(context);
211b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        mResource = mDropDownResource = resource;
212b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        mObjects = objects;
2137e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme        mObjectsFromResources = objsFromResources;
214b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        mFieldId = textViewResourceId;
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Adds the specified object at the end of the array.
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param object The object to add at the end of the array.
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2229e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public void add(@Nullable T object) {
223be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        synchronized (mLock) {
224be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            if (mOriginalValues != null) {
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mOriginalValues.add(object);
226be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            } else {
227be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne                mObjects.add(object);
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2297e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme            mObjectsFromResources = false;
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
231be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        if (mNotifyOnChange) notifyDataSetChanged();
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2358c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer     * Adds the specified Collection at the end of the array.
2368c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer     *
2378c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer     * @param collection The Collection to add at the end of the array.
2389e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
2399e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     *         is not supported by this list
2409e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     * @throws ClassCastException if the class of an element of the specified
2419e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     *         collection prevents it from being added to this list
2429e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     * @throws NullPointerException if the specified collection contains one
2439e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     *         or more null elements and this list does not permit null
2449e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     *         elements, or if the specified collection is null
2459e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     * @throws IllegalArgumentException if some property of an element of the
2469e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     *         specified collection prevents it from being added to this list
2479e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette     */
2489e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public void addAll(@NonNull Collection<? extends T> collection) {
249be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        synchronized (mLock) {
250be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            if (mOriginalValues != null) {
2518c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer                mOriginalValues.addAll(collection);
252be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            } else {
253be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne                mObjects.addAll(collection);
2548c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer            }
2557e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme            mObjectsFromResources = false;
2568c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer        }
257be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        if (mNotifyOnChange) notifyDataSetChanged();
2588c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer    }
2598c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer
2608c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer    /**
2618c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer     * Adds the specified items at the end of the array.
2628c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer     *
2638c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer     * @param items The items to add at the end of the array.
2648c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer     */
2658c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer    public void addAll(T ... items) {
266be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        synchronized (mLock) {
267be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            if (mOriginalValues != null) {
26895a78c38373bb99258d83a6ab2c92825d979f200Romain Guy                Collections.addAll(mOriginalValues, items);
269be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            } else {
27095a78c38373bb99258d83a6ab2c92825d979f200Romain Guy                Collections.addAll(mObjects, items);
2718c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer            }
2727e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme            mObjectsFromResources = false;
2738c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer        }
274be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        if (mNotifyOnChange) notifyDataSetChanged();
2758c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer    }
2768c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer
2778c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer    /**
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Inserts the specified object at the specified index in the array.
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param object The object to insert into the array.
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index The index at which the object must be inserted.
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2839e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public void insert(@Nullable T object, int index) {
284be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        synchronized (mLock) {
285be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            if (mOriginalValues != null) {
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mOriginalValues.add(index, object);
287be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            } else {
288be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne                mObjects.add(index, object);
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2907e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme            mObjectsFromResources = false;
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
292be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        if (mNotifyOnChange) notifyDataSetChanged();
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Removes the specified object from the array.
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param object The object to remove.
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3009e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public void remove(@Nullable T object) {
301be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        synchronized (mLock) {
302be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            if (mOriginalValues != null) {
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mOriginalValues.remove(object);
304be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            } else {
305be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne                mObjects.remove(object);
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3077e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme            mObjectsFromResources = false;
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mNotifyOnChange) notifyDataSetChanged();
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Remove all elements from the list.
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void clear() {
316be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        synchronized (mLock) {
317be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            if (mOriginalValues != null) {
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mOriginalValues.clear();
319be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            } else {
320be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne                mObjects.clear();
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3227e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme            mObjectsFromResources = false;
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mNotifyOnChange) notifyDataSetChanged();
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
328c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project     * Sorts the content of this adapter using the specified comparator.
329c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project     *
330c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project     * @param comparator The comparator used to sort the objects contained
331c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project     *        in this adapter.
332c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project     */
3339e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public void sort(@NonNull Comparator<? super T> comparator) {
334be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        synchronized (mLock) {
335be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            if (mOriginalValues != null) {
336be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne                Collections.sort(mOriginalValues, comparator);
337be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            } else {
338be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne                Collections.sort(mObjects, comparator);
339be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne            }
340be2c4f92a990ca48ad6ede252343dd9574dfe505Gilles Debunne        }
3418c582ef859fcbbb97623d22024c3ecb32b65c5efChristian Mehlmauer        if (mNotifyOnChange) notifyDataSetChanged();
342c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project    }
343c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void notifyDataSetChanged() {
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.notifyDataSetChanged();
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNotifyOnChange = true;
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
35142c69b9ce4ead51fc5e2a0ed55c40b498893047eYigit Boyar     * Control whether methods that change the list ({@link #add}, {@link #addAll(Collection)},
35242c69b9ce4ead51fc5e2a0ed55c40b498893047eYigit Boyar     * {@link #addAll(Object[])}, {@link #insert}, {@link #remove}, {@link #clear},
35342c69b9ce4ead51fc5e2a0ed55c40b498893047eYigit Boyar     * {@link #sort(Comparator)}) automatically call {@link #notifyDataSetChanged}.  If set to
35442c69b9ce4ead51fc5e2a0ed55c40b498893047eYigit Boyar     * false, caller must manually call notifyDataSetChanged() to have the changes
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * reflected in the attached view.
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The default is true, and calling notifyDataSetChanged()
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * resets the flag to true.
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param notifyOnChange if true, modifications to the list will
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                       automatically call {@link
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                       #notifyDataSetChanged}
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setNotifyOnChange(boolean notifyOnChange) {
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNotifyOnChange = notifyOnChange;
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the context associated with this array adapter. The context is used
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to create views from the resource passed to the constructor.
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The Context associated with this adapter.
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3749e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public @NonNull Context getContext() {
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mContext;
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3789e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    @Override
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getCount() {
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mObjects.size();
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3839e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    @Override
3849e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public @Nullable T getItem(int position) {
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mObjects.get(position);
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the position of the specified item in the array.
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param item The item to retrieve the position of.
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The position of the specified item.
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3959e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public int getPosition(@Nullable T item) {
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mObjects.indexOf(item);
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3999e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    @Override
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public long getItemId(int position) {
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return position;
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4049e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    @Override
4059e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public @NonNull View getView(int position, @Nullable View convertView,
4069e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette            @NonNull ViewGroup parent) {
407b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        return createViewFromResource(mInflater, position, convertView, parent, mResource);
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4109e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    private @NonNull View createViewFromResource(@NonNull LayoutInflater inflater, int position,
4119e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette            @Nullable View convertView, @NonNull ViewGroup parent, int resource) {
4129e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette        final View view;
4139e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette        final TextView text;
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (convertView == null) {
416b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette            view = inflater.inflate(resource, parent, false);
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            view = convertView;
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mFieldId == 0) {
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                //  If no custom field is assigned, assume the whole resource is a TextView
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                text = (TextView) view;
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                //  Otherwise, find the TextView field within the layout
4278e1a72964517bfd01d8e650453ef41e22f770f21Alan Viverette                text = view.findViewById(mFieldId);
4289e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette
4299e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                if (text == null) {
4309e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                    throw new RuntimeException("Failed to find view with ID "
4319e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                            + mContext.getResources().getResourceName(mFieldId)
4329e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                            + " in item layout");
4339e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (ClassCastException e) {
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalStateException(
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    "ArrayAdapter requires the resource ID to be a TextView", e);
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4419e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette        final T item = getItem(position);
442b5d9132d4eaeed13b236501e4af3f99416b4be78Daisuke Miyakawa        if (item instanceof CharSequence) {
4439e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette            text.setText((CharSequence) item);
444b5d9132d4eaeed13b236501e4af3f99416b4be78Daisuke Miyakawa        } else {
445b5d9132d4eaeed13b236501e4af3f99416b4be78Daisuke Miyakawa            text.setText(item.toString());
446b5d9132d4eaeed13b236501e4af3f99416b4be78Daisuke Miyakawa        }
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return view;
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>Sets the layout resource to create the drop down views.</p>
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param resource the layout resource defining the drop down views
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getDropDownView(int, android.view.View, android.view.ViewGroup)
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4577b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye    public void setDropDownViewResource(@LayoutRes int resource) {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this.mDropDownResource = resource;
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
462b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette     * Sets the {@link Resources.Theme} against which drop-down views are
463b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette     * inflated.
464b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette     * <p>
465b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette     * By default, drop-down views are inflated against the theme of the
466b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette     * {@link Context} passed to the adapter's constructor.
467b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette     *
468b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette     * @param theme the theme against which to inflate drop-down views or
469b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette     *              {@code null} to use the theme from the adapter's context
470b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette     * @see #getDropDownView(int, View, ViewGroup)
471b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette     */
472b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette    @Override
4739e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public void setDropDownViewTheme(@Nullable Resources.Theme theme) {
474b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        if (theme == null) {
475b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette            mDropDownInflater = null;
476b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        } else if (theme == mInflater.getContext().getTheme()) {
477b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette            mDropDownInflater = mInflater;
478b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        } else {
479b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette            final Context context = new ContextThemeWrapper(mContext, theme);
480b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette            mDropDownInflater = LayoutInflater.from(context);
481b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        }
482b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette    }
483b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette
484b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette    @Override
4859e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public @Nullable Resources.Theme getDropDownViewTheme() {
486b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        return mDropDownInflater == null ? null : mDropDownInflater.getContext().getTheme();
487b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette    }
488b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4909e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public View getDropDownView(int position, @Nullable View convertView,
4919e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette            @NonNull ViewGroup parent) {
492b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        final LayoutInflater inflater = mDropDownInflater == null ? mInflater : mDropDownInflater;
493b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        return createViewFromResource(inflater, position, convertView, parent, mDropDownResource);
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a new ArrayAdapter from external resources. The content of the array is
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * obtained through {@link android.content.res.Resources#getTextArray(int)}.
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context The application's environment.
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param textArrayResId The identifier of the array to use as the data source.
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param textViewResId The identifier of the layout used to create views.
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return An ArrayAdapter<CharSequence>.
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5069e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public static @NonNull ArrayAdapter<CharSequence> createFromResource(@NonNull Context context,
5077b9c912f536925ac6ec43935d6e97506851b33d6Tor Norbye            @ArrayRes int textArrayResId, @LayoutRes int textViewResId) {
5089e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette        final CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
5097e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme        return new ArrayAdapter<>(context, textViewResId, 0, Arrays.asList(strings), true);
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5129e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    @Override
5139e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette    public @NonNull Filter getFilter() {
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFilter == null) {
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFilter = new ArrayFilter();
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mFilter;
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5217e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme     * {@inheritDoc}
5227e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme     *
5237e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme     * @return values from the string array used by {@link #createFromResource(Context, int, int)},
5247e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme     * or {@code null} if object was created otherwsie or if contents were dynamically changed after
5257e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme     * creation.
5267e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme     */
5277e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme    @Override
5287e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme    public CharSequence[] getAutofillOptions() {
5297e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme        if (!mObjectsFromResources || mObjects == null || mObjects.isEmpty()) {
5307e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme            return null;
5317e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme        }
5327e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme        final int size = mObjects.size();
5337e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme        final CharSequence[] options = new CharSequence[size];
5347e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme        mObjects.toArray(options);
5357e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme        return options;
5367e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme    }
5377e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme
5387e4c205d8f7e6746ab6e0701e4d7776a2cdd6aa0Felipe Leme    /**
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>An array filter constrains the content of the array adapter with
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a prefix. Each item that does not start with the supplied prefix
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is removed from the list.</p>
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class ArrayFilter extends Filter {
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        protected FilterResults performFiltering(CharSequence prefix) {
5469e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette            final FilterResults results = new FilterResults();
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mOriginalValues == null) {
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                synchronized (mLock) {
5509e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                    mOriginalValues = new ArrayList<>(mObjects);
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (prefix == null || prefix.length() == 0) {
5559e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                final ArrayList<T> list;
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                synchronized (mLock) {
5579e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                    list = new ArrayList<>(mOriginalValues);
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
55995a78c38373bb99258d83a6ab2c92825d979f200Romain Guy                results.values = list;
56095a78c38373bb99258d83a6ab2c92825d979f200Romain Guy                results.count = list.size();
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5629e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                final String prefixString = prefix.toString().toLowerCase();
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5649e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                final ArrayList<T> values;
56595a78c38373bb99258d83a6ab2c92825d979f200Romain Guy                synchronized (mLock) {
5669e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                    values = new ArrayList<>(mOriginalValues);
56795a78c38373bb99258d83a6ab2c92825d979f200Romain Guy                }
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
56995a78c38373bb99258d83a6ab2c92825d979f200Romain Guy                final int count = values.size();
5709e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                final ArrayList<T> newValues = new ArrayList<>();
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < count; i++) {
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final T value = values.get(i);
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final String valueText = value.toString().toLowerCase();
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // First match against the whole, non-splitted value
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (valueText.startsWith(prefixString)) {
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        newValues.add(value);
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final String[] words = valueText.split(" ");
5819e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                        for (String word : words) {
5829e623b64b939944fa336264e2c8a555b817e4c2fAlan Viverette                            if (word.startsWith(prefixString)) {
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                newValues.add(value);
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                break;
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                results.values = newValues;
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                results.count = newValues.size();
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return results;
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        protected void publishResults(CharSequence constraint, FilterResults results) {
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //noinspection unchecked
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mObjects = (List<T>) results.values;
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (results.count > 0) {
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                notifyDataSetChanged();
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                notifyDataSetInvalidated();
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
609