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.os.Bundle;
20 import android.os.SystemClock;
21 import android.telecom.Call;
22 import android.view.LayoutInflater;
23 import android.view.View;
24 import android.view.ViewGroup;
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.fragment.app.Fragment;
32 import androidx.lifecycle.LiveData;
33 import androidx.lifecycle.ViewModelProviders;
34 
35 import com.android.car.apps.common.LetterTileDrawable;
36 import com.android.car.dialer.R;
37 import com.android.car.dialer.ui.view.ContactAvatarOutputlineProvider;
38 import com.android.car.telephony.common.CallDetail;
39 import com.android.car.telephony.common.TelecomUtils;
40 
41 import java.util.concurrent.CompletableFuture;
42 
43 /**
44  * A fragment that displays information about onhold call.
45  */
46 public class OnHoldCallUserProfileFragment extends Fragment {
47 
48     private TextView mTitle;
49     private ImageView mAvatarView;
50     private View mSwapCallsView;
51     private LiveData<Call> mPrimaryCallLiveData;
52     private CompletableFuture<Void> mPhoneNumberInfoFuture;
53     private LetterTileDrawable mDefaultAvatar;
54     private Chronometer mTimeTextView;
55 
56     @Override
onCreate(Bundle savedInstanceState)57     public void onCreate(Bundle savedInstanceState) {
58         super.onCreate(savedInstanceState);
59         mDefaultAvatar = TelecomUtils.createLetterTile(getContext(), null, null);
60     }
61 
62     @Nullable
63     @Override
onCreateView(@onNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)64     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
65             @Nullable Bundle savedInstanceState) {
66         View fragmentView = inflater.inflate(R.layout.onhold_user_profile, container, false);
67 
68         mTitle = fragmentView.findViewById(R.id.title);
69         mAvatarView = fragmentView.findViewById(R.id.icon);
70         mAvatarView.setOutlineProvider(ContactAvatarOutputlineProvider.get());
71 
72         mSwapCallsView = fragmentView.findViewById(R.id.swap_calls_view);
73         mSwapCallsView.setOnClickListener(v -> swapCalls());
74 
75         InCallViewModel inCallViewModel = ViewModelProviders.of(getActivity()).get(
76                 InCallViewModel.class);
77         inCallViewModel.getSecondaryCallDetail().observe(this, this::updateProfile);
78         mPrimaryCallLiveData = inCallViewModel.getPrimaryCall();
79 
80         mTimeTextView = fragmentView.findViewById(R.id.time);
81         inCallViewModel.getSecondaryCallConnectTime().observe(this, this::updateConnectTime);
82 
83         return fragmentView;
84     }
85 
86     /** Presents the onhold call duration. */
updateConnectTime(Long connectTime)87     protected void updateConnectTime(Long connectTime) {
88         if (connectTime == null) {
89             mTimeTextView.stop();
90             mTimeTextView.setText("");
91             return;
92         }
93         mTimeTextView.setBase(connectTime
94                 - System.currentTimeMillis() + SystemClock.elapsedRealtime());
95         mTimeTextView.start();
96     }
97 
updateProfile(@ullable CallDetail callDetail)98     private void updateProfile(@Nullable CallDetail callDetail) {
99         if (callDetail == null) {
100             return;
101         }
102 
103         mAvatarView.setImageDrawable(mDefaultAvatar);
104 
105         if (mPhoneNumberInfoFuture != null) {
106             mPhoneNumberInfoFuture.cancel(true);
107         }
108 
109         if (callDetail.isConference()) {
110             mTitle.setText(getString(R.string.ongoing_conf_title));
111             return;
112         }
113 
114         String number = callDetail.getNumber();
115         mTitle.setText(TelecomUtils.getFormattedNumber(getContext(), number));
116 
117         mPhoneNumberInfoFuture = TelecomUtils.getPhoneNumberInfo(getContext(), number)
118                 .thenAcceptAsync((info) -> {
119                     mTitle.setText(info.getDisplayName());
120                     TelecomUtils.setContactBitmapAsync(getContext(), mAvatarView,
121                             info.getAvatarUri(), info.getInitials(), info.getDisplayName());
122                 }, getContext().getMainExecutor());
123     }
124 
swapCalls()125     private void swapCalls() {
126         // Hold primary call and the secondary call will automatically come to the foreground.
127         if (mPrimaryCallLiveData.getValue().getState() != Call.STATE_HOLDING) {
128             mPrimaryCallLiveData.getValue().hold();
129         }
130     }
131 
132     @Override
onStop()133     public void onStop() {
134         super.onStop();
135         if (mPhoneNumberInfoFuture != null) {
136             mPhoneNumberInfoFuture.cancel(true);
137         }
138     }
139 }
140