blob: bebb6eaca2a385dd595da6faf5b25488be649758 [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
2 * Copyright (C) 2007 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
17package com.android.phone;
18
19import android.accounts.Account;
20import android.app.ActionBar;
21import android.app.ProgressDialog;
22import android.content.ContentProviderOperation;
23import android.content.ContentResolver;
24import android.content.ContentValues;
25import android.content.DialogInterface;
26import android.content.DialogInterface.OnCancelListener;
27import android.content.DialogInterface.OnClickListener;
28import android.content.Intent;
29import android.content.OperationApplicationException;
30import android.database.Cursor;
31import android.net.Uri;
32import android.os.Bundle;
33import android.os.RemoteException;
34import android.provider.ContactsContract;
35import android.provider.ContactsContract.CommonDataKinds.Email;
36import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
37import android.provider.ContactsContract.CommonDataKinds.Phone;
38import android.provider.ContactsContract.CommonDataKinds.StructuredName;
39import android.provider.ContactsContract.Data;
40import android.provider.ContactsContract.RawContacts;
41import android.text.TextUtils;
42import android.util.Log;
43import android.view.ContextMenu;
44import android.view.KeyEvent;
45import android.view.Menu;
46import android.view.MenuItem;
47import android.view.View;
48import android.widget.AdapterView;
49import android.widget.CursorAdapter;
50import android.widget.ListView;
51import android.widget.SimpleCursorAdapter;
52import android.widget.TextView;
53
54import java.util.ArrayList;
55
56/**
57 * SIM Address Book UI for the Phone app.
58 */
59public class SimContacts extends ADNList {
60 private static final String LOG_TAG = "SimContacts";
61
Santos Cordon7d4ddf62013-07-10 11:58:08 -070062 static final ContentValues sEmptyContentValues = new ContentValues();
63
64 private static final int MENU_IMPORT_ONE = 1;
65 private static final int MENU_IMPORT_ALL = 2;
66 private ProgressDialog mProgressDialog;
67
68 private Account mAccount;
69
70 private static class NamePhoneTypePair {
71 final String name;
72 final int phoneType;
73 public NamePhoneTypePair(String nameWithPhoneType) {
74 // Look for /W /H /M or /O at the end of the name signifying the type
75 int nameLen = nameWithPhoneType.length();
76 if (nameLen - 2 >= 0 && nameWithPhoneType.charAt(nameLen - 2) == '/') {
77 char c = Character.toUpperCase(nameWithPhoneType.charAt(nameLen - 1));
78 if (c == 'W') {
79 phoneType = Phone.TYPE_WORK;
80 } else if (c == 'M' || c == 'O') {
81 phoneType = Phone.TYPE_MOBILE;
82 } else if (c == 'H') {
83 phoneType = Phone.TYPE_HOME;
84 } else {
85 phoneType = Phone.TYPE_OTHER;
86 }
87 name = nameWithPhoneType.substring(0, nameLen - 2);
88 } else {
89 phoneType = Phone.TYPE_OTHER;
90 name = nameWithPhoneType;
91 }
92 }
93 }
94
95 private class ImportAllSimContactsThread extends Thread
96 implements OnCancelListener, OnClickListener {
97
98 boolean mCanceled = false;
99
100 public ImportAllSimContactsThread() {
101 super("ImportAllSimContactsThread");
102 }
103
104 @Override
105 public void run() {
106 final ContentValues emptyContentValues = new ContentValues();
107 final ContentResolver resolver = getContentResolver();
108
109 mCursor.moveToPosition(-1);
110 while (!mCanceled && mCursor.moveToNext()) {
111 actuallyImportOneSimContact(mCursor, resolver, mAccount);
112 mProgressDialog.incrementProgressBy(1);
113 }
114
115 mProgressDialog.dismiss();
116 finish();
117 }
118
119 public void onCancel(DialogInterface dialog) {
120 mCanceled = true;
121 }
122
123 public void onClick(DialogInterface dialog, int which) {
124 if (which == DialogInterface.BUTTON_NEGATIVE) {
125 mCanceled = true;
126 mProgressDialog.dismiss();
127 } else {
128 Log.e(LOG_TAG, "Unknown button event has come: " + dialog.toString());
129 }
130 }
131 }
132
133 private static void actuallyImportOneSimContact(
134 final Cursor cursor, final ContentResolver resolver, Account account) {
135 final NamePhoneTypePair namePhoneTypePair =
136 new NamePhoneTypePair(cursor.getString(NAME_COLUMN));
137 final String name = namePhoneTypePair.name;
138 final int phoneType = namePhoneTypePair.phoneType;
139 final String phoneNumber = cursor.getString(NUMBER_COLUMN);
140 final String emailAddresses = cursor.getString(EMAILS_COLUMN);
141 final String[] emailAddressArray;
142 if (!TextUtils.isEmpty(emailAddresses)) {
143 emailAddressArray = emailAddresses.split(",");
144 } else {
145 emailAddressArray = null;
146 }
147
148 final ArrayList<ContentProviderOperation> operationList =
149 new ArrayList<ContentProviderOperation>();
150 ContentProviderOperation.Builder builder =
151 ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
152 String myGroupsId = null;
153 if (account != null) {
154 builder.withValue(RawContacts.ACCOUNT_NAME, account.name);
155 builder.withValue(RawContacts.ACCOUNT_TYPE, account.type);
156 } else {
157 builder.withValues(sEmptyContentValues);
158 }
159 operationList.add(builder.build());
160
161 builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
162 builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
163 builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
164 builder.withValue(StructuredName.DISPLAY_NAME, name);
165 operationList.add(builder.build());
166
167 builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
168 builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
169 builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
170 builder.withValue(Phone.TYPE, phoneType);
171 builder.withValue(Phone.NUMBER, phoneNumber);
172 builder.withValue(Data.IS_PRIMARY, 1);
173 operationList.add(builder.build());
174
175 if (emailAddresses != null) {
176 for (String emailAddress : emailAddressArray) {
177 builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
178 builder.withValueBackReference(Email.RAW_CONTACT_ID, 0);
179 builder.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
180 builder.withValue(Email.TYPE, Email.TYPE_MOBILE);
181 builder.withValue(Email.DATA, emailAddress);
182 operationList.add(builder.build());
183 }
184 }
185
186 if (myGroupsId != null) {
187 builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
188 builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0);
189 builder.withValue(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
190 builder.withValue(GroupMembership.GROUP_SOURCE_ID, myGroupsId);
191 operationList.add(builder.build());
192 }
193
194 try {
195 resolver.applyBatch(ContactsContract.AUTHORITY, operationList);
196 } catch (RemoteException e) {
197 Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
198 } catch (OperationApplicationException e) {
199 Log.e(LOG_TAG, String.format("%s: %s", e.toString(), e.getMessage()));
200 }
201 }
202
203 private void importOneSimContact(int position) {
204 final ContentResolver resolver = getContentResolver();
205 if (mCursor.moveToPosition(position)) {
206 actuallyImportOneSimContact(mCursor, resolver, mAccount);
207 } else {
208 Log.e(LOG_TAG, "Failed to move the cursor to the position \"" + position + "\"");
209 }
210 }
211
212 /* Followings are overridden methods */
213
214 @Override
215 protected void onCreate(Bundle icicle) {
216 super.onCreate(icicle);
217
218 Intent intent = getIntent();
219 if (intent != null) {
220 final String accountName = intent.getStringExtra("account_name");
221 final String accountType = intent.getStringExtra("account_type");
222 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
223 mAccount = new Account(accountName, accountType);
224 }
225 }
226
227 registerForContextMenu(getListView());
228
229 ActionBar actionBar = getActionBar();
230 if (actionBar != null) {
231 // android.R.id.home will be triggered in onOptionsItemSelected()
232 actionBar.setDisplayHomeAsUpEnabled(true);
233 }
234 }
235
236 @Override
237 protected CursorAdapter newAdapter() {
238 return new SimpleCursorAdapter(this, R.layout.sim_import_list_entry, mCursor,
239 new String[] { "name" }, new int[] { android.R.id.text1 });
240 }
241
242 @Override
243 protected Uri resolveIntent() {
244 Intent intent = getIntent();
245 intent.setData(Uri.parse("content://icc/adn"));
246 if (Intent.ACTION_PICK.equals(intent.getAction())) {
247 // "index" is 1-based
248 mInitialSelection = intent.getIntExtra("index", 0) - 1;
249 }
250 return intent.getData();
251 }
252
253 @Override
254 public boolean onCreateOptionsMenu(Menu menu) {
255 super.onCreateOptionsMenu(menu);
256 menu.add(0, MENU_IMPORT_ALL, 0, R.string.importAllSimEntries);
257 return true;
258 }
259
260 @Override
261 public boolean onPrepareOptionsMenu(Menu menu) {
262 MenuItem item = menu.findItem(MENU_IMPORT_ALL);
263 if (item != null) {
264 item.setVisible(mCursor != null && mCursor.getCount() > 0);
265 }
266 return super.onPrepareOptionsMenu(menu);
267 }
268
269 @Override
270 public boolean onOptionsItemSelected(MenuItem item) {
271 switch (item.getItemId()) {
272 case android.R.id.home:
Jay Shrauner3a124e62014-07-17 09:58:34 -0700273 onBackPressed();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700274 return true;
275 case MENU_IMPORT_ALL:
276 CharSequence title = getString(R.string.importAllSimEntries);
277 CharSequence message = getString(R.string.importingSimContacts);
278
279 ImportAllSimContactsThread thread = new ImportAllSimContactsThread();
280
281 // TODO: need to show some error dialog.
282 if (mCursor == null) {
283 Log.e(LOG_TAG, "cursor is null. Ignore silently.");
284 break;
285 }
286 mProgressDialog = new ProgressDialog(this);
287 mProgressDialog.setTitle(title);
288 mProgressDialog.setMessage(message);
289 mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
290 mProgressDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
291 getString(R.string.cancel), thread);
292 mProgressDialog.setProgress(0);
293 mProgressDialog.setMax(mCursor.getCount());
294 mProgressDialog.show();
295
296 thread.start();
297
298 return true;
299 }
300 return super.onOptionsItemSelected(item);
301 }
302
303 @Override
304 public boolean onContextItemSelected(MenuItem item) {
305 switch (item.getItemId()) {
306 case MENU_IMPORT_ONE:
307 ContextMenu.ContextMenuInfo menuInfo = item.getMenuInfo();
308 if (menuInfo instanceof AdapterView.AdapterContextMenuInfo) {
309 int position = ((AdapterView.AdapterContextMenuInfo)menuInfo).position;
310 importOneSimContact(position);
311 return true;
312 }
313 }
314 return super.onContextItemSelected(item);
315 }
316
317 @Override
318 public void onCreateContextMenu(ContextMenu menu, View v,
319 ContextMenu.ContextMenuInfo menuInfo) {
320 if (menuInfo instanceof AdapterView.AdapterContextMenuInfo) {
321 AdapterView.AdapterContextMenuInfo itemInfo =
322 (AdapterView.AdapterContextMenuInfo) menuInfo;
323 TextView textView = (TextView) itemInfo.targetView.findViewById(android.R.id.text1);
324 if (textView != null) {
325 menu.setHeaderTitle(textView.getText());
326 }
327 menu.add(0, MENU_IMPORT_ONE, 0, R.string.importSimEntry);
328 }
329 }
330
331 @Override
332 public void onListItemClick(ListView l, View v, int position, long id) {
333 importOneSimContact(position);
334 }
335
336 @Override
337 public boolean onKeyDown(int keyCode, KeyEvent event) {
338 switch (keyCode) {
339 case KeyEvent.KEYCODE_CALL: {
340 if (mCursor != null && mCursor.moveToPosition(getSelectedItemPosition())) {
341 String phoneNumber = mCursor.getString(NUMBER_COLUMN);
342 if (phoneNumber == null || !TextUtils.isGraphic(phoneNumber)) {
343 // There is no number entered.
344 //TODO play error sound or something...
345 return true;
346 }
347 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
348 Uri.fromParts(Constants.SCHEME_TEL, phoneNumber, null));
349 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
350 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
351 startActivity(intent);
352 finish();
353 return true;
354 }
355 }
356 }
357 return super.onKeyDown(keyCode, event);
358 }
359}