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