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 17 package com.android.messaging.datamodel; 18 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.net.Uri; 22 import android.provider.ContactsContract; 23 import android.provider.ContactsContract.Contacts; 24 25 import com.android.messaging.util.FallbackStrategies; 26 import com.android.messaging.util.FallbackStrategies.Strategy; 27 import com.android.messaging.util.LogUtil; 28 import com.android.messaging.util.OsUtil; 29 30 /** 31 * Helper for querying frequent (and/or starred) contacts. 32 */ 33 public 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 FrequentContactsCursorLoader(String bindingId, Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)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 loadInBackground()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 execute(Void params)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 } getUri()63 protected abstract Uri getUri(); 64 } 65 66 private class PrimaryStrequentContactsQueryStrategy extends StrequentContactsQueryStrategy { 67 @Override getUri()68 protected Uri getUri() { 69 // Use the original URI requested. 70 return mOriginalUri; 71 } 72 } 73 74 private class FrequentOnlyContactsQueryStrategy extends StrequentContactsQueryStrategy { 75 @Override getUri()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 getUri()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 FrequentContactsCursorQueryData(Context context, String[] projection, String selection, String[] selectionArgs, String sortOrder)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 createBoundCursorLoader(String bindingId)110 public BoundCursorLoader createBoundCursorLoader(String bindingId) { 111 return new FrequentContactsCursorLoader(bindingId, mContext, mUri, mProjection, mSelection, 112 mSelectionArgs, mSortOrder); 113 } 114 } 115