1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.contacts.list;
17
18import android.content.Context;
19import android.content.CursorLoader;
20import android.database.Cursor;
21import android.database.CursorWrapper;
22import android.net.Uri;
23
24/**
25 * A specialized loader for the Join Contacts UI.  It executes two queries:
26 * join suggestions and (optionally) the full contact list.
27 *
28 * This loader also loads the "suggestion" cursor, which can be accessed with:
29 * {@code ((JoinContactLoaderResult) result).suggestionCursor }
30 */
31public class JoinContactLoader extends CursorLoader {
32
33    private String[] mProjection;
34    private Uri mSuggestionUri;
35
36    /**
37     * Actual returned class.  It's guaranteed that this loader always returns an instance of this
38     * class.  This class is needed to tie the lifecycle of the second cursor to that of the
39     * primary one.
40     *
41     * Note we can't change the result type of this loader itself, because CursorLoader
42     * extends AsyncTaskLoader<Cursor>, not AsyncTaskLoader<? extends Cursor>
43     */
44    public static class JoinContactLoaderResult extends CursorWrapper {
45        public final Cursor suggestionCursor;
46
47        public JoinContactLoaderResult(Cursor baseCursor, Cursor suggestionCursor) {
48            super(baseCursor);
49            this.suggestionCursor = suggestionCursor;
50        }
51
52        @Override
53        public void close() {
54            try {
55                if (suggestionCursor != null) {
56                    suggestionCursor.close();
57                }
58            } finally {
59                if (super.getWrappedCursor() != null) {
60                    super.close();
61                }
62            }
63        }
64    }
65
66    public JoinContactLoader(Context context) {
67        super(context, null, null, null, null, null);
68    }
69
70    public void setSuggestionUri(Uri uri) {
71        this.mSuggestionUri = uri;
72    }
73
74    @Override
75    public void setProjection(String[] projection) {
76        super.setProjection(projection);
77        this.mProjection = projection;
78    }
79
80    @Override
81    public Cursor loadInBackground() {
82        // First execute the suggestions query, then call super.loadInBackground
83        // to load the entire list
84        final Cursor suggestionsCursor = getContext().getContentResolver()
85                .query(mSuggestionUri, mProjection, null, null, null);
86        if (suggestionsCursor == null) {
87            return null;
88        }
89        Cursor cursorToClose = suggestionsCursor;
90        try {
91            final Cursor baseCursor = super.loadInBackground();
92            if (baseCursor != null) {
93                final JoinContactLoaderResult result =
94                        new JoinContactLoaderResult(baseCursor, suggestionsCursor);
95                cursorToClose = null;
96                return result;
97            }
98        } finally {
99            if (cursorToClose != null) {
100                cursorToClose.close();
101            }
102        }
103        return null;
104    }
105}
106