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