1ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/* 2ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Copyright (C) 2010 The Android Open Source Project 3ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 4ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License"); 5ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * you may not use this file except in compliance with the License. 6ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * You may obtain a copy of the License at 7ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 8ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * http://www.apache.org/licenses/LICENSE-2.0 9ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 10ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Unless required by applicable law or agreed to in writing, software 11ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS, 12ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * See the License for the specific language governing permissions and 14ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * limitations under the License. 15ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 16ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpackage com.android.contacts.common.list; 17ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 18ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.AsyncTaskLoader; 19ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.Context; 20ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.pm.PackageManager; 21ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.database.ContentObserver; 22ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.database.Cursor; 23ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.database.MatrixCursor; 24ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.net.Uri; 25ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.os.Handler; 26ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.provider.ContactsContract.Directory; 27ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.TextUtils; 28ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.R; 29c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanianimport com.android.dialer.common.LogUtil; 30c3d3c3dfbcf96f6db92b747463ac84ee244a0c85linyuhimport com.android.dialer.common.cp2.DirectoryCompat; 31c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanianimport com.android.dialer.util.PermissionsUtil; 32ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 33ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/** A specialized loader for the list of directories, see {@link Directory}. */ 34ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpublic class DirectoryListLoader extends AsyncTaskLoader<Cursor> { 35ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 36ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final int SEARCH_MODE_NONE = 0; 37ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final int SEARCH_MODE_DEFAULT = 1; 38ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final int SEARCH_MODE_CONTACT_SHORTCUT = 2; 39ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final int SEARCH_MODE_DATA_SHORTCUT = 3; 40ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This is a virtual column created for a MatrixCursor. 41ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final String DIRECTORY_TYPE = "directoryType"; 42ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final String[] RESULT_PROJECTION = { 43ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Directory._ID, DIRECTORY_TYPE, Directory.DISPLAY_NAME, Directory.PHOTO_SUPPORT, 44ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian }; 45ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final ContentObserver mObserver = 46ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new ContentObserver(new Handler()) { 47ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 48ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onChange(boolean selfChange) { 49ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian forceLoad(); 50ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 51ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian }; 52ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private int mDirectorySearchMode; 53ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private boolean mLocalInvisibleDirectoryEnabled; 54ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private MatrixCursor mDefaultDirectoryList; 55ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 56ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public DirectoryListLoader(Context context) { 57ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian super(context); 58ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 59ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 60ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void setDirectorySearchMode(int mode) { 61ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDirectorySearchMode = mode; 62ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 63ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 64ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 65ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * A flag that indicates whether the {@link Directory#LOCAL_INVISIBLE} directory should be 66ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * included in the results. 67ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 68ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void setLocalInvisibleDirectoryEnabled(boolean flag) { 69ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian this.mLocalInvisibleDirectoryEnabled = flag; 70ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 71ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 72ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 73ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian protected void onStartLoading() { 74c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian if (PermissionsUtil.hasContactsReadPermissions(getContext())) { 75c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian getContext() 76c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian .getContentResolver() 77c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian .registerContentObserver(DirectoryQuery.URI, false, mObserver); 78c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian } else { 79c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian LogUtil.w("DirectoryListLoader.onStartLoading", "contacts permission not available."); 80c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian } 81ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian forceLoad(); 82ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 83ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 84ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 85ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian protected void onStopLoading() { 86ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getContext().getContentResolver().unregisterContentObserver(mObserver); 87ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 88ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 89ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 90ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public Cursor loadInBackground() { 91ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mDirectorySearchMode == SEARCH_MODE_NONE) { 92ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return getDefaultDirectories(); 93ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 94ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 95ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian MatrixCursor result = new MatrixCursor(RESULT_PROJECTION); 96ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Context context = getContext(); 97ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PackageManager pm = context.getPackageManager(); 98ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String selection; 99ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian switch (mDirectorySearchMode) { 100ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian case SEARCH_MODE_DEFAULT: 101ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian selection = null; 102ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian break; 103ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 104ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian case SEARCH_MODE_CONTACT_SHORTCUT: 105ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian selection = Directory.SHORTCUT_SUPPORT + "=" + Directory.SHORTCUT_SUPPORT_FULL; 106ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian break; 107ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 108ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian case SEARCH_MODE_DATA_SHORTCUT: 109ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian selection = 110ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Directory.SHORTCUT_SUPPORT 111ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian + " IN (" 112ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian + Directory.SHORTCUT_SUPPORT_FULL 113ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian + ", " 114ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian + Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY 115ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian + ")"; 116ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian break; 117ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 118ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian default: 119ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian throw new RuntimeException("Unsupported directory search mode: " + mDirectorySearchMode); 120ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 121ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Cursor cursor = null; 122ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian try { 123ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian cursor = 124ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian context 125ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .getContentResolver() 126ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .query( 127ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian DirectoryQuery.URI, 128ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian DirectoryQuery.PROJECTION, 129ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian selection, 130ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian null, 131ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian DirectoryQuery.ORDER_BY); 132ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 133ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (cursor == null) { 134ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return result; 135ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 136ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 137ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian while (cursor.moveToNext()) { 138ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian long directoryId = cursor.getLong(DirectoryQuery.ID); 139ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!mLocalInvisibleDirectoryEnabled && DirectoryCompat.isInvisibleDirectory(directoryId)) { 140ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian continue; 141ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 142ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String directoryType = null; 143ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 144ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME); 145ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID); 146ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!TextUtils.isEmpty(packageName) && typeResourceId != 0) { 147ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian try { 148ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian directoryType = pm.getResourcesForApplication(packageName).getString(typeResourceId); 149ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } catch (Exception e) { 150c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian LogUtil.e( 151c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian "ContactEntryListAdapter.loadInBackground", 152c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian "cannot obtain directory type from package: " + packageName); 153ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 154ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 155ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME); 156ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int photoSupport = cursor.getInt(DirectoryQuery.PHOTO_SUPPORT); 157ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian result.addRow(new Object[] {directoryId, directoryType, displayName, photoSupport}); 158ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 159ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } catch (RuntimeException e) { 160c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian LogUtil.w( 161c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian "ContactEntryListAdapter.loadInBackground", "runtime exception when querying directory"); 162ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } finally { 163ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (cursor != null) { 164ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian cursor.close(); 165ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 166ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 167ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 168ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return result; 169ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 170ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 171ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Cursor getDefaultDirectories() { 172ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mDefaultDirectoryList == null) { 173ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDefaultDirectoryList = new MatrixCursor(RESULT_PROJECTION); 174ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDefaultDirectoryList.addRow( 175ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new Object[] {Directory.DEFAULT, getContext().getString(R.string.contactsList), null}); 176ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDefaultDirectoryList.addRow( 177ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new Object[] { 178ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Directory.LOCAL_INVISIBLE, 179ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getContext().getString(R.string.local_invisible_directory), 180ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian null 181ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian }); 182ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 183ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return mDefaultDirectoryList; 184ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 185ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 186ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 187ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian protected void onReset() { 188ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian stopLoading(); 189ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 190ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 191ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final class DirectoryQuery { 192ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 193ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final Uri URI = DirectoryCompat.getContentUri(); 194ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final String ORDER_BY = Directory._ID; 195ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 196ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final String[] PROJECTION = { 197ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Directory._ID, 198ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Directory.PACKAGE_NAME, 199ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Directory.TYPE_RESOURCE_ID, 200ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Directory.DISPLAY_NAME, 201ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Directory.PHOTO_SUPPORT, 202ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian }; 203ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 204ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final int ID = 0; 205ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final int PACKAGE_NAME = 1; 206ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final int TYPE_RESOURCE_ID = 2; 207ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final int DISPLAY_NAME = 3; 208ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public static final int PHOTO_SUPPORT = 4; 209ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 210ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian} 211