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