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.interactions;
18
19import com.android.contacts.R;
20import com.android.contacts.editor.SelectAccountDialogFragment;
21import com.android.contacts.model.AccountTypeManager;
22import com.android.contacts.model.AccountWithDataSet;
23import com.android.contacts.util.AccountSelectionUtil;
24import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
25import com.android.contacts.vcard.ExportVCardActivity;
26
27import android.app.AlertDialog;
28import android.app.Dialog;
29import android.app.DialogFragment;
30import android.app.FragmentManager;
31import android.content.Context;
32import android.content.DialogInterface;
33import android.content.Intent;
34import android.content.res.Resources;
35import android.database.Cursor;
36import android.net.Uri;
37import android.os.Bundle;
38import android.provider.ContactsContract.Contacts;
39import android.telephony.TelephonyManager;
40import android.util.Log;
41import android.view.LayoutInflater;
42import android.view.View;
43import android.view.ViewGroup;
44import android.widget.ArrayAdapter;
45import android.widget.TextView;
46import android.widget.Toast;
47
48import java.util.List;
49
50/**
51 * An dialog invoked to import/export contacts.
52 */
53public 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