1 /* 2 * Copyright (C) 2010 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.contacts.interactions; 18 19 import com.android.contacts.R; 20 import com.android.contacts.editor.SelectAccountDialogFragment; 21 import com.android.contacts.model.AccountTypeManager; 22 import com.android.contacts.model.AccountWithDataSet; 23 import com.android.contacts.util.AccountSelectionUtil; 24 import com.android.contacts.util.AccountsListAdapter.AccountListFilter; 25 import com.android.contacts.vcard.ExportVCardActivity; 26 27 import android.app.AlertDialog; 28 import android.app.Dialog; 29 import android.app.DialogFragment; 30 import android.app.FragmentManager; 31 import android.content.Context; 32 import android.content.DialogInterface; 33 import android.content.Intent; 34 import android.content.res.Resources; 35 import android.database.Cursor; 36 import android.net.Uri; 37 import android.os.Bundle; 38 import android.provider.ContactsContract.Contacts; 39 import android.telephony.TelephonyManager; 40 import android.util.Log; 41 import android.view.LayoutInflater; 42 import android.view.View; 43 import android.view.ViewGroup; 44 import android.widget.ArrayAdapter; 45 import android.widget.TextView; 46 import android.widget.Toast; 47 48 import java.util.List; 49 50 /** 51 * An dialog invoked to import/export contacts. 52 */ 53 public class ImportExportDialogFragment extends DialogFragment 54 implements SelectAccountDialogFragment.Listener { 55 public static final String TAG = "ImportExportDialogFragment"; 56 57 private static final String KEY_RES_ID = "resourceId"; 58 59 private final String[] LOOKUP_PROJECTION = new String[] { 60 Contacts.LOOKUP_KEY 61 }; 62 63 /** Preferred way to show this dialog */ 64 public static void show(FragmentManager fragmentManager) { 65 final ImportExportDialogFragment fragment = new ImportExportDialogFragment(); 66 fragment.show(fragmentManager, ImportExportDialogFragment.TAG); 67 } 68 69 @Override 70 public Dialog onCreateDialog(Bundle savedInstanceState) { 71 // Wrap our context to inflate list items using the correct theme 72 final Resources res = getActivity().getResources(); 73 final LayoutInflater dialogInflater = (LayoutInflater)getActivity() 74 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 75 76 // Adapter that shows a list of string resources 77 final ArrayAdapter<Integer> adapter = new ArrayAdapter<Integer>(getActivity(), 78 R.layout.select_dialog_item) { 79 @Override 80 public View getView(int position, View convertView, ViewGroup parent) { 81 final TextView result = (TextView)(convertView != null ? convertView : 82 dialogInflater.inflate(R.layout.select_dialog_item, parent, false)); 83 84 final int resId = getItem(position); 85 result.setText(resId); 86 return result; 87 } 88 }; 89 90 if (TelephonyManager.getDefault().hasIccCard() 91 && res.getBoolean(R.bool.config_allow_sim_import)) { 92 adapter.add(R.string.import_from_sim); 93 } 94 if (res.getBoolean(R.bool.config_allow_import_from_sdcard)) { 95 adapter.add(R.string.import_from_sdcard); 96 } 97 if (res.getBoolean(R.bool.config_allow_export_to_sdcard)) { 98 adapter.add(R.string.export_to_sdcard); 99 } 100 if (res.getBoolean(R.bool.config_allow_share_visible_contacts)) { 101 adapter.add(R.string.share_visible_contacts); 102 } 103 104 final DialogInterface.OnClickListener clickListener = 105 new DialogInterface.OnClickListener() { 106 @Override 107 public void onClick(DialogInterface dialog, int which) { 108 boolean dismissDialog; 109 final int resId = adapter.getItem(which); 110 switch (resId) { 111 case R.string.import_from_sim: 112 case R.string.import_from_sdcard: { 113 dismissDialog = handleImportRequest(resId); 114 break; 115 } 116 case R.string.export_to_sdcard: { 117 dismissDialog = true; 118 Intent exportIntent = new Intent(getActivity(), ExportVCardActivity.class); 119 getActivity().startActivity(exportIntent); 120 break; 121 } 122 case R.string.share_visible_contacts: { 123 dismissDialog = true; 124 doShareVisibleContacts(); 125 break; 126 } 127 default: { 128 dismissDialog = true; 129 Log.e(TAG, "Unexpected resource: " 130 + getActivity().getResources().getResourceEntryName(resId)); 131 } 132 } 133 if (dismissDialog) { 134 dialog.dismiss(); 135 } 136 } 137 }; 138 return new AlertDialog.Builder(getActivity()) 139 .setTitle(R.string.dialog_import_export) 140 .setSingleChoiceItems(adapter, -1, clickListener) 141 .create(); 142 } 143 144 private void doShareVisibleContacts() { 145 // TODO move the query into a loader and do this in a background thread 146 final Cursor cursor = getActivity().getContentResolver().query(Contacts.CONTENT_URI, 147 LOOKUP_PROJECTION, Contacts.IN_VISIBLE_GROUP + "!=0", null, null); 148 if (cursor != null) { 149 try { 150 if (!cursor.moveToFirst()) { 151 Toast.makeText(getActivity(), R.string.share_error, Toast.LENGTH_SHORT).show(); 152 return; 153 } 154 155 StringBuilder uriListBuilder = new StringBuilder(); 156 int index = 0; 157 do { 158 if (index != 0) 159 uriListBuilder.append(':'); 160 uriListBuilder.append(cursor.getString(0)); 161 index++; 162 } while (cursor.moveToNext()); 163 Uri uri = Uri.withAppendedPath( 164 Contacts.CONTENT_MULTI_VCARD_URI, 165 Uri.encode(uriListBuilder.toString())); 166 167 final Intent intent = new Intent(Intent.ACTION_SEND); 168 intent.setType(Contacts.CONTENT_VCARD_TYPE); 169 intent.putExtra(Intent.EXTRA_STREAM, uri); 170 getActivity().startActivity(intent); 171 } finally { 172 cursor.close(); 173 } 174 } 175 } 176 177 /** 178 * Handle "import from SIM" and "import from SD". 179 * 180 * @return {@code true} if the dialog show be closed. {@code false} otherwise. 181 */ 182 private boolean handleImportRequest(int resId) { 183 // There are three possibilities: 184 // - more than one accounts -> ask the user 185 // - just one account -> use the account without asking the user 186 // - no account -> use phone-local storage without asking the user 187 final AccountTypeManager accountTypes = AccountTypeManager.getInstance(getActivity()); 188 final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true); 189 final int size = accountList.size(); 190 if (size > 1) { 191 // Send over to the account selector 192 final Bundle args = new Bundle(); 193 args.putInt(KEY_RES_ID, resId); 194 SelectAccountDialogFragment.show( 195 getFragmentManager(), this, 196 R.string.dialog_new_contact_account, 197 AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, args); 198 199 // In this case, because this DialogFragment is used as a target fragment to 200 // SelectAccountDialogFragment, we can't close it yet. We close the dialog when 201 // we get a callback from it. 202 return false; 203 } 204 205 AccountSelectionUtil.doImport(getActivity(), resId, 206 (size == 1 ? accountList.get(0) : null)); 207 return true; // Close the dialog. 208 } 209 210 /** 211 * Called when an account is selected on {@link SelectAccountDialogFragment}. 212 */ 213 @Override 214 public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) { 215 AccountSelectionUtil.doImport(getActivity(), extraArgs.getInt(KEY_RES_ID), account); 216 217 // At this point the dialog is still showing (which is why we can use getActivity() above) 218 // So close it. 219 dismiss(); 220 } 221 222 @Override 223 public void onAccountSelectorCancelled() { 224 // See onAccountChosen() -- at this point the dialog is still showing. Close it. 225 dismiss(); 226 } 227 } 228