1 /* 2 * Copyright (C) 2019 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.car.dialer.ui.common; 18 19 import android.content.Context; 20 import android.content.res.Resources; 21 22 import androidx.annotation.NonNull; 23 import androidx.annotation.Nullable; 24 25 import com.android.car.dialer.R; 26 import com.android.car.dialer.log.L; 27 import com.android.car.telephony.common.Contact; 28 import com.android.car.telephony.common.PhoneNumber; 29 import com.android.car.telephony.common.TelecomUtils; 30 import com.android.car.ui.AlertDialogBuilder; 31 import com.android.car.ui.recyclerview.CarUiRadioButtonListItem; 32 import com.android.car.ui.recyclerview.CarUiRadioButtonListItemAdapter; 33 34 import java.util.ArrayList; 35 import java.util.List; 36 37 /** Ui Utilities for dialer */ 38 public class DialerUtils { 39 40 private static final String TAG = "CD.DialerUtils"; 41 42 /** 43 * Callback interface for 44 * {@link DialerUtils#showPhoneNumberSelector(Context, List, PhoneNumberSelectionCallback)} and 45 * {@link DialerUtils#promptForPrimaryNumber(Context, Contact, PhoneNumberSelectionCallback)} 46 */ 47 public interface PhoneNumberSelectionCallback { 48 /** 49 * Called when a phone number is chosen. 50 * 51 * @param phoneNumber The phone number 52 * @param always Whether the user pressed "aways" or "just once" 53 */ onPhoneNumberSelected(PhoneNumber phoneNumber, boolean always)54 void onPhoneNumberSelected(PhoneNumber phoneNumber, boolean always); 55 } 56 57 /** 58 * Shows a dialog asking the user to pick a phone number. 59 * Has buttons for selecting always or just once. 60 */ showPhoneNumberSelector(Context context, List<PhoneNumber> numbers, PhoneNumberSelectionCallback callback)61 public static void showPhoneNumberSelector(Context context, 62 List<PhoneNumber> numbers, 63 PhoneNumberSelectionCallback callback) { 64 65 final List<PhoneNumber> selectedPhoneNumber = new ArrayList<>(); 66 List<CarUiRadioButtonListItem> items = new ArrayList<>(); 67 CarUiRadioButtonListItemAdapter adapter = new CarUiRadioButtonListItemAdapter(items); 68 69 for (PhoneNumber number : numbers) { 70 CharSequence readableLabel = number.getReadableLabel(context.getResources()); 71 CarUiRadioButtonListItem item = new CarUiRadioButtonListItem(); 72 item.setTitle(number.isPrimary() 73 ? context.getString(R.string.primary_number_description, readableLabel) 74 : readableLabel); 75 item.setBody(number.getNumber()); 76 item.setOnCheckedChangeListener((i, isChecked) -> { 77 selectedPhoneNumber.clear(); 78 selectedPhoneNumber.add(number); 79 }); 80 items.add(item); 81 } 82 83 new AlertDialogBuilder(context) 84 .setTitle(R.string.select_number_dialog_title) 85 .setSingleChoiceItems(adapter, null) 86 .setNeutralButton(R.string.select_number_dialog_just_once_button, 87 (dialog, which) -> { 88 if (!selectedPhoneNumber.isEmpty()) { 89 callback.onPhoneNumberSelected(selectedPhoneNumber.get(0), false); 90 } 91 }) 92 .setPositiveButton(R.string.select_number_dialog_always_button, 93 (dialog, which) -> { 94 if (!selectedPhoneNumber.isEmpty()) { 95 callback.onPhoneNumberSelected(selectedPhoneNumber.get(0), true); 96 } 97 }) 98 .show(); 99 } 100 101 /** 102 * Gets the primary phone number from the contact. 103 * If no primary number is set, a dialog will pop up asking the user to select one. 104 * If the user presses the "always" button, the phone number will become their 105 * primary phone number. The "always" parameter of the callback will always be false 106 * using this method. 107 */ promptForPrimaryNumber( Context context, Contact contact, PhoneNumberSelectionCallback callback)108 public static void promptForPrimaryNumber( 109 Context context, 110 Contact contact, 111 PhoneNumberSelectionCallback callback) { 112 if (contact.hasPrimaryPhoneNumber()) { 113 callback.onPhoneNumberSelected(contact.getPrimaryPhoneNumber(), false); 114 } else if (contact.getNumbers().size() == 1) { 115 callback.onPhoneNumberSelected(contact.getNumbers().get(0), false); 116 } else if (contact.getNumbers().size() > 0) { 117 showPhoneNumberSelector(context, contact.getNumbers(), (phoneNumber, always) -> { 118 if (always) { 119 TelecomUtils.setAsPrimaryPhoneNumber(context, phoneNumber); 120 } 121 122 callback.onPhoneNumberSelected(phoneNumber, false); 123 }); 124 } else { 125 L.w(TAG, "contact %s doesn't have any phone number", contact.getDisplayName()); 126 } 127 } 128 129 /** 130 * Returns true if the contact has postal address and show postal address config is true. 131 */ hasPostalAddress(Resources resources, @NonNull Contact contact)132 private static boolean hasPostalAddress(Resources resources, @NonNull Contact contact) { 133 boolean showPostalAddress = resources.getBoolean( 134 R.bool.config_show_postal_address); 135 return showPostalAddress && (!contact.getPostalAddresses().isEmpty()); 136 } 137 138 /** 139 * Returns true if the contact has either phone number or postal address to show. 140 */ hasContactDetail(Resources resources, @Nullable Contact contact)141 public static boolean hasContactDetail(Resources resources, @Nullable Contact contact) { 142 boolean hasContactDetail = contact != null 143 && (!contact.getNumbers().isEmpty() || DialerUtils.hasPostalAddress( 144 resources, contact)); 145 return hasContactDetail; 146 } 147 } 148