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