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                 mNameView.setText(info.getDisplayName());
113 
114                 String phoneNumberLabel = info.getTypeLabel();
115                 if (!phoneNumberLabel.isEmpty()) {
116                     phoneNumberLabel += " ";
117                 }
118                 phoneNumberLabel += TelecomUtils.getFormattedNumber(getContext(), number);
119                 if (!TextUtils.isEmpty(phoneNumberLabel)
120                         && !phoneNumberLabel.equals(info.getDisplayName())) {
121                     mPhoneNumberView.setText(phoneNumberLabel);
122                     mPhoneNumberView.setVisibility(View.VISIBLE);
123                 } else {
124                     mPhoneNumberView.setVisibility(View.GONE);
125                 }
126 
127                 LetterTileDrawable letterTile = TelecomUtils.createLetterTile(
128                         getContext(), info.getInitials(), info.getDisplayName());
129 
130                 Glide.with(this)
131                         .load(info.getAvatarUri())
132                         .apply(new RequestOptions().centerCrop().error(letterTile))
133                         .into(new SimpleTarget<Drawable>() {
134                             @Override
135                             public void onResourceReady(Drawable resource,
136                                     Transition<? super Drawable> glideAnimation) {
137                                 mBackgroundImage.setAlpha(getResources().getFloat(
138                                         R.dimen.config_background_image_alpha));
139                                 mBackgroundImage.setBackgroundDrawable(resource, false);
140                                 mAvatarView.setImageDrawable(resource);
141                             }
142 
143                             @Override
144                             public void onLoadFailed(Drawable errorDrawable) {
145                                 mBackgroundImage.setAlpha(getResources().getFloat(
146                                         R.dimen.config_background_image_error_alpha));
147                                 mBackgroundImage.setBackgroundColor(letterTile.getColor());
148                                 mAvatarView.setImageDrawable(letterTile);
149                             }
150                         });
151             }, getContext().getMainExecutor());
152     }
153 
154     /** Presents the call state and call duration. */
updateCallDescription(@ullable Pair<Integer, Long> callStateAndConnectTime)155     protected void updateCallDescription(@Nullable Pair<Integer, Long> callStateAndConnectTime) {
156         if (callStateAndConnectTime == null || callStateAndConnectTime.first == null) {
157             mUserProfileCallStateText.stop();
158             mUserProfileCallStateText.setText("");
159             return;
160         }
161         if (callStateAndConnectTime.first == Call.STATE_ACTIVE) {
162             mUserProfileCallStateText.setBase(callStateAndConnectTime.second
163                     - System.currentTimeMillis() + SystemClock.elapsedRealtime());
164             mUserProfileCallStateText.start();
165         } else {
166             mUserProfileCallStateText.stop();
167             mUserProfileCallStateText.setText(
168                     TelecomUtils.callStateToUiString(getContext(),
169                             callStateAndConnectTime.first));
170         }
171     }
172 
173     @Override
onStop()174     public void onStop() {
175         super.onStop();
176         if (mPhoneNumberInfoFuture != null) {
177             mPhoneNumberInfoFuture.cancel(true);
178         }
179     }
180 }
181