summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCassie(Yitong) Wang <cassieyw@google.com>2019-06-26 02:02:50 -0700
committerandroid-build-merger <android-build-merger@google.com>2019-06-26 02:02:50 -0700
commitc515c355b191da148734cec41ae97c8509ab6bf3 (patch)
tree4fa14194e1a509bf18fe6362c9649dc6d500019a
parent7c76e58fe1724554322ba7f43fb6a35598bc6683 (diff)
parent9128a19af948485ae75b4ca6d77529fc4f0a90da (diff)
downloadDialer-c515c355b191da148734cec41ae97c8509ab6bf3.tar.gz
Show onhold call info and swap call button on ongoing call page
am: 9128a19af9 Change-Id: I813fc60b076f659d026138f3aa3b0ab42f1416f9
-rw-r--r--res/drawable/ic_swap_calls.xml27
-rw-r--r--res/layout/ongoing_call_fragment.xml12
-rw-r--r--res/layout/onhold_user_profile.xml80
-rw-r--r--res/values-night/colors.xml3
-rw-r--r--res/values/colors.xml3
-rw-r--r--res/values/dimens.xml7
-rw-r--r--res/values/strings.xml4
-rw-r--r--src/com/android/car/dialer/ui/activecall/InCallViewModel.java42
-rw-r--r--src/com/android/car/dialer/ui/activecall/OnHoldCallUserProfileFragment.java98
-rw-r--r--src/com/android/car/dialer/ui/activecall/OngoingCallFragment.java13
10 files changed, 277 insertions, 12 deletions
diff --git a/res/drawable/ic_swap_calls.xml b/res/drawable/ic_swap_calls.xml
new file mode 100644
index 00000000..098ca973
--- /dev/null
+++ b/res/drawable/ic_swap_calls.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/primary_icon_size"
+ android:height="@dimen/primary_icon_size"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+
+ <path
+ android:pathData="M0 0h24v24H0z" />
+ <path
+ android:fillColor="#fffafafa"
+ android:pathData="M18 4l-4 4h3v7c0 1.1-.9 2-2 2s-2-.9-2-2V8c0-2.21-1.79-4-4-4S5 5.79 5 8v7H2l4 4 4-4H7V8c0-1.1.9-2 2-2s2 .9 2 2v7c0 2.21 1.79 4 4 4s4-1.79 4-4V8h3l-4-4z"/>
+</vector>
diff --git a/res/layout/ongoing_call_fragment.xml b/res/layout/ongoing_call_fragment.xml
index cf3d9c09..007531b1 100644
--- a/res/layout/ongoing_call_fragment.xml
+++ b/res/layout/ongoing_call_fragment.xml
@@ -56,6 +56,18 @@ limitations under the License.
app:layout_constraintStart_toStartOf="parent"/>
<fragment
+ android:id="@+id/onhold_user_profile"
+ android:name="com.android.car.dialer.ui.activecall.OnHoldCallUserProfileFragment"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/onhold_user_info_height"
+ android:layout_marginTop="@dimen/onhold_profile_margin_y"
+ android:layout_marginStart="@dimen/onhold_profile_margin_x"
+ android:layout_marginEnd="@dimen/onhold_profile_margin_x"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+
+ <fragment
android:id="@+id/ongoing_call_control_bar"
android:name="com.android.car.dialer.ui.activecall.OnGoingCallControllerBarFragment"
android:layout_width="match_parent"
diff --git a/res/layout/onhold_user_profile.xml b/res/layout/onhold_user_profile.xml
new file mode 100644
index 00000000..806226bb
--- /dev/null
+++ b/res/layout/onhold_user_profile.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<androidx.cardview.widget.CardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:cardBackgroundColor="@color/onhold_call_background"
+ app:cardCornerRadius="@dimen/onhold_profile_corner_radius">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <androidx.constraintlayout.widget.Guideline
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/guideline"
+ android:orientation="vertical"
+ app:layout_constraintGuide_begin="@dimen/onhold_profile_guideline"/>
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/avatar_icon_size"
+ android:layout_height="@dimen/avatar_icon_size"
+ android:scaleType="centerCrop"
+ android:layout_marginStart="@dimen/onhold_profile_avatar_margin"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"/>
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:singleLine="true"
+ app:layout_constraintVertical_chainStyle="packed"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@+id/text"
+ app:layout_constraintStart_toStartOf="@id/guideline"
+ app:layout_constraintEnd_toStartOf="@+id/swap_calls_button"/>
+
+ <TextView
+ android:id="@id/text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/onhold_call_label"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:singleLine="true"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="@id/guideline"
+ app:layout_constraintEnd_toStartOf="@+id/swap_calls_button"/>
+
+ <ImageView
+ android:id="@+id/swap_calls_button"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_swap_calls"
+ android:scaleType="center"
+ android:tint="@color/secondary_icon_color"
+ android:background="?android:attr/selectableItemBackground"
+ android:paddingLeft="@dimen/swap_call_button_margin"
+ android:paddingRight="@dimen/swap_call_button_margin"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"/>
+ </androidx.constraintlayout.widget.ConstraintLayout>
+</androidx.cardview.widget.CardView>
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index c5f70536..abd5d8ee 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -16,6 +16,9 @@
<resources>
<color name="car_key2">@color/car_key2_light</color>
+ <!-- InCall page -->
+ <color name="onhold_call_background">@*android:color/car_grey_900</color>
+
<!-- Components -->
<color name="divider_color">@color/divider_color_dark</color>
<color name="secondary_icon_color">@color/secondary_icon_color_dark</color>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 74d067d7..2b99d101 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -17,10 +17,11 @@
<!-- InCall page -->
<color name="phone_call">@*android:color/car_green_700</color>
<color name="phone_end_call">@*android:color/car_red_500a</color>
+ <color name="onhold_call_background">@*android:color/car_grey_868</color>
<!-- Dialpad page -->
<color name="call_button_outline">@*android:color/car_green_500</color>
-
+
<!--Contact details-->
<color name="contact_details_icon_tint">@color/primary_icon_color</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 222e11b3..cd8bff5d 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -65,6 +65,13 @@
<dimen name="in_call_state_margin_top">@*android:dimen/car_padding_2</dimen>
<dimen name="in_call_margin_between_avatar_and_text">48dp</dimen>
<dimen name="in_call_user_profile_margin">@*android:dimen/car_margin</dimen>
+ <dimen name="onhold_user_info_height">@dimen/list_item_height</dimen>
+ <dimen name="onhold_profile_margin_x">@dimen/list_item_padding</dimen>
+ <dimen name="onhold_profile_margin_y">@*android:dimen/car_padding_3</dimen>
+ <dimen name="onhold_profile_corner_radius">8dp</dimen>
+ <dimen name="onhold_profile_avatar_margin">@*android:dimen/car_keyline_1</dimen>
+ <dimen name="onhold_profile_guideline">@dimen/list_item_guideline</dimen>
+ <dimen name="swap_call_button_margin">@*android:dimen/car_keyline_1</dimen>
<!-- Ringing call dimensions -->
<dimen name="ringing_call_button_touch_target_size">@dimen/touch_target_size</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 554c5f9a..f98c6db4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -139,6 +139,10 @@
<!-- Title for missed call notification [CHAR LIMIT=40]-->
<string name="notification_missed_call">Missed call</string>
+ <!-- Onhold User Profile Info -->
+ <!-- Text to show the call is onhold [CHAR LIMIT=40]-->
+ <string name="onhold_call_label">On Hold</string>
+
<!-- Dialer Setting -->
<!-- Title of the settings page [CHAR LIMIT=30]-->
<string name="setting_title">Settings</string>
diff --git a/src/com/android/car/dialer/ui/activecall/InCallViewModel.java b/src/com/android/car/dialer/ui/activecall/InCallViewModel.java
index 83c66839..f5f8704e 100644
--- a/src/com/android/car/dialer/ui/activecall/InCallViewModel.java
+++ b/src/com/android/car/dialer/ui/activecall/InCallViewModel.java
@@ -64,6 +64,8 @@ public class InCallViewModel extends AndroidViewModel implements
private final LiveData<CallDetail> mCallDetailLiveData;
private final LiveData<Integer> mCallStateLiveData;
private final LiveData<Call> mPrimaryCallLiveData;
+ private final LiveData<Call> mSecondaryCallLiveData;
+ private final LiveData<CallDetail> mSecondaryCallDetailLiveData;
private final LiveData<Integer> mAudioRouteLiveData;
private LiveData<Long> mCallConnectTimeLiveData;
private LiveData<Pair<Integer, Long>> mCallStateAndConnectTimeLiveData;
@@ -88,12 +90,11 @@ public class InCallViewModel extends AndroidViewModel implements
};
// Reuse the same instance so the callback won't be registered more than once.
- private final Call.Callback mIncomingCallStateChangedCallback = new Call.Callback() {
+ private final Call.Callback mCallStateChangedCallback = new Call.Callback() {
@Override
public void onStateChanged(Call call, int state) {
// Sets value to trigger the live data for incoming call and active call list to update.
mCallListLiveData.setValue(mCallListLiveData.getValue());
- call.unregisterCallback(this);
}
};
@@ -105,14 +106,8 @@ public class InCallViewModel extends AndroidViewModel implements
mCallComparator = new CallComparator();
mIncomingCallLiveData = Transformations.map(mCallListLiveData,
- callList -> {
- Call incomingCall = firstMatch(callList,
- call -> call != null && call.getState() == Call.STATE_RINGING);
- if (incomingCall != null) {
- incomingCall.registerCallback(mIncomingCallStateChangedCallback);
- }
- return incomingCall;
- });
+ callList -> firstMatch(callList,
+ call -> call != null && call.getState() == Call.STATE_RINGING));
mOngoingCallListLiveData = Transformations.map(mCallListLiveData,
callList -> {
@@ -137,6 +132,12 @@ public class InCallViewModel extends AndroidViewModel implements
mCallStateAndConnectTimeLiveData =
LiveDataFunctions.pair(mCallStateLiveData, mCallConnectTimeLiveData);
+ mSecondaryCallLiveData = Transformations.map(mOngoingCallListLiveData,
+ callList -> (callList != null && callList.size() > 1) ? callList.get(1) : null);
+
+ mSecondaryCallDetailLiveData = Transformations.switchMap(mSecondaryCallLiveData,
+ input -> input != null ? new CallDetailLiveData(input) : null);
+
mAudioRouteLiveData = new AudioRouteLiveData(mContext);
Intent intent = new Intent(mContext, InCallServiceImpl.class);
@@ -177,12 +178,31 @@ public class InCallViewModel extends AndroidViewModel implements
/**
* Returns the live data which monitor the primary call.
+ * A primary call in the first call in the ongoing call list,
+ * which is sorted based on {@link CallComparator}.
*/
public LiveData<Call> getPrimaryCall() {
return mPrimaryCallLiveData;
}
/**
+ * Returns the live data which monitor the secondary call.
+ * A secondary call in the second call in the ongoing call list,
+ * which is sorted based on {@link CallComparator}.
+ * The value will be null if there is no second call in the call list.
+ */
+ public LiveData<Call> getSecondaryCall() {
+ return mSecondaryCallLiveData;
+ }
+
+ /**
+ * Returns the live data which monitors the secondary call details.
+ */
+ public LiveData<CallDetail> getSecondaryCallDetail() {
+ return mSecondaryCallDetailLiveData;
+ }
+
+ /**
* Returns current audio route.
*/
public LiveData<Integer> getAudioRoute() {
@@ -192,6 +212,7 @@ public class InCallViewModel extends AndroidViewModel implements
@Override
public boolean onTelecomCallAdded(Call telecomCall) {
L.i(TAG, "onTelecomCallAdded %s %s", telecomCall, this);
+ telecomCall.registerCallback(mCallStateChangedCallback);
updateCallList();
return false;
}
@@ -199,6 +220,7 @@ public class InCallViewModel extends AndroidViewModel implements
@Override
public boolean onTelecomCallRemoved(Call telecomCall) {
L.i(TAG, "onTelecomCallRemoved %s %s", telecomCall, this);
+ telecomCall.unregisterCallback(mCallStateChangedCallback);
updateCallList();
return false;
}
diff --git a/src/com/android/car/dialer/ui/activecall/OnHoldCallUserProfileFragment.java b/src/com/android/car/dialer/ui/activecall/OnHoldCallUserProfileFragment.java
new file mode 100644
index 00000000..7740392a
--- /dev/null
+++ b/src/com/android/car/dialer/ui/activecall/OnHoldCallUserProfileFragment.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.dialer.ui.activecall;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.telecom.Call;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.util.Pair;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.ViewModelProviders;
+
+import com.android.car.dialer.R;
+import com.android.car.dialer.ui.view.ContactAvatarOutputlineProvider;
+import com.android.car.telephony.common.CallDetail;
+import com.android.car.telephony.common.TelecomUtils;
+
+/**
+ * A fragment that displays information about onhold call.
+ */
+public class OnHoldCallUserProfileFragment extends Fragment {
+
+ private TextView mTitle;
+ private ImageView mAvatarView;
+ private ImageView mSwapCallsButton;
+ private LiveData<Call> mPrimaryCallLiveData;
+ private LiveData<Call> mSecondaryCallLiveData;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View fragmentView = inflater.inflate(R.layout.onhold_user_profile, container, false);
+
+ mTitle = fragmentView.findViewById(R.id.title);
+ mAvatarView = fragmentView.findViewById(R.id.icon);
+ mAvatarView.setOutlineProvider(ContactAvatarOutputlineProvider.get());
+
+ mSwapCallsButton = fragmentView.findViewById(R.id.swap_calls_button);
+ mSwapCallsButton.setOnClickListener(v -> swapCalls());
+
+ InCallViewModel inCallViewModel = ViewModelProviders.of(getActivity()).get(
+ InCallViewModel.class);
+ inCallViewModel.getSecondaryCallDetail().observe(this, this::updateProfile);
+ mPrimaryCallLiveData = inCallViewModel.getPrimaryCall();
+ mSecondaryCallLiveData = inCallViewModel.getSecondaryCall();
+
+ return fragmentView;
+ }
+
+ private void updateProfile(@Nullable CallDetail callDetail) {
+ if (callDetail == null) {
+ return;
+ }
+
+ String number = callDetail.getNumber();
+ Pair<String, Uri> displayNameAndAvatarUri = TelecomUtils.getDisplayNameAndAvatarUri(
+ getContext(), number);
+
+ mTitle.setText(displayNameAndAvatarUri.first);
+ TelecomUtils.setContactBitmapAsync(getContext(), mAvatarView,
+ displayNameAndAvatarUri.second, displayNameAndAvatarUri.first);
+ }
+
+ private void swapCalls() {
+ // Unholds onhold call
+ if (mSecondaryCallLiveData.getValue() != null) {
+ mSecondaryCallLiveData.getValue().unhold();
+ }
+
+ // hold primary call
+ if (mPrimaryCallLiveData.getValue().getState() != Call.STATE_HOLDING) {
+ mPrimaryCallLiveData.getValue().hold();
+ }
+ }
+}
diff --git a/src/com/android/car/dialer/ui/activecall/OngoingCallFragment.java b/src/com/android/car/dialer/ui/activecall/OngoingCallFragment.java
index c82f04fe..c7421521 100644
--- a/src/com/android/car/dialer/ui/activecall/OngoingCallFragment.java
+++ b/src/com/android/car/dialer/ui/activecall/OngoingCallFragment.java
@@ -17,6 +17,7 @@
package com.android.car.dialer.ui.activecall;
import android.os.Bundle;
+import android.telecom.Call;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -37,11 +38,11 @@ import com.google.common.annotations.VisibleForTesting;
*/
public class OngoingCallFragment extends InCallFragment {
private Fragment mDialpadFragment;
+ private Fragment mOnholdCallFragment;
private View mUserProfileContainerView;
private BackgroundImageView mBackgroundImage;
private MutableLiveData<Boolean> mDialpadState;
-
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
@@ -49,6 +50,7 @@ public class OngoingCallFragment extends InCallFragment {
mUserProfileContainerView = fragmentView.findViewById(R.id.user_profile_container);
mBackgroundImage = fragmentView.findViewById(R.id.background_image);
+ mOnholdCallFragment = getChildFragmentManager().findFragmentById(R.id.onhold_user_profile);
mDialpadFragment = getChildFragmentManager().findFragmentById(R.id.incall_dialpad_fragment);
InCallViewModel inCallViewModel = ViewModelProviders.of(getActivity()).get(
@@ -56,6 +58,7 @@ public class OngoingCallFragment extends InCallFragment {
inCallViewModel.getPrimaryCallDetail().observe(this, this::bindUserProfileView);
inCallViewModel.getCallStateAndConnectTime().observe(this, this::updateCallDescription);
+ inCallViewModel.getSecondaryCall().observe(this, this::maybeShowOnholdCallFragment);
OngoingCallStateViewModel ongoingCallStateViewModel = ViewModelProviders.of(
getActivity()).get(OngoingCallStateViewModel.class);
@@ -88,4 +91,12 @@ public class OngoingCallFragment extends InCallFragment {
mUserProfileContainerView.setVisibility(View.VISIBLE);
mBackgroundImage.setDimmed(false);
}
+
+ private void maybeShowOnholdCallFragment(@Nullable Call secondaryCall) {
+ if (secondaryCall == null || secondaryCall.getState() != Call.STATE_HOLDING) {
+ getChildFragmentManager().beginTransaction().hide(mOnholdCallFragment).commit();
+ } else {
+ getChildFragmentManager().beginTransaction().show(mOnholdCallFragment).commit();
+ }
+ }
}