Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 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 | |
Gary Mai | 69c182a | 2016-12-05 13:07:03 -0800 | [diff] [blame] | 17 | package com.android.contacts.widget; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 18 | |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 19 | import android.app.AlertDialog; |
| 20 | import android.app.Dialog; |
Brian Attwell | c2e912c | 2014-10-27 12:29:44 -0700 | [diff] [blame] | 21 | import android.app.DialogFragment; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 22 | import android.content.Context; |
| 23 | import android.content.DialogInterface; |
| 24 | import android.os.Bundle; |
Yorke Lee | a2b62e0 | 2015-06-10 13:36:46 -0700 | [diff] [blame] | 25 | import android.os.Handler; |
| 26 | import android.os.ResultReceiver; |
Brandon Maxwell | 62cfa6e | 2015-12-04 15:27:45 -0800 | [diff] [blame] | 27 | import android.telecom.PhoneAccount; |
| 28 | import android.telecom.PhoneAccountHandle; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 29 | import android.telecom.TelecomManager; |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 30 | import android.text.TextUtils; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 31 | import android.view.LayoutInflater; |
| 32 | import android.view.View; |
| 33 | import android.view.ViewGroup; |
| 34 | import android.widget.ArrayAdapter; |
Nancy Chen | fdb76be | 2014-10-21 18:53:11 -0700 | [diff] [blame] | 35 | import android.widget.CheckBox; |
| 36 | import android.widget.CompoundButton; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 37 | import android.widget.ImageView; |
Nancy Chen | fdb76be | 2014-10-21 18:53:11 -0700 | [diff] [blame] | 38 | import android.widget.LinearLayout; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 39 | import android.widget.ListAdapter; |
| 40 | import android.widget.TextView; |
| 41 | |
Arthur Wang | 3f6a244 | 2016-12-05 14:51:59 -0800 | [diff] [blame] | 42 | import com.android.contacts.R; |
Gary Mai | 69c182a | 2016-12-05 13:07:03 -0800 | [diff] [blame] | 43 | import com.android.contacts.compat.PhoneAccountCompat; |
| 44 | import com.android.contacts.compat.PhoneNumberUtilsCompat; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 45 | |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 46 | import java.util.ArrayList; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 47 | import java.util.List; |
| 48 | |
| 49 | /** |
Nancy Chen | fdb76be | 2014-10-21 18:53:11 -0700 | [diff] [blame] | 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. |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 52 | */ |
Brian Attwell | c2e912c | 2014-10-27 12:29:44 -0700 | [diff] [blame] | 53 | public class SelectPhoneAccountDialogFragment extends DialogFragment { |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 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"; |
Yorke Lee | a2b62e0 | 2015-06-10 13:36:46 -0700 | [diff] [blame] | 58 | private static final String ARG_LISTENER = "listener"; |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 59 | |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 60 | private int mTitleResId; |
Nancy Chen | fdb76be | 2014-10-21 18:53:11 -0700 | [diff] [blame] | 61 | private boolean mCanSetDefault; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 62 | private List<PhoneAccountHandle> mAccountHandles; |
| 63 | private boolean mIsSelected; |
Nancy Chen | fdb76be | 2014-10-21 18:53:11 -0700 | [diff] [blame] | 64 | private boolean mIsDefaultChecked; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 65 | private TelecomManager mTelecomManager; |
| 66 | private SelectPhoneAccountListener mListener; |
| 67 | |
| 68 | /** |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 69 | * Create new fragment instance with default title and no option to set as default. |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 70 | * |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 71 | * @param accountHandles The {@code PhoneAccountHandle}s available to select from. |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 72 | * @param listener The listener for the results of the account selection. |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 73 | */ |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 74 | public static SelectPhoneAccountDialogFragment newInstance( |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 75 | List<PhoneAccountHandle> accountHandles, SelectPhoneAccountListener listener) { |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 76 | return newInstance(R.string.select_account_dialog_title, false, |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 77 | accountHandles, listener); |
| 78 | } |
| 79 | |
| 80 | /** |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 81 | * Create new fragment instance. |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 82 | * This method also allows specifying a custom title and "set default" checkbox. |
| 83 | * |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 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 | */ |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 90 | public static SelectPhoneAccountDialogFragment newInstance(int titleResId, |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 91 | boolean canSetDefault, List<PhoneAccountHandle> accountHandles, |
| 92 | SelectPhoneAccountListener listener) { |
Andrew Lee | 88cbb96 | 2015-06-01 12:16:15 -0700 | [diff] [blame] | 93 | ArrayList<PhoneAccountHandle> accountHandlesCopy = new ArrayList<PhoneAccountHandle>(); |
| 94 | if (accountHandles != null) { |
| 95 | accountHandlesCopy.addAll(accountHandles); |
Andrew Lee | 7e4758e | 2015-06-01 12:16:15 -0700 | [diff] [blame] | 96 | } |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 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); |
Andrew Lee | 88cbb96 | 2015-06-01 12:16:15 -0700 | [diff] [blame] | 101 | args.putParcelableArrayList(ARG_ACCOUNT_HANDLES, accountHandlesCopy); |
Yorke Lee | a2b62e0 | 2015-06-10 13:36:46 -0700 | [diff] [blame] | 102 | args.putParcelable(ARG_LISTENER, listener); |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 103 | fragment.setArguments(args); |
| 104 | fragment.setListener(listener); |
| 105 | return fragment; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 106 | } |
| 107 | |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 108 | public SelectPhoneAccountDialogFragment() { |
| 109 | } |
| 110 | |
| 111 | public void setListener(SelectPhoneAccountListener listener) { |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 112 | mListener = listener; |
| 113 | } |
| 114 | |
Yorke Lee | a2b62e0 | 2015-06-10 13:36:46 -0700 | [diff] [blame] | 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() {} |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | @Override |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 145 | public void onSaveInstanceState(Bundle outState) { |
| 146 | super.onSaveInstanceState(outState); |
| 147 | outState.putBoolean(ARG_IS_DEFAULT_CHECKED, mIsDefaultChecked); |
| 148 | } |
| 149 | |
| 150 | @Override |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 151 | public Dialog onCreateDialog(Bundle savedInstanceState) { |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 152 | mTitleResId = getArguments().getInt(ARG_TITLE_RES_ID); |
| 153 | mCanSetDefault = getArguments().getBoolean(ARG_CAN_SET_DEFAULT); |
| 154 | mAccountHandles = getArguments().getParcelableArrayList(ARG_ACCOUNT_HANDLES); |
Yorke Lee | a2b62e0 | 2015-06-10 13:36:46 -0700 | [diff] [blame] | 155 | mListener = getArguments().getParcelable(ARG_LISTENER); |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 156 | if (savedInstanceState != null) { |
| 157 | mIsDefaultChecked = savedInstanceState.getBoolean(ARG_IS_DEFAULT_CHECKED); |
| 158 | } |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 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); |
Yorke Lee | a2b62e0 | 2015-06-10 13:36:46 -0700 | [diff] [blame] | 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 | } |
Nancy Chen | fdb76be | 2014-10-21 18:53:11 -0700 | [diff] [blame] | 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; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 185 | } |
| 186 | }; |
| 187 | |
| 188 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 189 | ListAdapter selectAccountListAdapter = new SelectAccountListAdapter( |
| 190 | builder.getContext(), |
| 191 | R.layout.select_account_list_item, |
| 192 | mAccountHandles); |
| 193 | |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 194 | AlertDialog dialog = builder.setTitle(mTitleResId) |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 195 | .setAdapter(selectAccountListAdapter, selectionListener) |
| 196 | .create(); |
Nancy Chen | fdb76be | 2014-10-21 18:53:11 -0700 | [diff] [blame] | 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); |
Jay Shrauner | ebf0a0f | 2015-04-03 16:01:16 -0700 | [diff] [blame] | 207 | cb.setChecked(mIsDefaultChecked); |
Nancy Chen | fdb76be | 2014-10-21 18:53:11 -0700 | [diff] [blame] | 208 | |
| 209 | dialog.getListView().addFooterView(checkboxLayout); |
| 210 | } |
| 211 | |
| 212 | return dialog; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 213 | } |
| 214 | |
| 215 | private class SelectAccountListAdapter extends ArrayAdapter<PhoneAccountHandle> { |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 216 | private int mResId; |
| 217 | |
| 218 | public SelectAccountListAdapter( |
| 219 | Context context, int resource, List<PhoneAccountHandle> accountHandles) { |
| 220 | super(context, resource, accountHandles); |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 221 | mResId = resource; |
| 222 | } |
| 223 | |
| 224 | @Override |
| 225 | public View getView(int position, View convertView, ViewGroup parent) { |
| 226 | LayoutInflater inflater = (LayoutInflater) |
Ihab Awad | d1360e1 | 2014-10-24 11:43:33 -0700 | [diff] [blame] | 227 | getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 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(); |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 236 | holder.labelTextView = (TextView) rowView.findViewById(R.id.label); |
| 237 | holder.numberTextView = (TextView) rowView.findViewById(R.id.number); |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 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); |
Yorke Lee | a2bd6f5 | 2015-05-04 18:29:00 -0700 | [diff] [blame] | 248 | if (account == null) { |
| 249 | return rowView; |
| 250 | } |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 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); |
Ihab Awad | 07685ea | 2014-12-05 13:37:50 -0800 | [diff] [blame] | 257 | holder.numberTextView.setText( |
Brandon Maxwell | 62cfa6e | 2015-12-04 15:27:45 -0800 | [diff] [blame] | 258 | PhoneNumberUtilsCompat.createTtsSpannable( |
Ihab Awad | 07685ea | 2014-12-05 13:37:50 -0800 | [diff] [blame] | 259 | account.getAddress().getSchemeSpecificPart())); |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 260 | } |
Brandon Maxwell | 089df23 | 2015-12-18 12:30:55 -0800 | [diff] [blame] | 261 | holder.imageView.setImageDrawable(PhoneAccountCompat.createIconDrawable(account, |
| 262 | getContext())); |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 263 | return rowView; |
| 264 | } |
| 265 | |
| 266 | private class ViewHolder { |
Nancy Chen | 8464756 | 2014-11-03 17:08:47 -0800 | [diff] [blame] | 267 | TextView labelTextView; |
| 268 | TextView numberTextView; |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 269 | ImageView imageView; |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | @Override |
Yorke Lee | 6c4b7b1 | 2015-04-06 19:49:27 -0700 | [diff] [blame] | 274 | public void onStop() { |
Yorke Lee | a2b62e0 | 2015-06-10 13:36:46 -0700 | [diff] [blame] | 275 | if (!mIsSelected && mListener != null) { |
| 276 | mListener.onReceiveResult(SelectPhoneAccountListener.RESULT_DISMISSED, null); |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 277 | } |
Yorke Lee | 6c4b7b1 | 2015-04-06 19:49:27 -0700 | [diff] [blame] | 278 | super.onStop(); |
Nancy Chen | 1821c25 | 2014-10-08 12:45:34 -0700 | [diff] [blame] | 279 | } |
Brian Attwell | d46781c | 2014-10-31 18:45:34 +0000 | [diff] [blame] | 280 | } |