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 */ 16 package com.android.contacts.common.list; 17 18 import android.content.AsyncTaskLoader; 19 import android.content.Context; 20 import android.content.pm.PackageManager; 21 import android.database.ContentObserver; 22 import android.database.Cursor; 23 import android.database.MatrixCursor; 24 import android.net.Uri; 25 import android.os.Handler; 26 import android.provider.ContactsContract.Directory; 27 import android.text.TextUtils; 28 import android.util.Log; 29 30 import com.android.contacts.common.R; 31 32 /** 33 * A specialized loader for the list of directories, see {@link Directory}. 34 */ 35 public class DirectoryListLoader extends AsyncTaskLoader<Cursor> { 36 37 private static final String TAG = "ContactEntryListAdapter"; 38 39 public static final int SEARCH_MODE_NONE = 0; 40 public static final int SEARCH_MODE_DEFAULT = 1; 41 public static final int SEARCH_MODE_CONTACT_SHORTCUT = 2; 42 public static final int SEARCH_MODE_DATA_SHORTCUT = 3; 43 44 private static final class DirectoryQuery { 45 public static final Uri URI = Directory.CONTENT_URI; 46 public static final String ORDER_BY = Directory._ID; 47 48 public static final String[] PROJECTION = { 49 Directory._ID, 50 Directory.PACKAGE_NAME, 51 Directory.TYPE_RESOURCE_ID, 52 Directory.DISPLAY_NAME, 53 Directory.PHOTO_SUPPORT, 54 }; 55 56 public static final int ID = 0; 57 public static final int PACKAGE_NAME = 1; 58 public static final int TYPE_RESOURCE_ID = 2; 59 public static final int DISPLAY_NAME = 3; 60 public static final int PHOTO_SUPPORT = 4; 61 } 62 63 // This is a virtual column created for a MatrixCursor. 64 public static final String DIRECTORY_TYPE = "directoryType"; 65 66 private static final String[] RESULT_PROJECTION = { 67 Directory._ID, 68 DIRECTORY_TYPE, 69 Directory.DISPLAY_NAME, 70 Directory.PHOTO_SUPPORT, 71 }; 72 73 private final ContentObserver mObserver = new ContentObserver(new Handler()) { 74 @Override 75 public void onChange(boolean selfChange) { 76 forceLoad(); 77 } 78 }; 79 80 private int mDirectorySearchMode; 81 private boolean mLocalInvisibleDirectoryEnabled; 82 83 private MatrixCursor mDefaultDirectoryList; 84 85 public DirectoryListLoader(Context context) { 86 super(context); 87 } 88 89 public void setDirectorySearchMode(int mode) { 90 mDirectorySearchMode = mode; 91 } 92 93 /** 94 * A flag that indicates whether the {@link Directory#LOCAL_INVISIBLE} directory should 95 * be included in the results. 96 */ 97 public void setLocalInvisibleDirectoryEnabled(boolean flag) { 98 this.mLocalInvisibleDirectoryEnabled = flag; 99 } 100 101 @Override 102 protected void onStartLoading() { 103 getContext().getContentResolver(). 104 registerContentObserver(Directory.CONTENT_URI, false, mObserver); 105 forceLoad(); 106 } 107 108 @Override 109 protected void onStopLoading() { 110 getContext().getContentResolver().unregisterContentObserver(mObserver); 111 } 112 113 @Override 114 public Cursor loadInBackground() { 115 if (mDirectorySearchMode == SEARCH_MODE_NONE) { 116 return getDefaultDirectories(); 117 } 118 119 MatrixCursor result = new MatrixCursor(RESULT_PROJECTION); 120 Context context = getContext(); 121 PackageManager pm = context.getPackageManager(); 122 String selection; 123 switch (mDirectorySearchMode) { 124 case SEARCH_MODE_DEFAULT: 125 selection = mLocalInvisibleDirectoryEnabled ? null 126 : (Directory._ID + "!=" + Directory.LOCAL_INVISIBLE); 127 break; 128 129 case SEARCH_MODE_CONTACT_SHORTCUT: 130 selection = Directory.SHORTCUT_SUPPORT + "=" + Directory.SHORTCUT_SUPPORT_FULL 131 + (mLocalInvisibleDirectoryEnabled ? "" 132 : (" AND " + Directory._ID + "!=" + Directory.LOCAL_INVISIBLE)); 133 break; 134 135 case SEARCH_MODE_DATA_SHORTCUT: 136 selection = Directory.SHORTCUT_SUPPORT + " IN (" 137 + Directory.SHORTCUT_SUPPORT_FULL + ", " 138 + Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY + ")" 139 + (mLocalInvisibleDirectoryEnabled ? "" 140 : (" AND " + Directory._ID + "!=" + Directory.LOCAL_INVISIBLE)); 141 break; 142 143 default: 144 throw new RuntimeException( 145 "Unsupported directory search mode: " + mDirectorySearchMode); 146 } 147 148 Cursor cursor = context.getContentResolver().query(DirectoryQuery.URI, 149 DirectoryQuery.PROJECTION, selection, null, DirectoryQuery.ORDER_BY); 150 try { 151 while(cursor.moveToNext()) { 152 long directoryId = cursor.getLong(DirectoryQuery.ID); 153 String directoryType = null; 154 155 String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME); 156 int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID); 157 if (!TextUtils.isEmpty(packageName) && typeResourceId != 0) { 158 try { 159 directoryType = pm.getResourcesForApplication(packageName) 160 .getString(typeResourceId); 161 } catch (Exception e) { 162 Log.e(TAG, "Cannot obtain directory type from package: " + packageName); 163 } 164 } 165 String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME); 166 int photoSupport = cursor.getInt(DirectoryQuery.PHOTO_SUPPORT); 167 result.addRow(new Object[]{directoryId, directoryType, displayName, photoSupport}); 168 } 169 } finally { 170 cursor.close(); 171 } 172 173 return result; 174 } 175 176 private Cursor getDefaultDirectories() { 177 if (mDefaultDirectoryList == null) { 178 mDefaultDirectoryList = new MatrixCursor(RESULT_PROJECTION); 179 mDefaultDirectoryList.addRow(new Object[] { 180 Directory.DEFAULT, 181 getContext().getString(R.string.contactsList), 182 null 183 }); 184 mDefaultDirectoryList.addRow(new Object[] { 185 Directory.LOCAL_INVISIBLE, 186 getContext().getString(R.string.local_invisible_directory), 187 null 188 }); 189 } 190 return mDefaultDirectoryList; 191 } 192 193 @Override 194 protected void onReset() { 195 stopLoading(); 196 } 197 } 198