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