ImportExportDialogFragment.java revision ff95fe1ca9cc570acc41c9335a6cdeecfd851e44
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 != null) { 127 if (subInfoRecords.size() == 1) { 128 adapter.add(new AdapterEntry(getString(R.string.import_from_sim), 129 R.string.import_from_sim, subInfoRecords.get(0).getSubscriptionId())); 130 } else { 131 for (SubscriptionInfo record : subInfoRecords) { 132 adapter.add(new AdapterEntry(getSubDescription(record), 133 R.string.import_from_sim, record.getSubscriptionId())); 134 } 135 } 136 } 137 } 138 if (res.getBoolean(R.bool.config_allow_export_to_sdcard)) { 139 if (contactsAreAvailable) { 140 adapter.add(new AdapterEntry(getString(R.string.export_to_sdcard), 141 R.string.export_to_sdcard)); 142 } 143 } 144 if (res.getBoolean(R.bool.config_allow_share_visible_contacts)) { 145 if (contactsAreAvailable) { 146 adapter.add(new AdapterEntry(getString(R.string.share_visible_contacts), 147 R.string.share_visible_contacts)); 148 } 149 } 150 151 final DialogInterface.OnClickListener clickListener = 152 new DialogInterface.OnClickListener() { 153 @Override 154 public void onClick(DialogInterface dialog, int which) { 155 boolean dismissDialog; 156 final int resId = adapter.getItem(which).mChoiceResourceId; 157 switch (resId) { 158 case R.string.import_from_sim: 159 case R.string.import_from_sdcard: { 160 dismissDialog = handleImportRequest(resId, 161 adapter.getItem(which).mSubscriptionId); 162 break; 163 } 164 case R.string.export_to_sdcard: { 165 dismissDialog = true; 166 Intent exportIntent = new Intent(getActivity(), ExportVCardActivity.class); 167 exportIntent.putExtra(VCardCommonArguments.ARG_CALLING_ACTIVITY, 168 callingActivity); 169 getActivity().startActivity(exportIntent); 170 break; 171 } 172 case R.string.share_visible_contacts: { 173 dismissDialog = true; 174 doShareVisibleContacts(); 175 break; 176 } 177 default: { 178 dismissDialog = true; 179 Log.e(TAG, "Unexpected resource: " 180 + getActivity().getResources().getResourceEntryName(resId)); 181 } 182 } 183 if (dismissDialog) { 184 dialog.dismiss(); 185 } 186 } 187 }; 188 return new AlertDialog.Builder(getActivity()) 189 .setTitle(contactsAreAvailable 190 ? R.string.dialog_import_export 191 : R.string.dialog_import) 192 .setSingleChoiceItems(adapter, -1, clickListener) 193 .create(); 194 } 195 196 private void doShareVisibleContacts() { 197 // TODO move the query into a loader and do this in a background thread 198 final Cursor cursor = getActivity().getContentResolver().query(Contacts.CONTENT_URI, 199 LOOKUP_PROJECTION, Contacts.IN_VISIBLE_GROUP + "!=0", null, null); 200 if (cursor != null) { 201 try { 202 if (!cursor.moveToFirst()) { 203 Toast.makeText(getActivity(), R.string.share_error, Toast.LENGTH_SHORT).show(); 204 return; 205 } 206 207 StringBuilder uriListBuilder = new StringBuilder(); 208 int index = 0; 209 do { 210 if (index != 0) 211 uriListBuilder.append(':'); 212 uriListBuilder.append(cursor.getString(0)); 213 index++; 214 } while (cursor.moveToNext()); 215 Uri uri = Uri.withAppendedPath( 216 Contacts.CONTENT_MULTI_VCARD_URI, 217 Uri.encode(uriListBuilder.toString())); 218 219 final Intent intent = new Intent(Intent.ACTION_SEND); 220 intent.setType(Contacts.CONTENT_VCARD_TYPE); 221 intent.putExtra(Intent.EXTRA_STREAM, uri); 222 getActivity().startActivity(intent); 223 } finally { 224 cursor.close(); 225 } 226 } 227 } 228 229 /** 230 * Handle "import from SIM" and "import from SD". 231 * 232 * @return {@code true} if the dialog show be closed. {@code false} otherwise. 233 */ 234 private boolean handleImportRequest(int resId, long subscriptionId) { 235 // There are three possibilities: 236 // - more than one accounts -> ask the user 237 // - just one account -> use the account without asking the user 238 // - no account -> use phone-local storage without asking the user 239 final AccountTypeManager accountTypes = AccountTypeManager.getInstance(getActivity()); 240 final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true); 241 final int size = accountList.size(); 242 if (size > 1) { 243 // Send over to the account selector 244 final Bundle args = new Bundle(); 245 args.putInt(KEY_RES_ID, resId); 246 args.putLong(KEY_SUBSCRIPTION_ID, subscriptionId); 247 SelectAccountDialogFragment.show( 248 getFragmentManager(), this, 249 R.string.dialog_new_contact_account, 250 AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, args); 251 252 // In this case, because this DialogFragment is used as a target fragment to 253 // SelectAccountDialogFragment, we can't close it yet. We close the dialog when 254 // we get a callback from it. 255 return false; 256 } 257 258 AccountSelectionUtil.doImport(getActivity(), resId, 259 (size == 1 ? accountList.get(0) : null), subscriptionId); 260 return true; // Close the dialog. 261 } 262 263 /** 264 * Called when an account is selected on {@link SelectAccountDialogFragment}. 265 */ 266 @Override 267 public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) { 268 AccountSelectionUtil.doImport(getActivity(), extraArgs.getInt(KEY_RES_ID), 269 account, extraArgs.getLong(KEY_SUBSCRIPTION_ID)); 270 271 // At this point the dialog is still showing (which is why we can use getActivity() above) 272 // So close it. 273 dismiss(); 274 } 275 276 @Override 277 public void onAccountSelectorCancelled() { 278 // See onAccountChosen() -- at this point the dialog is still showing. Close it. 279 dismiss(); 280 } 281 282 private String getSubDescription(SubscriptionInfo record) { 283 CharSequence name = record.getDisplayName(); 284 if (TextUtils.isEmpty(record.getNumber())) { 285 // Don't include the phone number in the description, since we don't know the number. 286 return getString(R.string.import_from_sim_summary_no_number, name); 287 } 288 return getString(R.string.import_from_sim_summary, name, record.getNumber()); 289 } 290 291 private static class AdapterEntry { 292 public final String mLabel; 293 public final int mChoiceResourceId; 294 public final int mSubscriptionId; 295 296 public AdapterEntry(String label, int resId, int subId) { 297 mLabel = label; 298 mChoiceResourceId = resId; 299 mSubscriptionId = subId; 300 } 301 302 public AdapterEntry(String label, int resId) { 303 this(label, resId, SubscriptionManager.INVALID_SUBSCRIPTION_ID); 304 } 305 } 306} 307