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 
17 package com.android.contacts.widget;
18 
19 import android.app.AlertDialog;
20 import android.app.Dialog;
21 import android.app.DialogFragment;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.ResultReceiver;
27 import android.telecom.PhoneAccount;
28 import android.telecom.PhoneAccountHandle;
29 import android.telecom.TelecomManager;
30 import android.text.TextUtils;
31 import android.view.LayoutInflater;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.widget.ArrayAdapter;
35 import android.widget.CheckBox;
36 import android.widget.CompoundButton;
37 import android.widget.ImageView;
38 import android.widget.LinearLayout;
39 import android.widget.ListAdapter;
40 import android.widget.TextView;
41 
42 import com.android.contacts.R;
43 import com.android.contacts.compat.PhoneAccountCompat;
44 import com.android.contacts.compat.PhoneNumberUtilsCompat;
45 
46 import java.util.ArrayList;
47 import 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  */
53 public 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      */
newInstance( List<PhoneAccountHandle> accountHandles, SelectPhoneAccountListener listener)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      */
newInstance(int titleResId, boolean canSetDefault, List<PhoneAccountHandle> accountHandles, SelectPhoneAccountListener listener)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 
SelectPhoneAccountDialogFragment()108     public SelectPhoneAccountDialogFragment() {
109     }
110 
setListener(SelectPhoneAccountListener listener)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 
SelectPhoneAccountListener()122         public SelectPhoneAccountListener() {
123             super(new Handler());
124         }
125 
126         @Override
onReceiveResult(int resultCode, Bundle resultData)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 
onPhoneAccountSelected(PhoneAccountHandle selectedAccountHandle, boolean setDefault)138         public void onPhoneAccountSelected(PhoneAccountHandle selectedAccountHandle,
139                 boolean setDefault) {}
140 
onDialogDismissed()141         public void onDialogDismissed() {}
142     }
143 
144     @Override
onSaveInstanceState(Bundle outState)145     public void onSaveInstanceState(Bundle outState) {
146         super.onSaveInstanceState(outState);
147         outState.putBoolean(ARG_IS_DEFAULT_CHECKED, mIsDefaultChecked);
148     }
149 
150     @Override
onCreateDialog(Bundle savedInstanceState)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 
SelectAccountListAdapter( Context context, int resource, List<PhoneAccountHandle> accountHandles)218         public SelectAccountListAdapter(
219                 Context context, int resource, List<PhoneAccountHandle> accountHandles) {
220             super(context, resource, accountHandles);
221             mResId = resource;
222         }
223 
224         @Override
getView(int position, View convertView, ViewGroup parent)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
onStop()274     public void onStop() {
275         if (!mIsSelected && mListener != null) {
276             mListener.onReceiveResult(SelectPhoneAccountListener.RESULT_DISMISSED, null);
277         }
278         super.onStop();
279     }
280 }
281