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