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