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