1/*
2 * Copyright (C) 2015 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 */
16
17package com.android.messaging.datamodel;
18
19import android.content.Context;
20import android.database.Cursor;
21import android.net.Uri;
22import android.provider.ContactsContract;
23import android.provider.ContactsContract.Contacts;
24
25import com.android.messaging.util.FallbackStrategies;
26import com.android.messaging.util.FallbackStrategies.Strategy;
27import com.android.messaging.util.LogUtil;
28import com.android.messaging.util.OsUtil;
29
30/**
31 * Helper for querying frequent (and/or starred) contacts.
32 */
33public class FrequentContactsCursorQueryData extends CursorQueryData {
34    private static final String TAG = LogUtil.BUGLE_TAG;
35
36    private static class FrequentContactsCursorLoader extends BoundCursorLoader {
37        private final Uri mOriginalUri;
38
39        FrequentContactsCursorLoader(String bindingId, Context context, Uri uri,
40                String[] projection, String selection, String[] selectionArgs, String sortOrder) {
41            super(bindingId, context, uri, projection, selection, selectionArgs, sortOrder);
42            mOriginalUri = uri;
43        }
44
45        @Override
46        public Cursor loadInBackground() {
47            return FallbackStrategies
48                    .startWith(new PrimaryStrequentContactsQueryStrategy())
49                    .thenTry(new FrequentOnlyContactsQueryStrategy())
50                    .thenTry(new PhoneOnlyStrequentContactsQueryStrategy())
51                    .execute(null);
52        }
53
54        private abstract class StrequentContactsQueryStrategy implements Strategy<Void, Cursor> {
55            @Override
56            public Cursor execute(Void params) throws Exception {
57                final Uri uri = getUri();
58                if (uri != null) {
59                    setUri(uri);
60                }
61                return FrequentContactsCursorLoader.super.loadInBackground();
62            }
63            protected abstract Uri getUri();
64        }
65
66        private class PrimaryStrequentContactsQueryStrategy extends StrequentContactsQueryStrategy {
67            @Override
68            protected Uri getUri() {
69                // Use the original URI requested.
70                return mOriginalUri;
71            }
72        }
73
74        private class FrequentOnlyContactsQueryStrategy extends StrequentContactsQueryStrategy {
75            @Override
76            protected Uri getUri() {
77                // Some phones have a buggy implementation of the Contacts provider which crashes
78                // when we query for strequent (starred+frequent) contacts (b/17991485).
79                // If this happens, switch to just querying for frequent contacts.
80                return Contacts.CONTENT_FREQUENT_URI;
81            }
82        }
83
84        private class PhoneOnlyStrequentContactsQueryStrategy extends
85                StrequentContactsQueryStrategy {
86            @Override
87            protected Uri getUri() {
88                // Some 3rd party ROMs have content provider
89                // implementation where invalid SQL queries are returned for regular strequent
90                // queries. Using strequent_phone_only query as a fallback to display only phone
91                // contacts. This is the last-ditch effort; if this fails, we will display an
92                // empty frequent list (b/18354836).
93                final String strequentQueryParam = OsUtil.isAtLeastL() ?
94                        ContactsContract.STREQUENT_PHONE_ONLY : "strequent_phone_only";
95                // TODO: Handle enterprise contacts post M once contacts provider supports it
96                return Contacts.CONTENT_STREQUENT_URI.buildUpon()
97                        .appendQueryParameter(strequentQueryParam, "true").build();
98            }
99        }
100    }
101
102    public FrequentContactsCursorQueryData(Context context, String[] projection,
103            String selection, String[] selectionArgs, String sortOrder) {
104        // TODO: Handle enterprise contacts post M once contacts provider supports it
105        super(context, Contacts.CONTENT_STREQUENT_URI, projection, selection, selectionArgs,
106                sortOrder);
107    }
108
109    @Override
110    public BoundCursorLoader createBoundCursorLoader(String bindingId) {
111        return new FrequentContactsCursorLoader(bindingId, mContext, mUri, mProjection, mSelection,
112                mSelectionArgs, mSortOrder);
113    }
114}
115