blob: 13d0f926cb93e95c30e7d2a36bebfc1a741b2a2a [file] [log] [blame]
Chiao Cheng89437e82012-11-01 13:41:51 -07001/*
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 */
16package com.android.contacts.common.list;
17
18import android.content.AsyncTaskLoader;
19import android.content.Context;
20import android.content.pm.PackageManager;
21import android.database.ContentObserver;
22import android.database.Cursor;
23import android.database.MatrixCursor;
24import android.net.Uri;
25import android.os.Handler;
Victor Changb83af232015-12-01 19:13:12 +000026import android.provider.ContactsContract;
Chiao Cheng89437e82012-11-01 13:41:51 -070027import android.provider.ContactsContract.Directory;
28import android.text.TextUtils;
29import android.util.Log;
30
Victor Changb83af232015-12-01 19:13:12 +000031import com.android.contacts.common.ContactsUtils;
Chiao Cheng89437e82012-11-01 13:41:51 -070032import com.android.contacts.common.R;
Ricky Waidffb27d2015-12-08 16:58:27 +000033import com.android.contacts.common.compat.DirectoryCompat;
Chiao Cheng89437e82012-11-01 13:41:51 -070034
35/**
36 * A specialized loader for the list of directories, see {@link Directory}.
37 */
38public class DirectoryListLoader extends AsyncTaskLoader<Cursor> {
39
40 private static final String TAG = "ContactEntryListAdapter";
41
42 public static final int SEARCH_MODE_NONE = 0;
43 public static final int SEARCH_MODE_DEFAULT = 1;
44 public static final int SEARCH_MODE_CONTACT_SHORTCUT = 2;
45 public static final int SEARCH_MODE_DATA_SHORTCUT = 3;
46
47 private static final class DirectoryQuery {
Chiao Cheng89437e82012-11-01 13:41:51 -070048 public static final String ORDER_BY = Directory._ID;
49
50 public static final String[] PROJECTION = {
51 Directory._ID,
52 Directory.PACKAGE_NAME,
53 Directory.TYPE_RESOURCE_ID,
54 Directory.DISPLAY_NAME,
55 Directory.PHOTO_SUPPORT,
56 };
57
58 public static final int ID = 0;
59 public static final int PACKAGE_NAME = 1;
60 public static final int TYPE_RESOURCE_ID = 2;
61 public static final int DISPLAY_NAME = 3;
62 public static final int PHOTO_SUPPORT = 4;
Tony Mak02b2d9e2016-05-10 18:44:36 +010063
64 public static Uri getDirectoryUri(int mode) {
65 if (mode == SEARCH_MODE_DATA_SHORTCUT || mode == SEARCH_MODE_CONTACT_SHORTCUT) {
66 return Directory.CONTENT_URI;
67 } else {
68 return DirectoryCompat.getContentUri();
69 }
70 }
Chiao Cheng89437e82012-11-01 13:41:51 -070071 }
72
73 // This is a virtual column created for a MatrixCursor.
74 public static final String DIRECTORY_TYPE = "directoryType";
75
76 private static final String[] RESULT_PROJECTION = {
77 Directory._ID,
78 DIRECTORY_TYPE,
79 Directory.DISPLAY_NAME,
80 Directory.PHOTO_SUPPORT,
81 };
82
83 private final ContentObserver mObserver = new ContentObserver(new Handler()) {
84 @Override
85 public void onChange(boolean selfChange) {
86 forceLoad();
87 }
88 };
89
90 private int mDirectorySearchMode;
91 private boolean mLocalInvisibleDirectoryEnabled;
92
93 private MatrixCursor mDefaultDirectoryList;
94
95 public DirectoryListLoader(Context context) {
96 super(context);
97 }
98
99 public void setDirectorySearchMode(int mode) {
100 mDirectorySearchMode = mode;
101 }
102
103 /**
104 * A flag that indicates whether the {@link Directory#LOCAL_INVISIBLE} directory should
105 * be included in the results.
106 */
107 public void setLocalInvisibleDirectoryEnabled(boolean flag) {
108 this.mLocalInvisibleDirectoryEnabled = flag;
109 }
110
111 @Override
112 protected void onStartLoading() {
113 getContext().getContentResolver().
Tony Mak02b2d9e2016-05-10 18:44:36 +0100114 registerContentObserver(DirectoryQuery.getDirectoryUri(mDirectorySearchMode),
115 false, mObserver);
Chiao Cheng89437e82012-11-01 13:41:51 -0700116 forceLoad();
117 }
118
119 @Override
120 protected void onStopLoading() {
121 getContext().getContentResolver().unregisterContentObserver(mObserver);
122 }
123
124 @Override
125 public Cursor loadInBackground() {
126 if (mDirectorySearchMode == SEARCH_MODE_NONE) {
127 return getDefaultDirectories();
128 }
129
130 MatrixCursor result = new MatrixCursor(RESULT_PROJECTION);
131 Context context = getContext();
132 PackageManager pm = context.getPackageManager();
133 String selection;
134 switch (mDirectorySearchMode) {
135 case SEARCH_MODE_DEFAULT:
Ricky Waidffb27d2015-12-08 16:58:27 +0000136 selection = null;
Chiao Cheng89437e82012-11-01 13:41:51 -0700137 break;
138
139 case SEARCH_MODE_CONTACT_SHORTCUT:
Ricky Waidffb27d2015-12-08 16:58:27 +0000140 selection = Directory.SHORTCUT_SUPPORT + "=" + Directory.SHORTCUT_SUPPORT_FULL;
Chiao Cheng89437e82012-11-01 13:41:51 -0700141 break;
142
143 case SEARCH_MODE_DATA_SHORTCUT:
144 selection = Directory.SHORTCUT_SUPPORT + " IN ("
145 + Directory.SHORTCUT_SUPPORT_FULL + ", "
Ricky Waidffb27d2015-12-08 16:58:27 +0000146 + Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY + ")";
Chiao Cheng89437e82012-11-01 13:41:51 -0700147 break;
148
149 default:
150 throw new RuntimeException(
151 "Unsupported directory search mode: " + mDirectorySearchMode);
152 }
Yorke Lee35821292015-06-23 16:53:29 -0700153 Cursor cursor = null;
Chiao Cheng89437e82012-11-01 13:41:51 -0700154 try {
Tony Mak02b2d9e2016-05-10 18:44:36 +0100155 cursor = context.getContentResolver().query(
156 DirectoryQuery.getDirectoryUri(mDirectorySearchMode),
Yorke Lee35821292015-06-23 16:53:29 -0700157 DirectoryQuery.PROJECTION, selection, null, DirectoryQuery.ORDER_BY);
158
159 if (cursor == null) {
160 return result;
161 }
162
Chiao Cheng89437e82012-11-01 13:41:51 -0700163 while(cursor.moveToNext()) {
164 long directoryId = cursor.getLong(DirectoryQuery.ID);
Ricky Waidffb27d2015-12-08 16:58:27 +0000165 if (!mLocalInvisibleDirectoryEnabled
166 && DirectoryCompat.isInvisibleDirectory(directoryId)) {
167 continue;
168 }
Chiao Cheng89437e82012-11-01 13:41:51 -0700169 String directoryType = null;
170
171 String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME);
172 int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
173 if (!TextUtils.isEmpty(packageName) && typeResourceId != 0) {
174 try {
175 directoryType = pm.getResourcesForApplication(packageName)
176 .getString(typeResourceId);
177 } catch (Exception e) {
178 Log.e(TAG, "Cannot obtain directory type from package: " + packageName);
179 }
180 }
181 String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
182 int photoSupport = cursor.getInt(DirectoryQuery.PHOTO_SUPPORT);
183 result.addRow(new Object[]{directoryId, directoryType, displayName, photoSupport});
184 }
Yorke Lee35821292015-06-23 16:53:29 -0700185 } catch (RuntimeException e) {
186 Log.w(TAG, "Runtime Exception when querying directory");
Chiao Cheng89437e82012-11-01 13:41:51 -0700187 } finally {
Yorke Lee35821292015-06-23 16:53:29 -0700188 if (cursor != null) {
189 cursor.close();
190 }
Chiao Cheng89437e82012-11-01 13:41:51 -0700191 }
192
193 return result;
194 }
195
196 private Cursor getDefaultDirectories() {
197 if (mDefaultDirectoryList == null) {
198 mDefaultDirectoryList = new MatrixCursor(RESULT_PROJECTION);
199 mDefaultDirectoryList.addRow(new Object[] {
200 Directory.DEFAULT,
201 getContext().getString(R.string.contactsList),
Wenyi Wang72b0f452016-09-30 15:29:04 -0700202 null,
Chiao Cheng89437e82012-11-01 13:41:51 -0700203 null
204 });
205 mDefaultDirectoryList.addRow(new Object[] {
206 Directory.LOCAL_INVISIBLE,
207 getContext().getString(R.string.local_invisible_directory),
Wenyi Wang72b0f452016-09-30 15:29:04 -0700208 null,
Chiao Cheng89437e82012-11-01 13:41:51 -0700209 null
210 });
211 }
212 return mDefaultDirectoryList;
213 }
214
215 @Override
216 protected void onReset() {
217 stopLoading();
218 }
219}