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