blob: cc2b99216f63aef286be8244bed5b55003d70f95 [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.phone;
18
19import android.accounts.Account;
20import android.app.ActionBar;
21import android.app.ProgressDialog;
22import android.content.ContentProviderOperation;
23import android.content.ContentResolver;
24import android.content.ContentValues;
25import android.content.DialogInterface;
26import android.content.DialogInterface.OnCancelListener;
27import android.content.DialogInterface.OnClickListener;
28import android.content.Intent;
29import android.content.OperationApplicationException;
30import android.database.Cursor;
31import android.net.Uri;
32import android.os.Bundle;
33import android.os.RemoteException;
34import android.provider.ContactsContract;
35import android.provider.ContactsContract.CommonDataKinds.Email;
36import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
37import android.provider.ContactsContract.CommonDataKinds.Phone;
38import android.provider.ContactsContract.CommonDataKinds.StructuredName;
39import android.provider.ContactsContract.Data;
40import android.provider.ContactsContract.RawContacts;
Jay Shrauner137458b2014-09-05 14:27:25 -070041import android.telecomm.PhoneAccount;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070042import android.text.TextUtils;
43import android.util.Log;
44import android.view.ContextMenu;
45import android.view.KeyEvent;
46import android.view.Menu;
47import android.view.MenuItem;
48import android.view.View;
49import android.widget.AdapterView;
50import android.widget.CursorAdapter;
51import android.widget.ListView;
52import android.widget.SimpleCursorAdapter;
53import android.widget.TextView;
54
55import java.util.ArrayList;
56
57/**
58 * SIM Address Book UI for the Phone app.
59 */
60public class SimContacts extends ADNList {
61 private static final String LOG_TAG = "SimContacts";
62
Santos Cordon7d4ddf62013-07-10 11:58:08 -070063 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;
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
101 public ImportAllSimContactsThread() {
102 super("ImportAllSimContactsThread");
103 }
104
105 @Override
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
120 public void onCancel(DialogInterface dialog) {
121 mCanceled = true;
122 }
123
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
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
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
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
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
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
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
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
271 public boolean onOptionsItemSelected(MenuItem item) {
272 switch (item.getItemId()) {
273 case android.R.id.home:
Jay Shrauner3a124e62014-07-17 09:58:34 -0700274 onBackPressed();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700275 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
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
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
333 public void onListItemClick(ListView l, View v, int position, long id) {
334 importOneSimContact(position);
335 }
336
337 @Override
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,
Jay Shrauner137458b2014-09-05 14:27:25 -0700349 Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null));
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700350 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}