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 DirectoryListLoader(Context context)85 public DirectoryListLoader(Context context) { 86 super(context); 87 } 88 setDirectorySearchMode(int mode)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 */ setLocalInvisibleDirectoryEnabled(boolean flag)97 public void setLocalInvisibleDirectoryEnabled(boolean flag) { 98 this.mLocalInvisibleDirectoryEnabled = flag; 99 } 100 101 @Override onStartLoading()102 protected void onStartLoading() { 103 getContext().getContentResolver(). 104 registerContentObserver(Directory.CONTENT_URI, false, mObserver); 105 forceLoad(); 106 } 107 108 @Override onStopLoading()109 protected void onStopLoading() { 110 getContext().getContentResolver().unregisterContentObserver(mObserver); 111 } 112 113 @Override loadInBackground()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 Cursor cursor = null; 148 try { 149 cursor = context.getContentResolver().query(DirectoryQuery.URI, 150 DirectoryQuery.PROJECTION, selection, null, DirectoryQuery.ORDER_BY); 151 152 if (cursor == null) { 153 return result; 154 } 155 156 while(cursor.moveToNext()) { 157 long directoryId = cursor.getLong(DirectoryQuery.ID); 158 String directoryType = null; 159 160 String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME); 161 int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID); 162 if (!TextUtils.isEmpty(packageName) && typeResourceId != 0) { 163 try { 164 directoryType = pm.getResourcesForApplication(packageName) 165 .getString(typeResourceId); 166 } catch (Exception e) { 167 Log.e(TAG, "Cannot obtain directory type from package: " + packageName); 168 } 169 } 170 String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME); 171 int photoSupport = cursor.getInt(DirectoryQuery.PHOTO_SUPPORT); 172 result.addRow(new Object[]{directoryId, directoryType, displayName, photoSupport}); 173 } 174 } catch (RuntimeException e) { 175 Log.w(TAG, "Runtime Exception when querying directory"); 176 } finally { 177 if (cursor != null) { 178 cursor.close(); 179 } 180 } 181 182 return result; 183 } 184 getDefaultDirectories()185 private Cursor getDefaultDirectories() { 186 if (mDefaultDirectoryList == null) { 187 mDefaultDirectoryList = new MatrixCursor(RESULT_PROJECTION); 188 mDefaultDirectoryList.addRow(new Object[] { 189 Directory.DEFAULT, 190 getContext().getString(R.string.contactsList), 191 null 192 }); 193 mDefaultDirectoryList.addRow(new Object[] { 194 Directory.LOCAL_INVISIBLE, 195 getContext().getString(R.string.local_invisible_directory), 196 null 197 }); 198 } 199 return mDefaultDirectoryList; 200 } 201 202 @Override onReset()203 protected void onReset() { 204 stopLoading(); 205 } 206 } 207