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