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