blob: 3a7610da72f89dc68505d1146d7ce3e5bbc1577f [file] [log] [blame]
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -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.contacts;
18
19import com.google.android.collect.Lists;
20
21import static com.android.contacts.ContactEntryAdapter.CONTACT_CUSTOM_RINGTONE_COLUMN;
22import static com.android.contacts.ContactEntryAdapter.CONTACT_NAME_COLUMN;
23import static com.android.contacts.ContactEntryAdapter.CONTACT_NOTES_COLUMN;
24import static com.android.contacts.ContactEntryAdapter.CONTACT_PROJECTION;
25import static com.android.contacts.ContactEntryAdapter.CONTACT_SEND_TO_VOICEMAIL_COLUMN;
26import static com.android.contacts.ContactEntryAdapter.METHODS_AUX_DATA_COLUMN;
27import static com.android.contacts.ContactEntryAdapter.METHODS_DATA_COLUMN;
28import static com.android.contacts.ContactEntryAdapter.METHODS_ID_COLUMN;
29import static com.android.contacts.ContactEntryAdapter.METHODS_ISPRIMARY_COLUMN;
30import static com.android.contacts.ContactEntryAdapter.METHODS_KIND_COLUMN;
31import static com.android.contacts.ContactEntryAdapter.METHODS_LABEL_COLUMN;
32import static com.android.contacts.ContactEntryAdapter.METHODS_PROJECTION;
33import static com.android.contacts.ContactEntryAdapter.METHODS_TYPE_COLUMN;
34import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_COMPANY_COLUMN;
35import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_ID_COLUMN;
36import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_ISPRIMARY_COLUMN;
37import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_LABEL_COLUMN;
38import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_PROJECTION;
39import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_TITLE_COLUMN;
40import static com.android.contacts.ContactEntryAdapter.ORGANIZATIONS_TYPE_COLUMN;
41import static com.android.contacts.ContactEntryAdapter.PHONES_ID_COLUMN;
42import static com.android.contacts.ContactEntryAdapter.PHONES_ISPRIMARY_COLUMN;
43import static com.android.contacts.ContactEntryAdapter.PHONES_LABEL_COLUMN;
44import static com.android.contacts.ContactEntryAdapter.PHONES_NUMBER_COLUMN;
45import static com.android.contacts.ContactEntryAdapter.PHONES_PROJECTION;
46import static com.android.contacts.ContactEntryAdapter.PHONES_TYPE_COLUMN;
47
48import android.app.Activity;
49import android.app.AlertDialog;
50import android.app.Dialog;
51import android.content.ActivityNotFoundException;
52import android.content.ContentResolver;
53import android.content.ContentUris;
54import android.content.ContentValues;
55import android.content.Context;
56import android.content.DialogInterface;
57import android.content.Intent;
58import android.content.SharedPreferences;
59import android.content.res.Resources;
60import android.database.Cursor;
61import android.graphics.Bitmap;
62import android.media.Ringtone;
63import android.media.RingtoneManager;
64import android.net.Uri;
65import android.os.Bundle;
66import android.os.Parcel;
67import android.os.Parcelable;
68import android.preference.PreferenceManager;
69import android.provider.Contacts;
70import android.provider.Contacts.ContactMethods;
71import android.provider.Contacts.Intents.Insert;
72import android.provider.Contacts.Organizations;
73import android.provider.Contacts.People;
74import android.provider.Contacts.Phones;
75import android.telephony.PhoneNumberFormattingTextWatcher;
76import android.text.TextUtils;
77import android.text.method.DialerKeyListener;
78import android.text.method.TextKeyListener;
79import android.text.method.TextKeyListener.Capitalize;
80import android.util.Log;
81import android.view.ContextThemeWrapper;
82import android.view.KeyEvent;
83import android.view.LayoutInflater;
84import android.view.Menu;
85import android.view.MenuItem;
86import android.view.View;
87import android.view.ViewGroup;
88import android.view.ViewParent;
The Android Open Source Projectd9351702008-12-17 18:05:55 -080089import android.view.inputmethod.EditorInfo;
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -070090import android.widget.Button;
91import android.widget.CheckBox;
92import android.widget.EditText;
93import android.widget.ExpandableListView;
94import android.widget.ImageView;
95import android.widget.LinearLayout;
96import android.widget.SimpleExpandableListAdapter;
97import android.widget.TextView;
98import android.widget.Toast;
99
100import java.io.ByteArrayOutputStream;
101import java.util.ArrayList;
102import java.util.HashMap;
103import java.util.List;
104import java.util.Map;
105
106/**
107 * Activity for editing or inserting a contact. Note that if the contact data changes in the
108 * background while this activity is running, the updates will be overwritten.
109 */
110public final class EditContactActivity extends Activity implements View.OnClickListener,
111 ExpandableListView.OnChildClickListener {
112 private static final String TAG = "EditContactActivity";
113
114 private static final int STATE_UNKNOWN = 0;
115 /** Editing an existing contact */
116 private static final int STATE_EDIT = 1;
117 /** The full insert mode */
118 private static final int STATE_INSERT = 2;
119
120 /** The launch code when picking a photo and the raw data is returned */
121 private static final int PHOTO_PICKED_WITH_DATA = 3021;
122
123 /** The launch code when picking a ringtone */
124 private static final int RINGTONE_PICKED = 3023;
125
126 // Label picker position info
127 final static int LABEL_PICKER_PHONES_POSITION = 0;
128 final static int LABEL_PICKER_EMAIL_POSITION = 1;
129 final static int LABEL_PICKER_IM_POSITION = 2;
130 final static int LABEL_PICKER_POSTAL_POSITION = 3;
131 final static int LABEL_PICKER_OTHER_POSITION = 4;
132
133 // These correspond to the string array in resources for picker "other" items
134 final static int OTHER_ORGANIZATION = 0;
135 final static int OTHER_NOTE = 1;
136
137 // Dialog IDs
138 final static int LABEL_PICKER_ALL_TYPES_DIALOG = 1;
139 final static int DELETE_CONFIRMATION_DIALOG = 2;
140
141 // Menu item IDs
142 public static final int MENU_ITEM_SAVE = 1;
143 public static final int MENU_ITEM_DONT_SAVE = 2;
144 public static final int MENU_ITEM_DELETE = 3;
145 public static final int MENU_ITEM_ADD = 5;
146 public static final int MENU_ITEM_PHOTO = 6;
147
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -0700148 /** Used to represent an invalid type for a contact entry */
149 private static final int INVALID_TYPE = -1;
150
151 /** The default type for a phone that is added via an intent */
152 private static final int DEFAULT_PHONE_TYPE = Phones.TYPE_MOBILE;
153
154 /** The default type for an email that is added via an intent */
155 private static final int DEFAULT_EMAIL_TYPE = ContactMethods.TYPE_HOME;
156
157 /** The default type for a postal address that is added via an intent */
158 private static final int DEFAULT_POSTAL_TYPE = ContactMethods.TYPE_HOME;
159
160 private int mState; // saved across instances
161 private boolean mInsert; // saved across instances
162 private Uri mUri; // saved across instances
163 /** In insert mode this is the photo */
164 private Bitmap mPhoto; // saved across instances
165 private boolean mPhotoChanged = false; // saved across instances
166
167 private EditText mNameView;
168 private ImageView mPhotoImageView;
The Android Open Source Projectd9351702008-12-17 18:05:55 -0800169 private View mPhotoButton;
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -0700170 private CheckBox mSendToVoicemailCheckBox;
171 private LinearLayout mLayout;
172 private LayoutInflater mInflater;
173 private MenuItem mPhotoMenuItem;
174 private boolean mPhotoPresent = false;
175
176 // These are accessed by inner classes. They're package scoped to make access more efficient.
177 /* package */ ContentResolver mResolver;
178 /* package */ ArrayList<EditEntry> mPhoneEntries = new ArrayList<EditEntry>();
179 /* package */ ArrayList<EditEntry> mEmailEntries = new ArrayList<EditEntry>();
180 /* package */ ArrayList<EditEntry> mImEntries = new ArrayList<EditEntry>();
181 /* package */ ArrayList<EditEntry> mPostalEntries = new ArrayList<EditEntry>();
182 /* package */ ArrayList<EditEntry> mOtherEntries = new ArrayList<EditEntry>();
183 /* package */ ArrayList<ArrayList<EditEntry>> mSections = new ArrayList<ArrayList<EditEntry>>();
184
185 /* package */ static final int MSG_DELETE = 1;
186 /* package */ static final int MSG_CHANGE_LABEL = 2;
187 /* package */ static final int MSG_ADD_PHONE = 3;
188 /* package */ static final int MSG_ADD_EMAIL = 4;
189 /* package */ static final int MSG_ADD_POSTAL = 5;
190
191 public void onClick(View v) {
192 switch (v.getId()) {
193 case R.id.photoButton:
194 case R.id.photoImage: {
195 doPickPhotoAction();
196 break;
197 }
198
199 case R.id.addMore:
200 doAddAction();
201 break;
202
203 case R.id.saveButton:
204 doSaveAction();
205 break;
206
207 case R.id.discardButton:
208 doRevertAction();
209 break;
210
211 case R.id.delete:
212 case R.id.delete2: {
213 EditEntry entry = findEntryForView(v);
214 if (entry != null) {
215 // Clear the text and hide the view so it gets saved properly
216 ((TextView) entry.view.findViewById(R.id.data)).setText(null);
217 entry.view.setVisibility(View.GONE);
218 entry.isDeleted = true;
219 }
220 break;
221 }
222
223 case R.id.label: {
224 EditEntry entry = findEntryForView(v);
225 if (entry != null) {
226 String[] labels = getLabelsForKind(this, entry.kind);
227 LabelPickedListener listener = new LabelPickedListener(entry, labels);
228 new AlertDialog.Builder(EditContactActivity.this)
229 .setItems(labels, listener)
230 .setTitle(R.string.selectLabel)
231 .show();
232 }
233 break;
234 }
235
236 case R.id.data: {
237 EditEntry entry = findEntryForView(v);
238 if (isRingtoneEntry(entry)) {
239 doPickRingtone(entry);
240 }
241 break;
242 }
243 }
244 }
245
246 private void setPhotoPresent(boolean present) {
247 mPhotoImageView.setVisibility(present ? View.VISIBLE : View.GONE);
248 mPhotoButton.setVisibility(present ? View.GONE : View.VISIBLE);
249 mPhotoPresent = present;
250 if (mPhotoMenuItem != null) {
251 if (present) {
252 mPhotoMenuItem.setTitle(R.string.removePicture);
253 mPhotoMenuItem.setIcon(android.R.drawable.ic_menu_delete);
254 } else {
255 mPhotoMenuItem.setTitle(R.string.addPicture);
The Android Open Source Projectd9351702008-12-17 18:05:55 -0800256 mPhotoMenuItem.setIcon(R.drawable.ic_menu_add_picture);
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -0700257 }
258 }
259 }
260
261 private EditEntry findEntryForView(View v) {
262 // Try to find the entry for this view
263 EditEntry entry = null;
264 do {
265 Object tag = v.getTag();
266 if (tag != null && tag instanceof EditEntry) {
267 entry = (EditEntry) tag;
268 break;
269 } else {
270 ViewParent parent = v.getParent();
271 if (parent != null && parent instanceof View) {
272 v = (View) parent;
273 } else {
274 v = null;
275 }
276 }
277 } while (v != null);
278 return entry;
279 }
280
281 private DialogInterface.OnClickListener mDeleteContactDialogListener =
282 new DialogInterface.OnClickListener() {
283 public void onClick(DialogInterface dialog, int button) {
284 mResolver.delete(mUri, null, null);
285 finish();
286 }
287 };
288
289 private boolean mMobilePhoneAdded = false;
290 private boolean mPrimaryEmailAdded = false;
291
292 @Override
293 protected void onCreate(Bundle icicle) {
294 super.onCreate(icicle);
295
296 mResolver = getContentResolver();
297
298 // Build the list of sections
299 setupSections();
300
301 // Load the UI
302 setContentView(R.layout.edit_contact);
303 mLayout = (LinearLayout) findViewById(R.id.list);
304 mNameView = (EditText) findViewById(R.id.name);
305 mPhotoImageView = (ImageView) findViewById(R.id.photoImage);
306 mPhotoImageView.setOnClickListener(this);
307 mPhotoImageView.setVisibility(View.GONE);
The Android Open Source Projectd9351702008-12-17 18:05:55 -0800308 mPhotoButton = findViewById(R.id.photoButton);
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -0700309 mPhotoButton.setOnClickListener(this);
310 mSendToVoicemailCheckBox = (CheckBox) findViewById(R.id.send_to_voicemail);
311
312 // Setup the bottom buttons
313 View view = findViewById(R.id.addMore);
314 view.setOnClickListener(this);
315 view = findViewById(R.id.saveButton);
316 view.setOnClickListener(this);
317 view = findViewById(R.id.discardButton);
318 view.setOnClickListener(this);
319
320 mInflater = getLayoutInflater();
321
322 // Resolve the intent
323 mState = STATE_UNKNOWN;
324 Intent intent = getIntent();
325 String action = intent.getAction();
326 mUri = intent.getData();
327 if (mUri != null) {
328 if (action.equals(Intent.ACTION_EDIT)) {
329 if (icicle == null) {
330 // Build the entries & views
331 buildEntriesForEdit(getIntent().getExtras());
332 buildViews();
333 }
334 mState = STATE_EDIT;
335 } else if (action.equals(Intent.ACTION_INSERT)) {
336 if (icicle == null) {
337 // Build the entries & views
338 buildEntriesForInsert(getIntent().getExtras());
339 buildViews();
340 }
341 mState = STATE_INSERT;
342 mInsert = true;
343 }
344 }
345
346 if (mState == STATE_UNKNOWN) {
347 Log.e(TAG, "Cannot resolve intent: " + intent);
348 finish();
349 return;
350 }
351
352 if (mState == STATE_EDIT) {
353 setTitle(getResources().getText(R.string.editContact_title_edit));
354 } else {
355 setTitle(getResources().getText(R.string.editContact_title_insert));
356 }
357 }
358
359 private void setupSections() {
360 mSections.add(mPhoneEntries);
361 mSections.add(mEmailEntries);
362 mSections.add(mImEntries);
363 mSections.add(mPostalEntries);
364 mSections.add(mOtherEntries);
365 }
366
367 @Override
368 protected void onSaveInstanceState(Bundle outState) {
369 outState.putParcelableArrayList("phoneEntries", mPhoneEntries);
370 outState.putParcelableArrayList("emailEntries", mEmailEntries);
371 outState.putParcelableArrayList("imEntries", mImEntries);
372 outState.putParcelableArrayList("postalEntries", mPostalEntries);
373 outState.putParcelableArrayList("otherEntries", mOtherEntries);
374 outState.putInt("state", mState);
375 outState.putBoolean("insert", mInsert);
376 outState.putParcelable("uri", mUri);
377 outState.putString("name", mNameView.getText().toString());
378 outState.putParcelable("photo", mPhoto);
379 outState.putBoolean("photoChanged", mPhotoChanged);
380 outState.putBoolean("sendToVoicemail", mSendToVoicemailCheckBox.isChecked());
381 }
382
383 @Override
384 protected void onRestoreInstanceState(Bundle inState) {
385 mPhoneEntries = inState.getParcelableArrayList("phoneEntries");
386 mEmailEntries = inState.getParcelableArrayList("emailEntries");
387 mImEntries = inState.getParcelableArrayList("imEntries");
388 mPostalEntries = inState.getParcelableArrayList("postalEntries");
389 mOtherEntries = inState.getParcelableArrayList("otherEntries");
390 setupSections();
391
392 mState = inState.getInt("state");
393 mInsert = inState.getBoolean("insert");
394 mUri = inState.getParcelable("uri");
395 mNameView.setText(inState.getString("name"));
396 mPhoto = inState.getParcelable("photo");
397 if (mPhoto != null) {
398 mPhotoImageView.setImageBitmap(mPhoto);
399 setPhotoPresent(true);
400 } else {
401 mPhotoImageView.setImageResource(R.drawable.ic_contact_picture);
402 setPhotoPresent(false);
403 }
404 mPhotoChanged = inState.getBoolean("photoChanged");
405 mSendToVoicemailCheckBox.setChecked(inState.getBoolean("sendToVoicemail"));
406
407 // Now that everything is restored, build the view
408 buildViews();
409 }
410
411 @Override
412 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
413 if (resultCode != RESULT_OK) {
414 return;
415 }
416
417 switch (requestCode) {
418 case PHOTO_PICKED_WITH_DATA: {
419 final Bundle extras = data.getExtras();
420 if (extras != null) {
421 Bitmap photo = extras.getParcelable("data");
422 mPhoto = photo;
423 mPhotoChanged = true;
424 mPhotoImageView.setImageBitmap(photo);
425 setPhotoPresent(true);
426 }
427 break;
428 }
429
430 case RINGTONE_PICKED: {
431 Uri pickedUri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
432 handleRingtonePicked(pickedUri);
433 break;
434 }
435 }
436 }
437
438 @Override
439 public boolean onKeyDown(int keyCode, KeyEvent event) {
440 switch (keyCode) {
441 case KeyEvent.KEYCODE_BACK: {
442 doSaveAction();
443 return true;
444 }
445 }
446 return super.onKeyDown(keyCode, event);
447 }
448
449 @Override
450 public boolean onCreateOptionsMenu(Menu menu) {
451 super.onCreateOptionsMenu(menu);
452 menu.add(0, MENU_ITEM_SAVE, 0, R.string.menu_done)
453 .setIcon(android.R.drawable.ic_menu_save)
454 .setAlphabeticShortcut('\n');
455 menu.add(0, MENU_ITEM_DONT_SAVE, 0, R.string.menu_doNotSave)
456 .setIcon(android.R.drawable.ic_menu_close_clear_cancel)
457 .setAlphabeticShortcut('q');
458 if (!mInsert) {
459 menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_deleteContact)
460 .setIcon(android.R.drawable.ic_menu_delete);
461 }
462
463 menu.add(0, MENU_ITEM_ADD, 0, R.string.menu_addItem)
464 .setIcon(android.R.drawable.ic_menu_add)
465 .setAlphabeticShortcut('n');
466
467 mPhotoMenuItem = menu.add(0, MENU_ITEM_PHOTO, 0, null);
468 // Updates the state of the menu item
469 setPhotoPresent(mPhotoPresent);
470
471 return true;
472 }
473
474 @Override
475 public boolean onOptionsItemSelected(MenuItem item) {
476 switch (item.getItemId()) {
477 case MENU_ITEM_SAVE:
478 doSaveAction();
479 return true;
480
481 case MENU_ITEM_DONT_SAVE:
482 doRevertAction();
483 return true;
484
485 case MENU_ITEM_DELETE:
486 // Get confirmation
487 showDialog(DELETE_CONFIRMATION_DIALOG);
488 return true;
489
490 case MENU_ITEM_ADD:
491 doAddAction();
492 return true;
493
494 case MENU_ITEM_PHOTO:
495 if (!mPhotoPresent) {
496 doPickPhotoAction();
497 } else {
498 doRemovePhotoAction();
499 }
500 return true;
501 }
502
503 return false;
504 }
505
506 private void doAddAction() {
507 showDialog(LABEL_PICKER_ALL_TYPES_DIALOG);
508 }
509
510 private void doRevertAction() {
511 finish();
512 }
513
514 private void doPickPhotoAction() {
515 Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
516 // TODO: get these values from constants somewhere
517 intent.setType("image/*");
518 intent.putExtra("crop", "true");
519 intent.putExtra("aspectX", 1);
520 intent.putExtra("aspectY", 1);
521 intent.putExtra("outputX", 96);
522 intent.putExtra("outputY", 96);
523 try {
524 intent.putExtra("return-data", true);
525 startActivityForResult(intent, PHOTO_PICKED_WITH_DATA);
526 } catch (ActivityNotFoundException e) {
527 new AlertDialog.Builder(EditContactActivity.this)
528 .setTitle(R.string.errorDialogTitle)
529 .setMessage(R.string.photoPickerNotFoundText)
The Android Open Source Projectd9351702008-12-17 18:05:55 -0800530 .setPositiveButton(android.R.string.ok, null)
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -0700531 .show();
532 }
533 }
534
535 private void doRemovePhotoAction() {
536 mPhoto = null;
537 mPhotoChanged = true;
538 mPhotoImageView.setImageResource(R.drawable.ic_contact_picture);
539 setPhotoPresent(false);
540 }
541
542 private void doPickRingtone(EditEntry entry) {
543 Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
544 // Allow user to pick 'Default'
545 intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
546 // Show only ringtones
547 intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE);
548 // Don't show 'Silent'
549 intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false);
550 if (entry.data != null) {
551 Uri ringtoneUri = Uri.parse(entry.data);
552 // Put checkmark next to the current ringtone for this contact
553 intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, ringtoneUri);
554 }
555 // Launch!
556 startActivityForResult(intent, RINGTONE_PICKED);
557 }
558
559 private void handleRingtonePicked(Uri pickedUri) {
560 EditEntry entry = getRingtoneEntry();
561 if (entry == null) {
562 Log.w(TAG, "Ringtone picked but could not find ringtone entry");
563 return;
564 }
565
566 if (pickedUri == null || RingtoneManager.isDefault(pickedUri)) {
567 entry.data = null;
568 } else {
569 entry.data = pickedUri.toString();
570 }
571
572 updateRingtoneView(entry);
573 }
574
575 private void updateRingtoneView(EditEntry entry) {
576 if (entry.data == null) {
577 updateDataView(entry, getString(R.string.default_ringtone));
578 } else {
579 Uri ringtoneUri = Uri.parse(entry.data);
580 Ringtone ringtone = RingtoneManager.getRingtone(this, ringtoneUri);
581 if (ringtone == null) {
582 Log.w(TAG, "ringtone's URI doesn't resolve to a Ringtone");
583 return;
584 }
585 updateDataView(entry, ringtone.getTitle(this));
586 }
587 }
588
589 private void updateDataView(EditEntry entry, String text) {
590 TextView dataView = (TextView) entry.view.findViewById(R.id.data);
591 dataView.setText(text);
592 }
593
594 @Override
595 protected Dialog onCreateDialog(int id) {
596 switch (id) {
597 case LABEL_PICKER_ALL_TYPES_DIALOG:
598 return createAllTypesPicker();
599
600 case DELETE_CONFIRMATION_DIALOG:
601 return new AlertDialog.Builder(EditContactActivity.this)
602 .setTitle(R.string.deleteConfirmation_title)
603 .setIcon(android.R.drawable.ic_dialog_alert)
604 .setMessage(R.string.deleteConfirmation)
The Android Open Source Projectd9351702008-12-17 18:05:55 -0800605 .setNegativeButton(android.R.string.cancel, null)
606 .setPositiveButton(android.R.string.ok, mDeleteContactDialogListener)
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -0700607 .setCancelable(false)
608 .create();
609 }
610 return super.onCreateDialog(id);
611 }
612
613 static String[] getLabelsForKind(Context context, int kind) {
614 final Resources resources = context.getResources();
615 switch (kind) {
616 case Contacts.KIND_PHONE:
617 return resources.getStringArray(android.R.array.phoneTypes);
618 case Contacts.KIND_EMAIL:
619 return resources.getStringArray(android.R.array.emailAddressTypes);
620 case Contacts.KIND_POSTAL:
621 return resources.getStringArray(android.R.array.postalAddressTypes);
622 case Contacts.KIND_IM:
623 return resources.getStringArray(android.R.array.imProtocols);
624 case Contacts.KIND_ORGANIZATION:
625 return resources.getStringArray(android.R.array.organizationTypes);
626 case EditEntry.KIND_CONTACT:
627 return resources.getStringArray(R.array.otherLabels);
628 }
629 return null;
630 }
631
632 int getTypeFromLabelPosition(CharSequence[] labels, int labelPosition) {
633 // In the UI Custom... comes last, but it is uses the constant 0
634 // so it is in the same location across the various kinds. Fix up the
635 // position to a valid type here.
636 if (labelPosition == labels.length - 1) {
637 return ContactMethods.TYPE_CUSTOM;
638 } else {
639 return labelPosition + 1;
640 }
641 }
642
643 public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
644 int childPosition, long id) {
645 EditEntry entry = null;
646
647 // Make the dialog go away
648 dismissDialog(LABEL_PICKER_ALL_TYPES_DIALOG);
649
650 // Create the new entry
651 switch (groupPosition) {
652 case LABEL_PICKER_PHONES_POSITION: {
653 String[] labels = getLabelsForKind(this, Contacts.KIND_PHONE);
654 final int type = getTypeFromLabelPosition(labels, childPosition);
655 entry = EditEntry.newPhoneEntry(EditContactActivity.this,
656 labels[childPosition], type,
657 null, Uri.withAppendedPath(mUri, People.Phones.CONTENT_DIRECTORY), 0);
658 if (type == Phones.TYPE_CUSTOM) {
659 createCustomPicker(entry, mPhoneEntries);
660 return true;
661 } else {
662 mPhoneEntries.add(entry);
663 }
664 break;
665 }
666
667 case LABEL_PICKER_EMAIL_POSITION: {
668 String[] labels = getLabelsForKind(this, Contacts.KIND_EMAIL);
669 final int type = getTypeFromLabelPosition(labels, childPosition);
670 entry = EditEntry.newEmailEntry(EditContactActivity.this,
671 labels[childPosition], type, null,
672 Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY), 0);
673 if (type == ContactMethods.TYPE_CUSTOM) {
674 createCustomPicker(entry, mEmailEntries);
675 return true;
676 } else {
677 mEmailEntries.add(entry);
678 }
679 break;
680 }
681
682 case LABEL_PICKER_IM_POSITION: {
683 String[] labels = getLabelsForKind(this, Contacts.KIND_IM);
684 entry = EditEntry.newImEntry(EditContactActivity.this,
685 labels[childPosition], childPosition, null,
686 Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY), 0);
687 mImEntries.add(entry);
688 break;
689 }
690
691 case LABEL_PICKER_POSTAL_POSITION: {
692 String[] labels = getLabelsForKind(this, Contacts.KIND_POSTAL);
693 final int type = getTypeFromLabelPosition(labels, childPosition);
694 entry = EditEntry.newPostalEntry(EditContactActivity.this,
695 labels[childPosition], type, null,
696 Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY), 0);
697 if (type == ContactMethods.TYPE_CUSTOM) {
698 createCustomPicker(entry, mPostalEntries);
699 return true;
700 } else {
701 mPostalEntries.add(entry);
702 }
703 break;
704 }
705
706 case LABEL_PICKER_OTHER_POSITION: {
707 switch (childPosition) {
708 case OTHER_ORGANIZATION:
709 entry = EditEntry.newOrganizationEntry(EditContactActivity.this,
710 Uri.withAppendedPath(mUri, Organizations.CONTENT_DIRECTORY),
The Android Open Source Projectd9351702008-12-17 18:05:55 -0800711 Organizations.TYPE_WORK);
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -0700712 mOtherEntries.add(entry);
713 break;
714
715 case OTHER_NOTE:
716 entry = EditEntry.newNotesEntry(EditContactActivity.this, null, mUri);
717 mOtherEntries.add(entry);
718 break;
719
720 default:
721 entry = null;
722 }
723 break;
724 }
725
726 default:
727 entry = null;
728 }
729
730 // Rebuild the views if needed
731 if (entry != null) {
732 buildViews();
733
734 View dataView = entry.view.findViewById(R.id.data);
735 if (dataView == null) {
736 entry.view.requestFocus();
737 } else {
738 dataView.requestFocus();
739 }
740 }
741 return true;
742 }
743
744 private EditEntry getRingtoneEntry() {
745 for (int i = mOtherEntries.size() - 1; i >= 0; i--) {
746 EditEntry entry = mOtherEntries.get(i);
747 if (isRingtoneEntry(entry)) {
748 return entry;
749 }
750 }
751 return null;
752 }
753
754 private static boolean isRingtoneEntry(EditEntry entry) {
755 return entry != null && entry.column != null && entry.column.equals(People.CUSTOM_RINGTONE);
756 }
757
758 private Dialog createAllTypesPicker() {
759 // Setup the adapter
760 List<Map<String, ?>> groupData = Lists.newArrayList();
761 List<List<Map<String, ?>>> childData = Lists.newArrayList();
762 List<Map<String, ?>> children;
763 HashMap<String, CharSequence> curGroupMap;
764 CharSequence[] labels;
765 int labelsSize;
766
767 // Phones
768 curGroupMap = new HashMap<String, CharSequence>();
769 groupData.add(curGroupMap);
770 curGroupMap.put("data", getText(R.string.phoneLabelsGroup));
771
772 labels = getLabelsForKind(this, Contacts.KIND_PHONE);
773 labelsSize = labels.length;
774 children = Lists.newArrayList();
775 for (int i = 0; i < labelsSize; i++) {
776 HashMap<String, CharSequence> curChildMap = new HashMap<String, CharSequence>();
777 children.add(curChildMap);
778 curChildMap.put("data", labels[i]);
779 }
780 childData.add(LABEL_PICKER_PHONES_POSITION, children);
781
782 // Email
783 curGroupMap = new HashMap<String, CharSequence>();
784 groupData.add(curGroupMap);
785 curGroupMap.put("data", getText(R.string.emailLabelsGroup));
786
787 labels = getLabelsForKind(this, Contacts.KIND_EMAIL);
788 labelsSize = labels.length;
789 children = Lists.newArrayList();
790 for (int i = 0; i < labelsSize; i++) {
791 HashMap<String, CharSequence> curChildMap = new HashMap<String, CharSequence>();
792 children.add(curChildMap);
793 curChildMap.put("data", labels[i]);
794 }
795 childData.add(LABEL_PICKER_EMAIL_POSITION, children);
796
797 // IM
798 curGroupMap = new HashMap<String, CharSequence>();
799 groupData.add(curGroupMap);
800 curGroupMap.put("data", getText(R.string.imLabelsGroup));
801
802 labels = getLabelsForKind(this, Contacts.KIND_IM);
803 labelsSize = labels.length;
804 children = Lists.newArrayList();
805 for (int i = 0; i < labelsSize; i++) {
806 HashMap<String, CharSequence> curChildMap = new HashMap<String, CharSequence>();
807 children.add(curChildMap);
808 curChildMap.put("data", labels[i]);
809 }
810 childData.add(LABEL_PICKER_IM_POSITION, children);
811
812 // Postal
813 curGroupMap = new HashMap<String, CharSequence>();
814 groupData.add(curGroupMap);
815 curGroupMap.put("data", getText(R.string.postalLabelsGroup));
816
817 labels = getLabelsForKind(this, Contacts.KIND_POSTAL);
818 labelsSize = labels.length;
819 children = Lists.newArrayList();
820 for (int i = 0; i < labelsSize; i++) {
821 HashMap<String, CharSequence> curChildMap = new HashMap<String, CharSequence>();
822 children.add(curChildMap);
823 curChildMap.put("data", labels[i]);
824 }
825 childData.add(LABEL_PICKER_POSTAL_POSITION, children);
826
827 // Other
828 curGroupMap = new HashMap<String, CharSequence>();
829 groupData.add(curGroupMap);
830 curGroupMap.put("data", getText(R.string.otherLabelsGroup));
831
832 labels = getLabelsForKind(this, EditEntry.KIND_CONTACT);
833 labelsSize = labels.length;
834 children = Lists.newArrayList();
835 for (int i = 0; i < labelsSize; i++) {
836 HashMap<String, CharSequence> curChildMap = new HashMap<String, CharSequence>();
837 children.add(curChildMap);
838 curChildMap.put("data", labels[i]);
839 }
840 childData.add(LABEL_PICKER_OTHER_POSITION, children);
841
842 // Create the expandable list view
843 ExpandableListView list = new ExpandableListView(new ContextThemeWrapper(this,
844 android.R.style.Theme_Light));
845 list.setOnChildClickListener(this);
846 list.setAdapter(new SimpleExpandableListAdapter(
847 new ContextThemeWrapper(this, android.R.style.Theme_Light),
848 groupData,
849 android.R.layout.simple_expandable_list_item_1,
850 new String[] { "data" },
851 new int[] { android.R.id.text1 },
852 childData,
853 android.R.layout.simple_expandable_list_item_1,
854 new String[] { "data" },
855 new int[] { android.R.id.text1 }
856 ));
857 // This list shouldn't have a color hint since the dialog may be transparent
858 list.setCacheColorHint(0);
859
860 // Create the dialog
861 return new AlertDialog.Builder(this).setView(list).setInverseBackgroundForced(true)
862 .setTitle(R.string.selectLabel).create();
863 }
864
865 private void createCustomPicker(final EditEntry entry, final ArrayList<EditEntry> addTo) {
866 final EditText label = new EditText(this);
867 label.setKeyListener(TextKeyListener.getInstance(false, Capitalize.WORDS));
868 label.requestFocus();
869 new AlertDialog.Builder(this)
870 .setView(label)
871 .setTitle(R.string.customLabelPickerTitle)
The Android Open Source Projectd9351702008-12-17 18:05:55 -0800872 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -0700873 public void onClick(DialogInterface dialog, int which) {
874 entry.setLabel(EditContactActivity.this, ContactMethods.TYPE_CUSTOM,
875 label.getText().toString());
876 if (addTo != null) {
877 addTo.add(entry);
878 buildViews();
879 entry.view.requestFocus(View.FOCUS_DOWN);
880 }
881 }
882 })
The Android Open Source Projectd9351702008-12-17 18:05:55 -0800883 .setNegativeButton(android.R.string.cancel, null)
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -0700884 .show();
885 }
886
887 /**
888 * Saves or creates the contact based on the mode, and if sucessful finishes the activity.
889 */
890 private void doSaveAction() {
891 // Save or create the contact if needed
892 switch (mState) {
893 case STATE_EDIT:
894 save();
895 break;
896
897 case STATE_INSERT:
898 create();
899 break;
900
901 default:
902 Log.e(TAG, "Unknown state in doSaveOrCreate: " + mState);
903 break;
904 }
905 finish();
906 }
907
908 /**
909 * Save the various fields to the existing contact.
910 */
911 private void save() {
912 ContentValues values = new ContentValues();
913 String data;
914 int numValues = 0;
915
916 // Handle the name and send to voicemail specially
917 final String name = mNameView.getText().toString();
918 if (name != null && TextUtils.isGraphic(name)) {
919 numValues++;
920 }
921 values.put(People.NAME, name);
922 values.put(People.SEND_TO_VOICEMAIL, mSendToVoicemailCheckBox.isChecked() ? 1 : 0);
923 mResolver.update(mUri, values, null, null);
924
925 if (mPhotoChanged) {
926 // Only write the photo if it's changed, since we don't initially load mPhoto
927 if (mPhoto != null) {
928 ByteArrayOutputStream stream = new ByteArrayOutputStream();
929 mPhoto.compress(Bitmap.CompressFormat.JPEG, 75, stream);
930 Contacts.People.setPhotoData(mResolver, mUri, stream.toByteArray());
931 } else {
932 Contacts.People.setPhotoData(mResolver, mUri, null);
933 }
934 }
935
936 int entryCount = ContactEntryAdapter.countEntries(mSections, false);
937 for (int i = 0; i < entryCount; i++) {
938 EditEntry entry = ContactEntryAdapter.getEntry(mSections, i, false);
939 int kind = entry.kind;
940 data = entry.getData();
941 boolean empty = data == null || !TextUtils.isGraphic(data);
942 if (kind == EditEntry.KIND_CONTACT) {
943 values.clear();
944 if (!empty) {
945 values.put(entry.column, data);
946 mResolver.update(entry.uri, values, null, null);
947 numValues++;
948 } else {
949 values.put(entry.column, (String) null);
950 mResolver.update(entry.uri, values, null, null);
951 }
952 } else {
953 if (!empty) {
954 values.clear();
955 entry.toValues(values);
956 if (entry.id != 0) {
957 mResolver.update(entry.uri, values, null, null);
958 } else {
959 mResolver.insert(entry.uri, values);
960 }
961 numValues++;
962 } else if (entry.id != 0) {
963 mResolver.delete(entry.uri, null, null);
964 }
965 }
966 }
967
968 if (numValues == 0) {
969 // The contact is completely empty, delete it
970 mResolver.delete(mUri, null, null);
971 mUri = null;
972 setResult(RESULT_CANCELED);
973 } else {
974 // Add the entry to the my contacts group if it isn't there already
975 People.addToMyContactsGroup(mResolver, ContentUris.parseId(mUri));
976 setResult(RESULT_OK, new Intent().setData(mUri));
977 Toast.makeText(this, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
978 }
979 }
980
981 /**
982 * Takes the entered data and saves it to a new contact.
983 */
984 private void create() {
985 ContentValues values = new ContentValues();
986 String data;
987 int numValues = 0;
988
989 // Create the contact itself
990 final String name = mNameView.getText().toString();
991 if (name != null && TextUtils.isGraphic(name)) {
992 numValues++;
993 }
994 values.put(People.NAME, name);
995 values.put(People.SEND_TO_VOICEMAIL, mSendToVoicemailCheckBox.isChecked() ? 1 : 0);
996
997 // Add the contact to the My Contacts group
998 Uri contactUri = People.createPersonInMyContactsGroup(mResolver, values);
999
1000 // Add the contact to the group that is being displayed in the contact list
1001 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001002 int displayType = prefs.getInt(ContactsListActivity.PREF_DISPLAY_TYPE,
1003 ContactsListActivity.DISPLAY_TYPE_UNKNOWN);
1004 if (displayType == ContactsListActivity.DISPLAY_TYPE_USER_GROUP) {
1005 String displayGroup = prefs.getString(ContactsListActivity.PREF_DISPLAY_INFO,
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001006 null);
1007 if (!TextUtils.isEmpty(displayGroup)) {
1008 People.addToGroup(mResolver, ContentUris.parseId(contactUri), displayGroup);
1009 }
1010 }
1011
1012 // Handle the photo
1013 if (mPhoto != null) {
1014 ByteArrayOutputStream stream = new ByteArrayOutputStream();
1015 mPhoto.compress(Bitmap.CompressFormat.JPEG, 75, stream);
1016 Contacts.People.setPhotoData(getContentResolver(), contactUri, stream.toByteArray());
1017 }
1018
1019 // Create the contact methods
1020 int entryCount = ContactEntryAdapter.countEntries(mSections, false);
1021 for (int i = 0; i < entryCount; i++) {
1022 EditEntry entry = ContactEntryAdapter.getEntry(mSections, i, false);
1023 if (entry.kind != EditEntry.KIND_CONTACT) {
1024 values.clear();
1025 if (entry.toValues(values)) {
1026 // Only create the entry if there is data
1027 entry.uri = mResolver.insert(
1028 Uri.withAppendedPath(contactUri, entry.contentDirectory), values);
1029 entry.id = ContentUris.parseId(entry.uri);
1030 numValues++;
1031 }
1032 } else {
1033 // Update the contact with any straggling data, like notes
1034 data = entry.getData();
1035 values.clear();
1036 if (data != null && TextUtils.isGraphic(data)) {
1037 values.put(entry.column, data);
1038 mResolver.update(contactUri, values, null, null);
1039 numValues++;
1040 }
1041 }
1042 }
1043
1044 if (numValues == 0) {
1045 mResolver.delete(contactUri, null, null);
1046 setResult(RESULT_CANCELED);
1047 } else {
1048 mUri = contactUri;
1049 Intent resultIntent = new Intent()
1050 .setData(mUri)
1051 .putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
1052 setResult(RESULT_OK, resultIntent);
1053 Toast.makeText(this, R.string.contactCreatedToast, Toast.LENGTH_SHORT).show();
1054 }
1055 }
1056
1057 /**
1058 * Build up the entries to display on the screen.
1059 *
1060 * @param extras the extras used to start this activity, may be null
1061 */
1062 private void buildEntriesForEdit(Bundle extras) {
1063 Cursor personCursor = mResolver.query(mUri, CONTACT_PROJECTION, null, null, null);
1064 if (personCursor == null) {
1065 Log.e(TAG, "invalid contact uri: " + mUri);
1066 finish();
1067 return;
1068 } else if (!personCursor.moveToFirst()) {
1069 Log.e(TAG, "invalid contact uri: " + mUri);
1070 finish();
1071 personCursor.close();
1072 return;
1073 }
1074
1075 // Clear out the old entries
1076 int numSections = mSections.size();
1077 for (int i = 0; i < numSections; i++) {
1078 mSections.get(i).clear();
1079 }
1080
1081 EditEntry entry;
1082
1083 // Name
1084 mNameView.setText(personCursor.getString(CONTACT_NAME_COLUMN));
1085
1086 // Photo
1087 mPhoto = People.loadContactPhoto(this, mUri, 0, null);
1088 if (mPhoto == null) {
1089 setPhotoPresent(false);
1090 } else {
1091 setPhotoPresent(true);
1092 mPhotoImageView.setImageBitmap(mPhoto);
1093 }
1094
1095 // Send to voicemail
1096 mSendToVoicemailCheckBox
1097 .setChecked(personCursor.getInt(CONTACT_SEND_TO_VOICEMAIL_COLUMN) == 1);
1098
1099 // Organizations
1100 Uri organizationsUri = Uri.withAppendedPath(mUri, Organizations.CONTENT_DIRECTORY);
1101 Cursor organizationsCursor = mResolver.query(organizationsUri, ORGANIZATIONS_PROJECTION,
1102 null, null, null);
1103
1104 if (organizationsCursor != null) {
1105 while (organizationsCursor.moveToNext()) {
1106 int type = organizationsCursor.getInt(ORGANIZATIONS_TYPE_COLUMN);
1107 String label = organizationsCursor.getString(ORGANIZATIONS_LABEL_COLUMN);
1108 String company = organizationsCursor.getString(ORGANIZATIONS_COMPANY_COLUMN);
1109 String title = organizationsCursor.getString(ORGANIZATIONS_TITLE_COLUMN);
1110 long id = organizationsCursor.getLong(ORGANIZATIONS_ID_COLUMN);
1111 Uri uri = ContentUris.withAppendedId(Organizations.CONTENT_URI, id);
1112
1113 // Add an organization entry
1114 entry = EditEntry.newOrganizationEntry(this, label, type, company, title, uri, id);
1115 entry.isPrimary = organizationsCursor.getLong(ORGANIZATIONS_ISPRIMARY_COLUMN) != 0;
1116 mOtherEntries.add(entry);
1117 }
1118 organizationsCursor.close();
1119 }
1120
1121 // Notes
1122 if (!personCursor.isNull(CONTACT_NOTES_COLUMN)) {
1123 entry = EditEntry.newNotesEntry(this, personCursor.getString(CONTACT_NOTES_COLUMN),
1124 mUri);
1125 mOtherEntries.add(entry);
1126 }
1127
1128 // Ringtone
1129 entry = EditEntry.newRingtoneEntry(this,
1130 personCursor.getString(CONTACT_CUSTOM_RINGTONE_COLUMN), mUri);
1131 mOtherEntries.add(entry);
1132 personCursor.close();
1133
1134 // Build up the phone entries
1135 Uri phonesUri = Uri.withAppendedPath(mUri, People.Phones.CONTENT_DIRECTORY);
1136 Cursor phonesCursor = mResolver.query(phonesUri, PHONES_PROJECTION,
1137 null, null, null);
1138
1139 if (phonesCursor != null) {
1140 while (phonesCursor.moveToNext()) {
1141 int type = phonesCursor.getInt(PHONES_TYPE_COLUMN);
1142 String label = phonesCursor.getString(PHONES_LABEL_COLUMN);
1143 String number = phonesCursor.getString(PHONES_NUMBER_COLUMN);
1144 long id = phonesCursor.getLong(PHONES_ID_COLUMN);
1145 boolean isPrimary = phonesCursor.getLong(PHONES_ISPRIMARY_COLUMN) != 0;
1146 Uri uri = ContentUris.withAppendedId(phonesUri, id);
1147
1148 // Add a phone number entry
1149 entry = EditEntry.newPhoneEntry(this, label, type, number, uri, id);
1150 entry.isPrimary = isPrimary;
1151 mPhoneEntries.add(entry);
1152
1153 // Keep track of which primary types have been added
1154 if (type == Phones.TYPE_MOBILE) {
1155 mMobilePhoneAdded = true;
1156 }
1157 }
1158
1159 phonesCursor.close();
1160 }
1161
1162 // Build the contact method entries
1163 Uri methodsUri = Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY);
1164 Cursor methodsCursor = mResolver.query(methodsUri, METHODS_PROJECTION, null, null, null);
1165
1166 if (methodsCursor != null) {
1167 while (methodsCursor.moveToNext()) {
1168 int kind = methodsCursor.getInt(METHODS_KIND_COLUMN);
1169 String label = methodsCursor.getString(METHODS_LABEL_COLUMN);
1170 String data = methodsCursor.getString(METHODS_DATA_COLUMN);
1171 String auxData = methodsCursor.getString(METHODS_AUX_DATA_COLUMN);
1172 int type = methodsCursor.getInt(METHODS_TYPE_COLUMN);
1173 long id = methodsCursor.getLong(METHODS_ID_COLUMN);
1174 boolean isPrimary = methodsCursor.getLong(METHODS_ISPRIMARY_COLUMN) != 0;
1175 Uri uri = ContentUris.withAppendedId(methodsUri, id);
1176
1177 switch (kind) {
1178 case Contacts.KIND_EMAIL: {
1179 entry = EditEntry.newEmailEntry(this, label, type, data, uri, id);
1180 entry.isPrimary = isPrimary;
1181 mEmailEntries.add(entry);
1182
1183 if (isPrimary) {
1184 mPrimaryEmailAdded = true;
1185 }
1186 break;
1187 }
1188
1189 case Contacts.KIND_POSTAL: {
1190 entry = EditEntry.newPostalEntry(this, label, type, data, uri, id);
1191 entry.isPrimary = isPrimary;
1192 mPostalEntries.add(entry);
1193 break;
1194 }
1195
1196 case Contacts.KIND_IM: {
1197 Object protocolObj = ContactMethods.decodeImProtocol(auxData);
1198 if (protocolObj == null) {
1199 // Invalid IM protocol, log it then ignore.
1200 Log.e(TAG, "Couldn't decode IM protocol: " + auxData);
1201 continue;
1202 } else {
1203 if (protocolObj instanceof Number) {
1204 int protocol = ((Number) protocolObj).intValue();
1205 entry = EditEntry.newImEntry(this,
1206 getLabelsForKind(this, Contacts.KIND_IM)[protocol], protocol,
1207 data, uri, id);
1208 } else {
1209 entry = EditEntry.newImEntry(this, protocolObj.toString(), -1, data,
1210 uri, id);
1211 }
1212 mImEntries.add(entry);
1213 }
1214 break;
1215 }
1216 }
1217 }
1218
1219 methodsCursor.close();
1220 }
1221
1222 // Add values from the extras, if there are any
1223 if (extras != null) {
1224 addFromExtras(extras, phonesUri, methodsUri);
1225 }
1226
1227 // Add the base types if needed
1228 if (!mMobilePhoneAdded) {
1229 entry = EditEntry.newPhoneEntry(this,
1230 Uri.withAppendedPath(mUri, People.Phones.CONTENT_DIRECTORY),
1231 DEFAULT_PHONE_TYPE);
1232 mPhoneEntries.add(entry);
1233 }
1234
1235 if (!mPrimaryEmailAdded) {
1236 entry = EditEntry.newEmailEntry(this,
1237 Uri.withAppendedPath(mUri, People.ContactMethods.CONTENT_DIRECTORY),
1238 DEFAULT_EMAIL_TYPE);
1239 entry.isPrimary = true;
1240 mEmailEntries.add(entry);
1241 }
1242 }
1243
1244 /**
1245 * Build the list of EditEntries for full mode insertions.
1246 *
1247 * @param extras the extras used to start this activity, may be null
1248 */
1249 private void buildEntriesForInsert(Bundle extras) {
1250 // Clear out the old entries
1251 int numSections = mSections.size();
1252 for (int i = 0; i < numSections; i++) {
1253 mSections.get(i).clear();
1254 }
1255
1256 EditEntry entry;
1257
1258 // Check the intent extras
1259 if (extras != null) {
1260 addFromExtras(extras, null, null);
1261 }
1262
1263 // Photo
1264 mPhotoImageView.setImageResource(R.drawable.ic_contact_picture);
1265
1266 // Add the base entries if they're not already present
1267 if (!mMobilePhoneAdded) {
1268 entry = EditEntry.newPhoneEntry(this, null, Phones.TYPE_MOBILE);
1269 entry.isPrimary = true;
1270 mPhoneEntries.add(entry);
1271 }
1272
1273 if (!mPrimaryEmailAdded) {
1274 entry = EditEntry.newEmailEntry(this, null, DEFAULT_EMAIL_TYPE);
1275 entry.isPrimary = true;
1276 mEmailEntries.add(entry);
1277 }
1278
1279 // Ringtone
1280 entry = EditEntry.newRingtoneEntry(this, null, mUri);
1281 mOtherEntries.add(entry);
1282
1283 }
1284
1285 private void addFromExtras(Bundle extras, Uri phonesUri, Uri methodsUri) {
1286 EditEntry entry;
1287
1288 // Read the name from the bundle
1289 CharSequence name = extras.getCharSequence(Insert.NAME);
1290 if (name != null && TextUtils.isGraphic(name)) {
1291 mNameView.setText(name);
1292 }
1293
1294 // Postal entries from extras
1295 CharSequence postal = extras.getCharSequence(Insert.POSTAL);
1296 int postalType = extras.getInt(Insert.POSTAL_TYPE, INVALID_TYPE);
1297 if (!TextUtils.isEmpty(postal) && postalType == INVALID_TYPE) {
1298 postalType = DEFAULT_POSTAL_TYPE;
1299 }
1300
1301 if (postalType != INVALID_TYPE) {
1302 entry = EditEntry.newPostalEntry(this, null, postalType, postal.toString(),
1303 methodsUri, 0);
1304 entry.isPrimary = extras.getBoolean(Insert.POSTAL_ISPRIMARY);
1305 mPostalEntries.add(entry);
1306 }
1307
1308 // Email entries from extras
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001309 addEmailFromExtras(extras, methodsUri, Insert.EMAIL, Insert.EMAIL_TYPE,
1310 Insert.EMAIL_ISPRIMARY);
1311 addEmailFromExtras(extras, methodsUri, Insert.SECONDARY_EMAIL, Insert.SECONDARY_EMAIL_TYPE,
1312 null);
1313 addEmailFromExtras(extras, methodsUri, Insert.TERTIARY_EMAIL, Insert.TERTIARY_EMAIL_TYPE,
1314 null);
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001315
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001316 // Phone entries from extras
1317 addPhoneFromExtras(extras, phonesUri, Insert.PHONE, Insert.PHONE_TYPE,
1318 Insert.PHONE_ISPRIMARY);
1319 addPhoneFromExtras(extras, phonesUri, Insert.SECONDARY_PHONE, Insert.SECONDARY_PHONE_TYPE,
1320 null);
1321 addPhoneFromExtras(extras, phonesUri, Insert.TERTIARY_PHONE, Insert.TERTIARY_PHONE_TYPE,
1322 null);
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001323
1324 // IM entries from extras
1325 CharSequence imHandle = extras.getCharSequence(Insert.IM_HANDLE);
1326 CharSequence imProtocol = extras.getCharSequence(Insert.IM_PROTOCOL);
1327
1328 if (imHandle != null && imProtocol != null) {
1329 Object protocolObj = ContactMethods.decodeImProtocol(imProtocol.toString());
1330 if (protocolObj instanceof Number) {
1331 int protocol = ((Number) protocolObj).intValue();
1332 entry = EditEntry.newImEntry(this,
1333 getLabelsForKind(this, Contacts.KIND_IM)[protocol], protocol,
1334 imHandle.toString(), null, 0);
1335 } else {
1336 entry = EditEntry.newImEntry(this, protocolObj.toString(), -1, imHandle.toString(),
1337 null, 0);
1338 }
1339 entry.isPrimary = extras.getBoolean(Insert.IM_ISPRIMARY);
1340 mImEntries.add(entry);
1341 }
1342 }
1343
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001344 private void addEmailFromExtras(Bundle extras, Uri methodsUri, String emailField,
1345 String typeField, String primaryField) {
1346 CharSequence email = extras.getCharSequence(emailField);
1347 int emailType = extras.getInt(typeField, INVALID_TYPE);
1348 if (!TextUtils.isEmpty(email) && emailType == INVALID_TYPE) {
1349 emailType = DEFAULT_EMAIL_TYPE;
1350 mPrimaryEmailAdded = true;
1351 }
1352
1353 if (emailType != INVALID_TYPE) {
1354 EditEntry entry = EditEntry.newEmailEntry(this, null, emailType, email.toString(),
1355 methodsUri, 0);
1356 entry.isPrimary = (primaryField == null) ? false : extras.getBoolean(primaryField);
1357 mEmailEntries.add(entry);
1358
1359 // Keep track of which primary types have been added
1360 if (entry.isPrimary) {
1361 mPrimaryEmailAdded = true;
1362 }
1363 }
1364 }
1365
1366 private void addPhoneFromExtras(Bundle extras, Uri phonesUri, String phoneField,
1367 String typeField, String primaryField) {
1368 CharSequence phoneNumber = extras.getCharSequence(phoneField);
1369 int phoneType = extras.getInt(typeField, INVALID_TYPE);
1370 if (!TextUtils.isEmpty(phoneNumber) && phoneType == INVALID_TYPE) {
1371 phoneType = DEFAULT_PHONE_TYPE;
1372 }
1373
1374 if (phoneType != INVALID_TYPE) {
1375 EditEntry entry = EditEntry.newPhoneEntry(this, null, phoneType,
1376 phoneNumber.toString(), phonesUri, 0);
1377 entry.isPrimary = (primaryField == null) ? false : extras.getBoolean(primaryField);
1378 mPhoneEntries.add(entry);
1379
1380 // Keep track of which primary types have been added
1381 if (phoneType == Phones.TYPE_MOBILE) {
1382 mMobilePhoneAdded = true;
1383 }
1384 }
1385 }
1386
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001387 /**
1388 * Removes all existing views, builds new ones for all the entries, and adds them.
1389 */
1390 private void buildViews() {
1391 // Remove existing views
1392 final LinearLayout layout = mLayout;
1393 layout.removeAllViews();
1394
1395 buildViewsForSection(layout, mPhoneEntries, R.string.listSeparatorCallNumber);
1396 buildViewsForSection(layout, mEmailEntries, R.string.listSeparatorSendEmail);
1397 buildViewsForSection(layout, mImEntries, R.string.listSeparatorSendIm);
1398 buildViewsForSection(layout, mPostalEntries, R.string.listSeparatorMapAddress);
1399 buildViewsForSection(layout, mOtherEntries, R.string.listSeparatorOtherInformation);
1400 }
1401
1402
1403 /**
1404 * Builds the views for a specific section.
1405 *
1406 * @param layout the container
1407 * @param section the section to build the views for
1408 */
1409 private void buildViewsForSection(final LinearLayout layout, ArrayList<EditEntry> section,
1410 int separatorResource) {
1411 // Build the separator if the section isn't empty
1412 if (section.size() > 0) {
1413 View separator = mInflater.inflate(R.layout.edit_separator, layout, false);
1414 TextView text = (TextView) separator.findViewById(R.id.text);
1415 text.setText(getText(separatorResource));
1416 layout.addView(separator);
1417 }
1418
1419 // Build views for the current section
1420 for (EditEntry entry : section) {
1421 entry.activity = this; // this could be null from when the state is restored
1422 if (!entry.isDeleted) {
1423 View view = buildViewForEntry(entry);
1424 layout.addView(view);
1425 }
1426 }
1427 }
1428
1429 /**
1430 * Builds a view to display an EditEntry.
1431 *
1432 * @param entry the entry to display
1433 * @return a view that will display the given entry
1434 */
1435 /* package */ View buildViewForEntry(final EditEntry entry) {
1436 // Look for any existing entered text, and save it if found
1437 if (entry.view != null && entry.syncDataWithView) {
1438 String enteredText = ((TextView) entry.view.findViewById(R.id.data))
1439 .getText().toString();
1440 if (!TextUtils.isEmpty(enteredText)) {
1441 entry.data = enteredText;
1442 }
1443 }
1444
1445 // Build a new view
1446 final ViewGroup parent = mLayout;
1447 View view;
1448
1449 if (entry.kind == Contacts.KIND_ORGANIZATION) {
1450 view = mInflater.inflate(R.layout.edit_contact_entry_org, parent, false);
1451 } else if (isRingtoneEntry(entry)) {
1452 view = mInflater.inflate(R.layout.edit_contact_entry_ringtone, parent, false);
1453 } else if (!entry.isStaticLabel) {
1454 view = mInflater.inflate(R.layout.edit_contact_entry, parent, false);
1455 } else {
1456 view = mInflater.inflate(R.layout.edit_contact_entry_static_label, parent, false);
1457 }
1458 entry.view = view;
1459
1460 // Set the entry as the tag so we can find it again later given just the view
1461 view.setTag(entry);
1462
1463 // Bind the label
1464 entry.bindLabel(this);
1465
1466 // Bind data
1467 TextView data = (TextView) view.findViewById(R.id.data);
1468 TextView data2 = (TextView) view.findViewById(R.id.data2);
1469
1470 if (data instanceof Button) {
1471 data.setOnClickListener(this);
1472 }
1473 if (data.length() == 0) {
1474 if (entry.syncDataWithView) {
1475 // If there is already data entered don't overwrite it
1476 data.setText(entry.data);
1477 } else {
1478 fillViewData(entry);
1479 }
1480 }
1481 if (data2 != null && data2.length() == 0) {
1482 // If there is already data entered don't overwrite it
1483 data2.setText(entry.data2);
1484 }
1485 data.setHint(entry.hint);
1486 if (data2 != null) data2.setHint(entry.hint2);
1487 if (entry.lines > 1) {
1488 data.setLines(entry.lines);
1489 data.setMaxLines(entry.maxLines);
1490 if (data2 != null) {
1491 data2.setLines(entry.lines);
1492 data2.setMaxLines(entry.maxLines);
1493 }
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001494 }
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001495 int contentType = entry.contentType;
1496 if (contentType != EditorInfo.TYPE_NULL) {
1497 data.setInputType(contentType);
1498 if (data2 != null) {
1499 data2.setInputType(contentType);
1500 }
1501 if ((contentType&EditorInfo.TYPE_MASK_CLASS)
1502 == EditorInfo.TYPE_CLASS_PHONE) {
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001503 data.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
1504 if (data2 != null) {
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001505 data2.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
1506 }
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001507 }
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001508 }
1509
1510 // Hook up the delete button
1511 View delete = view.findViewById(R.id.delete);
1512 if (delete != null) delete.setOnClickListener(this);
1513 View delete2 = view.findViewById(R.id.delete2);
1514 if (delete2 != null) delete2.setOnClickListener(this);
1515
1516 return view;
1517 }
1518
1519 private void fillViewData(final EditEntry entry) {
1520 if (isRingtoneEntry(entry)) {
1521 updateRingtoneView(entry);
1522 }
1523 }
1524
1525 /**
1526 * Handles the results from the label change picker.
1527 */
1528 private final class LabelPickedListener implements DialogInterface.OnClickListener {
1529 EditEntry mEntry;
1530 String[] mLabels;
1531
1532 public LabelPickedListener(EditEntry entry, String[] labels) {
1533 mEntry = entry;
1534 mLabels = labels;
1535 }
1536
1537 public void onClick(DialogInterface dialog, int which) {
1538 // TODO: Use a managed dialog
1539 if (mEntry.kind != Contacts.KIND_IM) {
1540 final int type = getTypeFromLabelPosition(mLabels, which);
1541 if (type == ContactMethods.TYPE_CUSTOM) {
1542 createCustomPicker(mEntry, null);
1543 } else {
1544 mEntry.setLabel(EditContactActivity.this, type, mLabels[which]);
1545 }
1546 } else {
1547 mEntry.setLabel(EditContactActivity.this, which, mLabels[which]);
1548 }
1549 }
1550 }
1551
1552 /**
1553 * A basic structure with the data for a contact entry in the list.
1554 */
1555 private static final class EditEntry extends ContactEntryAdapter.Entry implements Parcelable {
1556 // These aren't stuffed into the parcel
1557 public EditContactActivity activity;
1558 public View view;
1559
1560 // These are stuffed into the parcel
1561 public String hint;
1562 public String hint2;
1563 public String column;
1564 public String contentDirectory;
1565 public String data2;
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001566 public int contentType;
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001567 public int type;
1568 /**
1569 * If 0 or 1, setSingleLine will be called. If negative, setSingleLine
1570 * will not be called.
1571 */
1572 public int lines = 1;
1573 public boolean isPrimary;
1574 public boolean isDeleted = false;
1575 public boolean isStaticLabel = false;
1576 public boolean syncDataWithView = true;
1577
1578 private EditEntry() {
1579 // only used by CREATOR
1580 }
1581
1582 public EditEntry(EditContactActivity activity) {
1583 this.activity = activity;
1584 }
1585
1586 public EditEntry(EditContactActivity activity, String label,
1587 int type, String data, Uri uri, long id) {
1588 this.activity = activity;
1589 this.isPrimary = false;
1590 this.label = label;
1591 this.type = type;
1592 this.data = data;
1593 this.uri = uri;
1594 this.id = id;
1595 }
1596
1597 public int describeContents() {
1598 return 0;
1599 }
1600
1601 public void writeToParcel(Parcel parcel, int flags) {
1602 // Make sure to read data from the input field, if anything is entered
1603 data = getData();
1604
1605 // Write in our own fields.
1606 parcel.writeString(hint);
1607 parcel.writeString(hint2);
1608 parcel.writeString(column);
1609 parcel.writeString(contentDirectory);
1610 parcel.writeString(data2);
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001611 parcel.writeInt(contentType);
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001612 parcel.writeInt(type);
1613 parcel.writeInt(lines);
1614 parcel.writeInt(isPrimary ? 1 : 0);
1615 parcel.writeInt(isDeleted ? 1 : 0);
1616 parcel.writeInt(isStaticLabel ? 1 : 0);
1617 parcel.writeInt(syncDataWithView ? 1 : 0);
1618
1619 // Write in the fields from Entry
1620 super.writeToParcel(parcel);
1621 }
1622
1623 public static final Parcelable.Creator<EditEntry> CREATOR =
1624 new Parcelable.Creator<EditEntry>() {
1625 public EditEntry createFromParcel(Parcel in) {
1626 EditEntry entry = new EditEntry();
1627
1628 // Read out our own fields
1629 entry.hint = in.readString();
1630 entry.hint2 = in.readString();
1631 entry.column = in.readString();
1632 entry.contentDirectory = in.readString();
1633 entry.data2 = in.readString();
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001634 entry.contentType = in.readInt();
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001635 entry.type = in.readInt();
1636 entry.lines = in.readInt();
1637 entry.isPrimary = in.readInt() == 1;
1638 entry.isDeleted = in.readInt() == 1;
1639 entry.isStaticLabel = in.readInt() == 1;
1640 entry.syncDataWithView = in.readInt() == 1;
1641
1642 // Read out the fields from Entry
1643 entry.readFromParcel(in);
1644
1645 return entry;
1646 }
1647
1648 public EditEntry[] newArray(int size) {
1649 return new EditEntry[size];
1650 }
1651 };
1652
1653 public void setLabel(Context context, int typeIn, String labelIn) {
1654 type = typeIn;
1655 label = labelIn;
1656 if (view != null) {
1657 bindLabel(context);
1658 }
1659 }
1660
1661 public void bindLabel(Context context) {
1662 TextView v = (TextView) view.findViewById(R.id.label);
1663 if (isStaticLabel) {
1664 v.setText(label);
1665 return;
1666 }
1667
1668 switch (kind) {
1669 case Contacts.KIND_PHONE: {
1670 v.setText(Phones.getDisplayLabel(context, type, label));
1671 break;
1672 }
1673
1674 case Contacts.KIND_IM: {
1675 v.setText(getLabelsForKind(activity, kind)[type]);
1676 break;
1677 }
1678
1679 case Contacts.KIND_ORGANIZATION: {
1680 v.setText(Organizations.getDisplayLabel(activity, type, label));
1681 break;
1682 }
1683
1684 default: {
1685 v.setText(Contacts.ContactMethods.getDisplayLabel(context, kind, type, label));
1686 if (kind == Contacts.KIND_POSTAL) {
1687 v.setMaxLines(3);
1688 }
1689 break;
1690 }
1691 }
1692 v.setOnClickListener(activity);
1693 }
1694
1695 /**
1696 * Returns the data for the entry
1697 * @return the data for the entry
1698 */
1699 public String getData() {
1700 if (view != null && syncDataWithView) {
1701 CharSequence text = ((TextView) view.findViewById(R.id.data)).getText();
1702 if (text != null) {
1703 return text.toString();
1704 }
1705 }
1706
1707 if (data != null) {
1708 return data.toString();
1709 }
1710
1711 return null;
1712 }
1713
1714 /**
1715 * Dumps the entry into a HashMap suitable for passing to the database.
1716 *
1717 * @param values the HashMap to fill in.
1718 * @return true if the value should be saved, false otherwise
1719 */
1720 public boolean toValues(ContentValues values) {
1721 boolean success = false;
1722 String labelString = null;
1723 // Save the type and label
1724 if (view != null) {
1725 // Read the possibly updated label from the text field
1726 labelString = ((TextView) view.findViewById(R.id.label)).getText().toString();
1727 }
1728 switch (kind) {
1729 case Contacts.KIND_PHONE:
1730 if (type != Phones.TYPE_CUSTOM) {
1731 labelString = null;
1732 }
1733 values.put(Phones.LABEL, labelString);
1734 values.put(Phones.TYPE, type);
1735 break;
1736
1737 case Contacts.KIND_EMAIL:
1738 if (type != ContactMethods.TYPE_CUSTOM) {
1739 labelString = null;
1740 }
1741 values.put(ContactMethods.LABEL, labelString);
1742 values.put(ContactMethods.KIND, kind);
1743 values.put(ContactMethods.TYPE, type);
1744 break;
1745
1746 case Contacts.KIND_IM:
1747 values.put(ContactMethods.KIND, kind);
1748 values.put(ContactMethods.TYPE, ContactMethods.TYPE_OTHER);
1749 values.putNull(ContactMethods.LABEL);
1750 if (type != -1) {
1751 values.put(ContactMethods.AUX_DATA,
1752 ContactMethods.encodePredefinedImProtocol(type));
1753 } else {
1754 values.put(ContactMethods.AUX_DATA,
1755 ContactMethods.encodeCustomImProtocol(label.toString()));
1756 }
1757 break;
1758
1759 case Contacts.KIND_POSTAL:
1760 if (type != ContactMethods.TYPE_CUSTOM) {
1761 labelString = null;
1762 }
1763 values.put(ContactMethods.LABEL, labelString);
1764 values.put(ContactMethods.KIND, kind);
1765 values.put(ContactMethods.TYPE, type);
1766 break;
1767
1768 case Contacts.KIND_ORGANIZATION:
1769 if (type != ContactMethods.TYPE_CUSTOM) {
1770 labelString = null;
1771 }
1772 values.put(ContactMethods.LABEL, labelString);
1773 values.put(ContactMethods.TYPE, type);
1774 // Save the title
1775 if (view != null) {
1776 // Read the possibly updated data from the text field
1777 data2 = ((TextView) view.findViewById(R.id.data2)).getText().toString();
1778 }
1779 if (!TextUtils.isGraphic(data2)) {
1780 values.putNull(Organizations.TITLE);
1781 } else {
1782 values.put(Organizations.TITLE, data2.toString());
1783 success = true;
1784 }
1785 break;
1786
1787 default:
1788 Log.w(TAG, "unknown kind " + kind);
1789 values.put(ContactMethods.LABEL, labelString);
1790 values.put(ContactMethods.KIND, kind);
1791 values.put(ContactMethods.TYPE, type);
1792 break;
1793 }
1794
1795 values.put(ContactMethods.ISPRIMARY, isPrimary ? "1" : "0");
1796
1797 // Save the data
1798 if (view != null && syncDataWithView) {
1799 // Read the possibly updated data from the text field
1800 data = ((TextView) view.findViewById(R.id.data)).getText().toString();
1801 }
1802 if (!TextUtils.isGraphic(data)) {
1803 values.putNull(column);
1804 return success;
1805 } else {
1806 values.put(column, data.toString());
1807 return true;
1808 }
1809 }
1810
1811 /**
1812 * Create a new empty organization entry
1813 */
1814 public static final EditEntry newOrganizationEntry(EditContactActivity activity,
1815 Uri uri, int type) {
1816 return newOrganizationEntry(activity, null, type, null, null, uri, 0);
1817 }
1818
1819 /**
1820 * Create a new company entry with the given data.
1821 */
1822 public static final EditEntry newOrganizationEntry(EditContactActivity activity,
1823 String label, int type, String company, String title, Uri uri, long id) {
1824 EditEntry entry = new EditEntry(activity, label, type, company, uri, id);
1825 entry.hint = activity.getString(R.string.ghostData_company);
1826 entry.hint2 = activity.getString(R.string.ghostData_title);
1827 entry.data2 = title;
1828 entry.column = Organizations.COMPANY;
1829 entry.contentDirectory = Organizations.CONTENT_DIRECTORY;
1830 entry.kind = Contacts.KIND_ORGANIZATION;
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001831 entry.contentType = EditorInfo.TYPE_CLASS_TEXT
1832 | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001833 return entry;
1834 }
1835
1836 /**
1837 * Create a new notes entry with the given data.
1838 */
1839 public static final EditEntry newNotesEntry(EditContactActivity activity,
1840 String data, Uri uri) {
1841 EditEntry entry = new EditEntry(activity);
1842 entry.label = activity.getString(R.string.label_notes);
1843 entry.hint = activity.getString(R.string.ghostData_notes);
1844 entry.data = data;
1845 entry.uri = uri;
1846 entry.column = People.NOTES;
1847 entry.maxLines = 10;
1848 entry.lines = 2;
1849 entry.id = 0;
1850 entry.kind = KIND_CONTACT;
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001851 entry.contentType = EditorInfo.TYPE_CLASS_TEXT
1852 | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
1853 | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001854 entry.isStaticLabel = true;
1855 return entry;
1856 }
1857
1858 /**
1859 * Create a new ringtone entry with the given data.
1860 */
1861 public static final EditEntry newRingtoneEntry(EditContactActivity activity,
1862 String data, Uri uri) {
1863 EditEntry entry = new EditEntry(activity);
1864 entry.label = activity.getString(R.string.label_ringtone);
1865 entry.data = data;
1866 entry.uri = uri;
1867 entry.column = People.CUSTOM_RINGTONE;
1868 entry.kind = KIND_CONTACT;
1869 entry.isStaticLabel = true;
1870 entry.syncDataWithView = false;
1871 entry.lines = -1;
1872 return entry;
1873 }
1874
1875 /**
1876 * Create a new empty email entry
1877 */
1878 public static final EditEntry newPhoneEntry(EditContactActivity activity,
1879 Uri uri, int type) {
1880 return newPhoneEntry(activity, null, type, null, uri, 0);
1881 }
1882
1883 /**
1884 * Create a new phone entry with the given data.
1885 */
1886 public static final EditEntry newPhoneEntry(EditContactActivity activity,
1887 String label, int type, String data, Uri uri,
1888 long id) {
1889 EditEntry entry = new EditEntry(activity, label, type, data, uri, id);
1890 entry.hint = activity.getString(R.string.ghostData_phone);
1891 entry.column = People.Phones.NUMBER;
1892 entry.contentDirectory = People.Phones.CONTENT_DIRECTORY;
1893 entry.kind = Contacts.KIND_PHONE;
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001894 entry.contentType = EditorInfo.TYPE_CLASS_PHONE;
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001895 return entry;
1896 }
1897
1898 /**
1899 * Create a new empty email entry
1900 */
1901 public static final EditEntry newEmailEntry(EditContactActivity activity,
1902 Uri uri, int type) {
1903 return newEmailEntry(activity, null, type, null, uri, 0);
1904 }
1905
1906 /**
1907 * Create a new email entry with the given data.
1908 */
1909 public static final EditEntry newEmailEntry(EditContactActivity activity,
1910 String label, int type, String data, Uri uri,
1911 long id) {
1912 EditEntry entry = new EditEntry(activity, label, type, data, uri, id);
1913 entry.hint = activity.getString(R.string.ghostData_email);
1914 entry.column = ContactMethods.DATA;
1915 entry.contentDirectory = People.ContactMethods.CONTENT_DIRECTORY;
1916 entry.kind = Contacts.KIND_EMAIL;
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001917 entry.contentType = EditorInfo.TYPE_CLASS_TEXT
1918 | EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001919 return entry;
1920 }
1921
1922 /**
1923 * Create a new empty postal address entry
1924 */
1925 public static final EditEntry newPostalEntry(EditContactActivity activity,
1926 Uri uri, int type) {
1927 return newPostalEntry(activity, null, type, null, uri, 0);
1928 }
1929
1930 /**
1931 * Create a new postal address entry with the given data.
1932 *
1933 * @param label label for the item, from the db not the display label
1934 * @param type the type of postal address
1935 * @param data the starting data for the entry, may be null
1936 * @param uri the uri for the entry if it already exists, may be null
1937 * @param id the id for the entry if it already exists, 0 it it doesn't
1938 * @return the new EditEntry
1939 */
1940 public static final EditEntry newPostalEntry(EditContactActivity activity,
1941 String label, int type, String data, Uri uri, long id) {
1942 EditEntry entry = new EditEntry(activity, label, type, data, uri, id);
1943 entry.hint = activity.getString(R.string.ghostData_postal);
1944 entry.column = ContactMethods.DATA;
1945 entry.contentDirectory = People.ContactMethods.CONTENT_DIRECTORY;
1946 entry.kind = Contacts.KIND_POSTAL;
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001947 entry.contentType = EditorInfo.TYPE_CLASS_TEXT
1948 | EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS
1949 | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS
1950 | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001951 entry.maxLines = 4;
1952 entry.lines = 2;
1953 return entry;
1954 }
1955
1956 /**
1957 * Create a new postal address entry with the given data.
1958 *
1959 * @param label label for the item, from the db not the display label
1960 * @param protocol the type used
1961 * @param data the starting data for the entry, may be null
1962 * @param uri the uri for the entry if it already exists, may be null
1963 * @param id the id for the entry if it already exists, 0 it it doesn't
1964 * @return the new EditEntry
1965 */
1966 public static final EditEntry newImEntry(EditContactActivity activity,
1967 String label, int protocol, String data, Uri uri, long id) {
1968 EditEntry entry = new EditEntry(activity, label, protocol, data, uri, id);
1969 entry.hint = activity.getString(R.string.ghostData_im);
1970 entry.column = ContactMethods.DATA;
1971 entry.contentDirectory = People.ContactMethods.CONTENT_DIRECTORY;
1972 entry.kind = Contacts.KIND_IM;
The Android Open Source Projectd9351702008-12-17 18:05:55 -08001973 entry.contentType = EditorInfo.TYPE_CLASS_TEXT;
The Android Open Source Project5dc3b4f2008-10-21 07:00:00 -07001974 return entry;
1975 }
1976 }
1977}