1/*
2 * Copyright (C) 2014 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.widget;
18
19import android.app.AlertDialog;
20import android.app.Dialog;
21import android.app.DialogFragment;
22import android.content.Context;
23import android.content.DialogInterface;
24import android.graphics.drawable.Icon;
25import android.os.Bundle;
26import android.os.Handler;
27import android.os.ResultReceiver;
28import android.telecom.PhoneAccount;
29import android.telecom.PhoneAccountHandle;
30import android.telecom.TelecomManager;
31import android.text.TextUtils;
32import android.view.LayoutInflater;
33import android.view.View;
34import android.view.ViewGroup;
35import android.widget.ArrayAdapter;
36import android.widget.CheckBox;
37import android.widget.CompoundButton;
38import android.widget.ImageView;
39import android.widget.LinearLayout;
40import android.widget.ListAdapter;
41import android.widget.TextView;
42
43import com.android.contacts.common.R;
44import com.android.contacts.common.compat.PhoneAccountCompat;
45import com.android.contacts.common.compat.PhoneNumberUtilsCompat;
46
47import java.util.ArrayList;
48import java.util.List;
49
50/**
51 * Dialog that allows the user to select a phone accounts for a given action. Optionally provides
52 * the choice to set the phone account as default.
53 */
54public class SelectPhoneAccountDialogFragment extends DialogFragment {
55    private static final String ARG_TITLE_RES_ID = "title_res_id";
56    private static final String ARG_CAN_SET_DEFAULT = "can_set_default";
57    private static final String ARG_ACCOUNT_HANDLES = "account_handles";
58    private static final String ARG_IS_DEFAULT_CHECKED = "is_default_checked";
59    private static final String ARG_LISTENER = "listener";
60
61    private int mTitleResId;
62    private boolean mCanSetDefault;
63    private List<PhoneAccountHandle> mAccountHandles;
64    private boolean mIsSelected;
65    private boolean mIsDefaultChecked;
66    private TelecomManager mTelecomManager;
67    private SelectPhoneAccountListener mListener;
68
69    /**
70     * Create new fragment instance with default title and no option to set as default.
71     *
72     * @param accountHandles The {@code PhoneAccountHandle}s available to select from.
73     * @param listener The listener for the results of the account selection.
74     */
75    public static SelectPhoneAccountDialogFragment newInstance(
76            List<PhoneAccountHandle> accountHandles, SelectPhoneAccountListener listener) {
77        return newInstance(R.string.select_account_dialog_title, false,
78                accountHandles, listener);
79    }
80
81    /**
82     * Create new fragment instance.
83     * This method also allows specifying a custom title and "set default" checkbox.
84     *
85     * @param titleResId The resource ID for the string to use in the title of the dialog.
86     * @param canSetDefault {@code true} if the dialog should include an option to set the selection
87     * as the default. False otherwise.
88     * @param accountHandles The {@code PhoneAccountHandle}s available to select from.
89     * @param listener The listener for the results of the account selection.
90     */
91    public static SelectPhoneAccountDialogFragment newInstance(int titleResId,
92            boolean canSetDefault, List<PhoneAccountHandle> accountHandles,
93            SelectPhoneAccountListener listener) {
94        ArrayList<PhoneAccountHandle> accountHandlesCopy = new ArrayList<PhoneAccountHandle>();
95        if (accountHandles != null) {
96            accountHandlesCopy.addAll(accountHandles);
97        }
98        SelectPhoneAccountDialogFragment fragment = new SelectPhoneAccountDialogFragment();
99        final Bundle args = new Bundle();
100        args.putInt(ARG_TITLE_RES_ID, titleResId);
101        args.putBoolean(ARG_CAN_SET_DEFAULT, canSetDefault);
102        args.putParcelableArrayList(ARG_ACCOUNT_HANDLES, accountHandlesCopy);
103        args.putParcelable(ARG_LISTENER, listener);
104        fragment.setArguments(args);
105        fragment.setListener(listener);
106        return fragment;
107    }
108
109    public SelectPhoneAccountDialogFragment() {
110    }
111
112    public void setListener(SelectPhoneAccountListener listener) {
113        mListener = listener;
114    }
115
116    public static class SelectPhoneAccountListener extends ResultReceiver {
117        static final int RESULT_SELECTED = 1;
118        static final int RESULT_DISMISSED = 2;
119
120        static final String EXTRA_SELECTED_ACCOUNT_HANDLE = "extra_selected_account_handle";
121        static final String EXTRA_SET_DEFAULT = "extra_set_default";
122
123        public SelectPhoneAccountListener() {
124            super(new Handler());
125        }
126
127        @Override
128        protected void onReceiveResult(int resultCode, Bundle resultData) {
129            if (resultCode == RESULT_SELECTED) {
130                onPhoneAccountSelected(
131                        (PhoneAccountHandle) resultData.getParcelable(
132                                EXTRA_SELECTED_ACCOUNT_HANDLE),
133                        resultData.getBoolean(EXTRA_SET_DEFAULT));
134            } else if (resultCode == RESULT_DISMISSED) {
135                onDialogDismissed();
136            }
137        }
138
139        public void onPhoneAccountSelected(PhoneAccountHandle selectedAccountHandle,
140                boolean setDefault) {}
141
142        public void onDialogDismissed() {}
143    }
144
145    @Override
146    public void onSaveInstanceState(Bundle outState) {
147        super.onSaveInstanceState(outState);
148        outState.putBoolean(ARG_IS_DEFAULT_CHECKED, mIsDefaultChecked);
149    }
150
151    @Override
152    public Dialog onCreateDialog(Bundle savedInstanceState) {
153        mTitleResId = getArguments().getInt(ARG_TITLE_RES_ID);
154        mCanSetDefault = getArguments().getBoolean(ARG_CAN_SET_DEFAULT);
155        mAccountHandles = getArguments().getParcelableArrayList(ARG_ACCOUNT_HANDLES);
156        mListener = getArguments().getParcelable(ARG_LISTENER);
157        if (savedInstanceState != null) {
158            mIsDefaultChecked = savedInstanceState.getBoolean(ARG_IS_DEFAULT_CHECKED);
159        }
160        mIsSelected = false;
161        mTelecomManager =
162                (TelecomManager) getActivity().getSystemService(Context.TELECOM_SERVICE);
163
164        final DialogInterface.OnClickListener selectionListener =
165                new DialogInterface.OnClickListener() {
166            @Override
167            public void onClick(DialogInterface dialog, int which) {
168                mIsSelected = true;
169                PhoneAccountHandle selectedAccountHandle = mAccountHandles.get(which);
170                final Bundle result = new Bundle();
171                result.putParcelable(SelectPhoneAccountListener.EXTRA_SELECTED_ACCOUNT_HANDLE,
172                        selectedAccountHandle);
173                result.putBoolean(SelectPhoneAccountListener.EXTRA_SET_DEFAULT,
174                        mIsDefaultChecked);
175                if (mListener != null) {
176                    mListener.onReceiveResult(SelectPhoneAccountListener.RESULT_SELECTED, result);
177                }
178            }
179        };
180
181        final CompoundButton.OnCheckedChangeListener checkListener =
182                new CompoundButton.OnCheckedChangeListener() {
183            @Override
184            public void onCheckedChanged(CompoundButton check, boolean isChecked) {
185                mIsDefaultChecked = isChecked;
186            }
187        };
188
189        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
190        ListAdapter selectAccountListAdapter = new SelectAccountListAdapter(
191                builder.getContext(),
192                R.layout.select_account_list_item,
193                mAccountHandles);
194
195        AlertDialog dialog = builder.setTitle(mTitleResId)
196                .setAdapter(selectAccountListAdapter, selectionListener)
197                .create();
198
199        if (mCanSetDefault) {
200            // Generate custom checkbox view
201            LinearLayout checkboxLayout = (LinearLayout) getActivity()
202                    .getLayoutInflater()
203                    .inflate(R.layout.default_account_checkbox, null);
204
205            CheckBox cb =
206                    (CheckBox) checkboxLayout.findViewById(R.id.default_account_checkbox_view);
207            cb.setOnCheckedChangeListener(checkListener);
208            cb.setChecked(mIsDefaultChecked);
209
210            dialog.getListView().addFooterView(checkboxLayout);
211        }
212
213        return dialog;
214    }
215
216    private class SelectAccountListAdapter extends ArrayAdapter<PhoneAccountHandle> {
217        private int mResId;
218
219        public SelectAccountListAdapter(
220                Context context, int resource, List<PhoneAccountHandle> accountHandles) {
221            super(context, resource, accountHandles);
222            mResId = resource;
223        }
224
225        @Override
226        public View getView(int position, View convertView, ViewGroup parent) {
227            LayoutInflater inflater = (LayoutInflater)
228                    getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
229
230            View rowView;
231            final ViewHolder holder;
232
233            if (convertView == null) {
234                // Cache views for faster scrolling
235                rowView = inflater.inflate(mResId, null);
236                holder = new ViewHolder();
237                holder.labelTextView = (TextView) rowView.findViewById(R.id.label);
238                holder.numberTextView = (TextView) rowView.findViewById(R.id.number);
239                holder.imageView = (ImageView) rowView.findViewById(R.id.icon);
240                rowView.setTag(holder);
241            }
242            else {
243                rowView = convertView;
244                holder = (ViewHolder) rowView.getTag();
245            }
246
247            PhoneAccountHandle accountHandle = getItem(position);
248            PhoneAccount account = mTelecomManager.getPhoneAccount(accountHandle);
249            if (account == null) {
250                return rowView;
251            }
252            holder.labelTextView.setText(account.getLabel());
253            if (account.getAddress() == null ||
254                    TextUtils.isEmpty(account.getAddress().getSchemeSpecificPart())) {
255                holder.numberTextView.setVisibility(View.GONE);
256            } else {
257                holder.numberTextView.setVisibility(View.VISIBLE);
258                holder.numberTextView.setText(
259                        PhoneNumberUtilsCompat.createTtsSpannable(
260                                account.getAddress().getSchemeSpecificPart()));
261            }
262            holder.imageView.setImageDrawable(PhoneAccountCompat.createIconDrawable(account,
263                    getContext()));
264            return rowView;
265        }
266
267        private class ViewHolder {
268            TextView labelTextView;
269            TextView numberTextView;
270            ImageView imageView;
271        }
272    }
273
274    @Override
275    public void onStop() {
276        if (!mIsSelected && mListener != null) {
277            mListener.onReceiveResult(SelectPhoneAccountListener.RESULT_DISMISSED, null);
278        }
279        super.onStop();
280    }
281}
282