/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.messaging.datamodel; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; import com.android.messaging.util.FallbackStrategies; import com.android.messaging.util.FallbackStrategies.Strategy; import com.android.messaging.util.LogUtil; import com.android.messaging.util.OsUtil; /** * Helper for querying frequent (and/or starred) contacts. */ public class FrequentContactsCursorQueryData extends CursorQueryData { private static final String TAG = LogUtil.BUGLE_TAG; private static class FrequentContactsCursorLoader extends BoundCursorLoader { private final Uri mOriginalUri; FrequentContactsCursorLoader(String bindingId, Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { super(bindingId, context, uri, projection, selection, selectionArgs, sortOrder); mOriginalUri = uri; } @Override public Cursor loadInBackground() { return FallbackStrategies .startWith(new PrimaryStrequentContactsQueryStrategy()) .thenTry(new FrequentOnlyContactsQueryStrategy()) .thenTry(new PhoneOnlyStrequentContactsQueryStrategy()) .execute(null); } private abstract class StrequentContactsQueryStrategy implements Strategy { @Override public Cursor execute(Void params) throws Exception { final Uri uri = getUri(); if (uri != null) { setUri(uri); } return FrequentContactsCursorLoader.super.loadInBackground(); } protected abstract Uri getUri(); } private class PrimaryStrequentContactsQueryStrategy extends StrequentContactsQueryStrategy { @Override protected Uri getUri() { // Use the original URI requested. return mOriginalUri; } } private class FrequentOnlyContactsQueryStrategy extends StrequentContactsQueryStrategy { @Override protected Uri getUri() { // Some phones have a buggy implementation of the Contacts provider which crashes // when we query for strequent (starred+frequent) contacts (b/17991485). // If this happens, switch to just querying for frequent contacts. return Contacts.CONTENT_FREQUENT_URI; } } private class PhoneOnlyStrequentContactsQueryStrategy extends StrequentContactsQueryStrategy { @Override protected Uri getUri() { // Some 3rd party ROMs have content provider // implementation where invalid SQL queries are returned for regular strequent // queries. Using strequent_phone_only query as a fallback to display only phone // contacts. This is the last-ditch effort; if this fails, we will display an // empty frequent list (b/18354836). final String strequentQueryParam = OsUtil.isAtLeastL() ? ContactsContract.STREQUENT_PHONE_ONLY : "strequent_phone_only"; // TODO: Handle enterprise contacts post M once contacts provider supports it return Contacts.CONTENT_STREQUENT_URI.buildUpon() .appendQueryParameter(strequentQueryParam, "true").build(); } } } public FrequentContactsCursorQueryData(Context context, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO: Handle enterprise contacts post M once contacts provider supports it super(context, Contacts.CONTENT_STREQUENT_URI, projection, selection, selectionArgs, sortOrder); } @Override public BoundCursorLoader createBoundCursorLoader(String bindingId) { return new FrequentContactsCursorLoader(bindingId, mContext, mUri, mProjection, mSelection, mSelectionArgs, mSortOrder); } }