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