blob: 192c744f204b6c65f613483d273419b5414b6603 [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 */
Gary Mai69c182a2016-12-05 13:07:03 -080016package com.android.contacts.list;
Chiao Cheng89437e82012-11-01 13:41:51 -070017
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;
26import android.provider.ContactsContract.Directory;
27import android.text.TextUtils;
28import android.util.Log;
29
Arthur Wang3f6a2442016-12-05 14:51:59 -080030import com.android.contacts.R;
Gary Mai69c182a2016-12-05 13:07:03 -080031import com.android.contacts.compat.DirectoryCompat;
Chiao Cheng89437e82012-11-01 13:41:51 -070032
33/**
34 * A specialized loader for the list of directories, see {@link Directory}.
35 */
36public class DirectoryListLoader extends AsyncTaskLoader<Cursor> {
37
38 private static final String TAG = "ContactEntryListAdapter";
39
40 public static final int SEARCH_MODE_NONE = 0;
41 public static final int SEARCH_MODE_DEFAULT = 1;
42 public static final int SEARCH_MODE_CONTACT_SHORTCUT = 2;
43 public static final int SEARCH_MODE_DATA_SHORTCUT = 3;
44
45 private static final class DirectoryQuery {
Chiao Cheng89437e82012-11-01 13:41:51 -070046 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;
Tony Mak02b2d9e2016-05-10 18:44:36 +010061
62 public static Uri getDirectoryUri(int mode) {
63 if (mode == SEARCH_MODE_DATA_SHORTCUT || mode == SEARCH_MODE_CONTACT_SHORTCUT) {
64 return Directory.CONTENT_URI;
65 } else {
66 return DirectoryCompat.getContentUri();
67 }
68 }
Chiao Cheng89437e82012-11-01 13:41:51 -070069 }
70
71 // This is a virtual column created for a MatrixCursor.
72 public static final String DIRECTORY_TYPE = "directoryType";
73
74 private static final String[] RESULT_PROJECTION = {
75 Directory._ID,
76 DIRECTORY_TYPE,
77 Directory.DISPLAY_NAME,
78 Directory.PHOTO_SUPPORT,
79 };
80
81 private final ContentObserver mObserver = new ContentObserver(new Handler()) {
82 @Override
83 public void onChange(boolean selfChange) {
84 forceLoad();
85 }
86 };
87
88 private int mDirectorySearchMode;
89 private boolean mLocalInvisibleDirectoryEnabled;
90
91 private MatrixCursor mDefaultDirectoryList;
92
93 public DirectoryListLoader(Context context) {
94 super(context);
95 }
96
97 public void setDirectorySearchMode(int mode) {
98 mDirectorySearchMode = mode;
99 }
100
101 /**
102 * A flag that indicates whether the {@link Directory#LOCAL_INVISIBLE} directory should
103 * be included in the results.
104 */
105 public void setLocalInvisibleDirectoryEnabled(boolean flag) {
106 this.mLocalInvisibleDirectoryEnabled = flag;
107 }
108
109 @Override
110 protected void onStartLoading() {
111 getContext().getContentResolver().
Tony Mak02b2d9e2016-05-10 18:44:36 +0100112 registerContentObserver(DirectoryQuery.getDirectoryUri(mDirectorySearchMode),
113 false, mObserver);
Chiao Cheng89437e82012-11-01 13:41:51 -0700114 forceLoad();
115 }
116
117 @Override
118 protected void onStopLoading() {
119 getContext().getContentResolver().unregisterContentObserver(mObserver);
120 }
121
122 @Override
123 public Cursor loadInBackground() {
124 if (mDirectorySearchMode == SEARCH_MODE_NONE) {
125 return getDefaultDirectories();
126 }
127
128 MatrixCursor result = new MatrixCursor(RESULT_PROJECTION);
129 Context context = getContext();
130 PackageManager pm = context.getPackageManager();
131 String selection;
132 switch (mDirectorySearchMode) {
133 case SEARCH_MODE_DEFAULT:
Ricky Waidffb27d2015-12-08 16:58:27 +0000134 selection = null;
Chiao Cheng89437e82012-11-01 13:41:51 -0700135 break;
136
137 case SEARCH_MODE_CONTACT_SHORTCUT:
Ricky Waidffb27d2015-12-08 16:58:27 +0000138 selection = Directory.SHORTCUT_SUPPORT + "=" + Directory.SHORTCUT_SUPPORT_FULL;
Chiao Cheng89437e82012-11-01 13:41:51 -0700139 break;
140
141 case SEARCH_MODE_DATA_SHORTCUT:
142 selection = Directory.SHORTCUT_SUPPORT + " IN ("
143 + Directory.SHORTCUT_SUPPORT_FULL + ", "
Ricky Waidffb27d2015-12-08 16:58:27 +0000144 + Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY + ")";
Chiao Cheng89437e82012-11-01 13:41:51 -0700145 break;
146
147 default:
148 throw new RuntimeException(
149 "Unsupported directory search mode: " + mDirectorySearchMode);
150 }
Yorke Lee35821292015-06-23 16:53:29 -0700151 Cursor cursor = null;
Chiao Cheng89437e82012-11-01 13:41:51 -0700152 try {
Tony Mak02b2d9e2016-05-10 18:44:36 +0100153 cursor = context.getContentResolver().query(
154 DirectoryQuery.getDirectoryUri(mDirectorySearchMode),
Yorke Lee35821292015-06-23 16:53:29 -0700155 DirectoryQuery.PROJECTION, selection, null, DirectoryQuery.ORDER_BY);
156
157 if (cursor == null) {
158 return result;
159 }
160
Chiao Cheng89437e82012-11-01 13:41:51 -0700161 while(cursor.moveToNext()) {
162 long directoryId = cursor.getLong(DirectoryQuery.ID);
Ricky Waidffb27d2015-12-08 16:58:27 +0000163 if (!mLocalInvisibleDirectoryEnabled
164 && DirectoryCompat.isInvisibleDirectory(directoryId)) {
165 continue;
166 }
Chiao Cheng89437e82012-11-01 13:41:51 -0700167 String directoryType = null;
168
169 String packageName = cursor.getString(DirectoryQuery.PACKAGE_NAME);
170 int typeResourceId = cursor.getInt(DirectoryQuery.TYPE_RESOURCE_ID);
171 if (!TextUtils.isEmpty(packageName) && typeResourceId != 0) {
172 try {
173 directoryType = pm.getResourcesForApplication(packageName)
174 .getString(typeResourceId);
175 } catch (Exception e) {
176 Log.e(TAG, "Cannot obtain directory type from package: " + packageName);
177 }
178 }
179 String displayName = cursor.getString(DirectoryQuery.DISPLAY_NAME);
180 int photoSupport = cursor.getInt(DirectoryQuery.PHOTO_SUPPORT);
181 result.addRow(new Object[]{directoryId, directoryType, displayName, photoSupport});
182 }
Yorke Lee35821292015-06-23 16:53:29 -0700183 } catch (RuntimeException e) {
184 Log.w(TAG, "Runtime Exception when querying directory");
Chiao Cheng89437e82012-11-01 13:41:51 -0700185 } finally {
Yorke Lee35821292015-06-23 16:53:29 -0700186 if (cursor != null) {
187 cursor.close();
188 }
Chiao Cheng89437e82012-11-01 13:41:51 -0700189 }
190
191 return result;
192 }
193
194 private Cursor getDefaultDirectories() {
195 if (mDefaultDirectoryList == null) {
196 mDefaultDirectoryList = new MatrixCursor(RESULT_PROJECTION);
197 mDefaultDirectoryList.addRow(new Object[] {
198 Directory.DEFAULT,
199 getContext().getString(R.string.contactsList),
Wenyi Wang72b0f452016-09-30 15:29:04 -0700200 null,
Chiao Cheng89437e82012-11-01 13:41:51 -0700201 null
202 });
203 mDefaultDirectoryList.addRow(new Object[] {
204 Directory.LOCAL_INVISIBLE,
205 getContext().getString(R.string.local_invisible_directory),
Wenyi Wang72b0f452016-09-30 15:29:04 -0700206 null,
Chiao Cheng89437e82012-11-01 13:41:51 -0700207 null
208 });
209 }
210 return mDefaultDirectoryList;
211 }
212
213 @Override
214 protected void onReset() {
215 stopLoading();
216 }
217}