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