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.activecall;
18 
19 import android.graphics.drawable.Drawable;
20 import android.os.Bundle;
21 import android.os.SystemClock;
22 import android.telecom.Call;
23 import android.text.TextUtils;
24 import android.view.View;
25 import android.widget.Chronometer;
26 import android.widget.ImageView;
27 import android.widget.TextView;
28 
29 import androidx.annotation.NonNull;
30 import androidx.annotation.Nullable;
31 import androidx.core.util.Pair;
32 import androidx.fragment.app.Fragment;
33 
34 import com.android.car.apps.common.BackgroundImageView;
35 import com.android.car.apps.common.LetterTileDrawable;
36 import com.android.car.dialer.R;
37 import com.android.car.dialer.log.L;
38 import com.android.car.dialer.ui.view.ContactAvatarOutputlineProvider;
39 import com.android.car.telephony.common.CallDetail;
40 import com.android.car.telephony.common.TelecomUtils;
41 
42 import com.bumptech.glide.Glide;
43 import com.bumptech.glide.request.RequestOptions;
44 import com.bumptech.glide.request.target.SimpleTarget;
45 import com.bumptech.glide.request.transition.Transition;
46 
47 import java.util.concurrent.CompletableFuture;
48 
49 /** A fragment that displays information about a call with actions. */
50 public abstract class InCallFragment extends Fragment {
51     private static final String TAG = "CD.InCallFragment";
52 
53     private View mUserProfileContainerView;
54     private TextView mPhoneNumberView;
55     private Chronometer mUserProfileCallStateText;
56     private TextView mNameView;
57     private ImageView mAvatarView;
58     private BackgroundImageView mBackgroundImage;
59     private LetterTileDrawable mDefaultAvatar;
60     private CompletableFuture<Void> mPhoneNumberInfoFuture;
61     private String mCurrentNumber;
62 
63     @Override
onCreate(Bundle savedInstanceState)64     public void onCreate(Bundle savedInstanceState) {
65         super.onCreate(savedInstanceState);
66         mDefaultAvatar = TelecomUtils.createLetterTile(getContext(), null, null);
67     }
68 
69     /**
70      * Shared UI elements between ongoing call and incoming call page: {@link BackgroundImageView}
71      * and {@link R.layout#user_profile_large}.
72      */
73     @Override
onViewCreated(@onNull View view, @Nullable Bundle savedInstanceState)74     public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
75         mUserProfileContainerView = view.findViewById(R.id.user_profile_container);
76         mNameView = mUserProfileContainerView.findViewById(R.id.user_profile_title);
77         mAvatarView = mUserProfileContainerView.findViewById(R.id.user_profile_avatar);
78         mAvatarView.setOutlineProvider(ContactAvatarOutputlineProvider.get());
79         mPhoneNumberView = mUserProfileContainerView.findViewById(R.id.user_profile_phone_number);
80         mUserProfileCallStateText = mUserProfileContainerView.findViewById(
81                 R.id.user_profile_call_state);
82         mBackgroundImage = view.findViewById(R.id.background_image);
83     }
84 
85     /** Presents the user profile. */
bindUserProfileView(@ullable CallDetail callDetail)86     protected void bindUserProfileView(@Nullable CallDetail callDetail) {
87         L.i(TAG, "bindUserProfileView: %s", callDetail);
88         if (callDetail == null) {
89             return;
90         }
91 
92         String number = callDetail.getNumber();
93         if (mCurrentNumber != null && mCurrentNumber.equals(number)) {
94             return;
95         }
96         mCurrentNumber = number;
97 
98         if (mPhoneNumberInfoFuture != null) {
99             mPhoneNumberInfoFuture.cancel(true);
100         }
101 
102         mNameView.setText(TelecomUtils.getFormattedNumber(getContext(), number));
103         mPhoneNumberView.setVisibility(View.GONE);
104         mAvatarView.setImageDrawable(mDefaultAvatar);
105 
106         mPhoneNumberInfoFuture = TelecomUtils.getPhoneNumberInfo(getContext(), number)
107             .thenAcceptAsync((info) -> {
108                 if (getContext() == null) {
109                     return;
110                 }
111 
112                 String nameViewText = info.getDisplayName();
113                 mNameView.setText(nameViewText);
114 
115                 String phoneNumberLabel = info.getTypeLabel();
116                 if (!phoneNumberLabel.isEmpty()) {
117                     phoneNumberLabel += " ";
118                 }
119 
120                 String bidiWrappedLabel = phoneNumberLabel + TelecomUtils.getBidiWrappedNumber(
121                         TelecomUtils.getFormattedNumber(getContext(), number));
122                 phoneNumberLabel += TelecomUtils.getFormattedNumber(getContext(), number);
123 
124                 if (!TextUtils.isEmpty(phoneNumberLabel)
125                         && !phoneNumberLabel.equals(info.getDisplayName())) {
126                     mPhoneNumberView.setText(bidiWrappedLabel);
127                     mPhoneNumberView.setVisibility(View.VISIBLE);
128                 } else {
129                     mPhoneNumberView.setVisibility(View.GONE);
130                 }
131 
132                 LetterTileDrawable letterTile = TelecomUtils.createLetterTile(
133                         getContext(), info.getInitials(), info.getDisplayName());
134 
135                 Glide.with(this)
136                         .load(info.getAvatarUri())
137                         .apply(new RequestOptions().centerCrop().error(letterTile))
138                         .into(new SimpleTarget<Drawable>() {
139                             @Override
140                             public void onResourceReady(Drawable resource,
141                                     Transition<? super Drawable> glideAnimation) {
142                                 mBackgroundImage.setAlpha(getResources().getFloat(
143                                         R.dimen.config_background_image_alpha));
144                                 mBackgroundImage.setBackgroundDrawable(resource, false);
145                                 mAvatarView.setImageDrawable(resource);
146                             }
147 
148                             @Override
149                             public void onLoadFailed(Drawable errorDrawable) {
150                                 mBackgroundImage.setAlpha(getResources().getFloat(
151                                         R.dimen.config_background_image_error_alpha));
152                                 mBackgroundImage.setBackgroundColor(letterTile.getColor());
153                                 mAvatarView.setImageDrawable(letterTile);
154                             }
155                         });
156             }, getContext().getMainExecutor());
157     }
158 
159     /** Presents the call state and call duration. */
updateCallDescription(@ullable Pair<Integer, Long> callStateAndConnectTime)160     protected void updateCallDescription(@Nullable Pair<Integer, Long> callStateAndConnectTime) {
161         if (callStateAndConnectTime == null || callStateAndConnectTime.first == null) {
162             mUserProfileCallStateText.stop();
163             mUserProfileCallStateText.setText("");
164             return;
165         }
166         if (callStateAndConnectTime.first == Call.STATE_ACTIVE) {
167             mUserProfileCallStateText.setBase(callStateAndConnectTime.second
168                     - System.currentTimeMillis() + SystemClock.elapsedRealtime());
169             mUserProfileCallStateText.start();
170         } else {
171             mUserProfileCallStateText.stop();
172             mUserProfileCallStateText.setText(TelecomUtils.callStateToUiString(getContext(),
173                     callStateAndConnectTime.first));
174         }
175     }
176 
177     @Override
onStop()178     public void onStop() {
179         super.onStop();
180         if (mPhoneNumberInfoFuture != null) {
181             mPhoneNumberInfoFuture.cancel(true);
182         }
183     }
184 }
185