• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.contact;
18 
19 import android.graphics.Bitmap;
20 import android.graphics.drawable.Drawable;
21 import android.net.Uri;
22 import android.os.Bundle;
23 import android.view.View;
24 
25 import androidx.annotation.NonNull;
26 import androidx.annotation.Nullable;
27 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
28 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
29 import androidx.lifecycle.LiveData;
30 import androidx.lifecycle.ViewModelProvider;
31 
32 import com.android.car.apps.common.LetterTileDrawable;
33 import com.android.car.arch.common.FutureData;
34 import com.android.car.dialer.R;
35 import com.android.car.dialer.ui.common.DialerListBaseFragment;
36 import com.android.car.telephony.common.Contact;
37 import com.android.car.telephony.common.PhoneNumber;
38 import com.android.car.telephony.common.TelecomUtils;
39 import com.android.car.ui.core.CarUi;
40 import com.android.car.ui.toolbar.Toolbar;
41 import com.android.car.ui.toolbar.ToolbarController;
42 
43 import com.bumptech.glide.Glide;
44 import com.bumptech.glide.request.RequestOptions;
45 import com.bumptech.glide.request.target.SimpleTarget;
46 import com.bumptech.glide.request.transition.Transition;
47 
48 import javax.inject.Inject;
49 
50 import dagger.hilt.android.AndroidEntryPoint;
51 
52 /**
53  * A fragment that shows the name of the contact, the photo and all listed phone numbers. It is
54  * primarily used to respond to the results of search queries but supplyig it with the content://
55  * uri of a contact should work too.
56  */
57 @AndroidEntryPoint(DialerListBaseFragment.class)
58 public class ContactDetailsFragment extends Hilt_ContactDetailsFragment implements
59         ContactDetailsAdapter.PhoneNumberPresenter {
60     private static final String TAG = "CD.ContactDetailsFragment";
61     public static final String FRAGMENT_TAG = "CONTACT_DETAIL_FRAGMENT_TAG";
62 
63     // Key to load and save the contact entity instance.
64     private static final String KEY_CONTACT_ENTITY = "ContactEntity";
65 
66     @Inject ContactDetailsAdapter.Factory mContactDetailsAdapterFactory;
67     private Contact mContact;
68     private LiveData<FutureData<Contact>> mContactDetailsLiveData;
69     private ContactDetailsViewModel mContactDetailsViewModel;
70 
71     private boolean mShowActionBarView;
72     private boolean mShowActionBarAvatar;
73 
74     /**
75      * Creates a new ContactDetailsFragment using a {@link Contact}.
76      */
newInstance(Contact contact)77     public static ContactDetailsFragment newInstance(Contact contact) {
78         ContactDetailsFragment fragment = new ContactDetailsFragment();
79         Bundle args = new Bundle();
80         args.putParcelable(KEY_CONTACT_ENTITY, contact);
81         fragment.setArguments(args);
82         return fragment;
83     }
84 
85     @Override
onCreate(Bundle savedInstanceState)86     public void onCreate(Bundle savedInstanceState) {
87         super.onCreate(savedInstanceState);
88 
89         mContact = getArguments() == null ? null : getArguments().getParcelable(KEY_CONTACT_ENTITY);
90         if (mContact == null && savedInstanceState != null) {
91             mContact = savedInstanceState.getParcelable(KEY_CONTACT_ENTITY);
92         }
93         mContactDetailsViewModel = new ViewModelProvider(this).get(
94                 ContactDetailsViewModel.class);
95         mContactDetailsLiveData = mContactDetailsViewModel.getContactDetails(mContact);
96 
97         mShowActionBarView = getResources().getBoolean(
98                 R.bool.config_show_contact_details_action_bar_view);
99         mShowActionBarAvatar = getResources().getBoolean(
100                 R.bool.config_show_contact_details_action_bar_avatar);
101     }
102 
103     @Override
onViewCreated(View view, Bundle savedInstanceState)104     public void onViewCreated(View view, Bundle savedInstanceState) {
105         super.onViewCreated(view, savedInstanceState);
106         ContactDetailsAdapter contactDetailsAdapter = mContactDetailsAdapterFactory.create(mContact,
107                 this);
108         getRecyclerView().setAdapter(contactDetailsAdapter);
109         mContactDetailsLiveData.observe(this, contact -> {
110             if (contact.isLoading()) {
111                 showLoading();
112             } else {
113                 onContactChanged(contact.getData());
114                 contactDetailsAdapter.setContact(contact.getData());
115                 showContent();
116             }
117         });
118     }
119 
onContactChanged(Contact contact)120     private void onContactChanged(Contact contact) {
121         if (getArguments() != null) {
122             getArguments().clear();
123         }
124         ToolbarController toolbar = CarUi.getToolbar(getActivity());
125         // Null check to have unit tests to pass.
126         if (toolbar == null) {
127             return;
128         }
129         toolbar.setTitle(null);
130         toolbar.setLogo(null);
131         if (mShowActionBarView) {
132             toolbar.setTitle(contact == null ? getString(R.string.error_contact_deleted)
133                     : contact.getDisplayName());
134             if (mShowActionBarAvatar) {
135                 int avatarSize = getResources().getDimensionPixelSize(
136                         R.dimen.contact_details_action_bar_avatar_size);
137                 LetterTileDrawable letterTile = TelecomUtils.createLetterTile(getContext(),
138                         contact == null ? null : contact.getInitials(),
139                         contact == null ? null : contact.getDisplayName());
140                 Uri avatarUri = contact == null ? null : contact.getAvatarUri();
141                 Glide.with(this)
142                         .asBitmap()
143                         .load(avatarUri)
144                         .apply(new RequestOptions().override(avatarSize).error(letterTile))
145                         .into(new SimpleTarget<Bitmap>() {
146                             @Override
147                             public void onResourceReady(Bitmap bitmap,
148                                     Transition<? super Bitmap> transition) {
149                                 RoundedBitmapDrawable roundedBitmapDrawable = createFromBitmap(
150                                         bitmap, avatarSize);
151                                 toolbar.setLogo(roundedBitmapDrawable);
152                             }
153 
154                             @Override
155                             public void onLoadFailed(@Nullable Drawable errorDrawable) {
156                                 RoundedBitmapDrawable roundedBitmapDrawable = createFromLetterTile(
157                                         letterTile, avatarSize);
158                                 toolbar.setLogo(roundedBitmapDrawable);
159                             }
160                         });
161             }
162         }
163     }
164 
165     @Override
setupToolbar(@onNull ToolbarController toolbar)166     protected void setupToolbar(@NonNull ToolbarController toolbar) {
167         toolbar.setState(getToolbarState());
168         toolbar.setMenuItems(null);
169     }
170 
171     @Override
getToolbarState()172     protected Toolbar.State getToolbarState() {
173         return Toolbar.State.SUBPAGE;
174     }
175 
176     @Override
onSaveInstanceState(Bundle outState)177     public void onSaveInstanceState(Bundle outState) {
178         super.onSaveInstanceState(outState);
179         outState.putParcelable(KEY_CONTACT_ENTITY, mContact);
180     }
181 
182     @Override
onClick(Contact contact, PhoneNumber phoneNumber)183     public void onClick(Contact contact, PhoneNumber phoneNumber) {
184         boolean isFavorite = phoneNumber.isFavorite();
185         if (isFavorite) {
186             mContactDetailsViewModel.removeFromFavorite(contact, phoneNumber);
187         } else {
188             mContactDetailsViewModel.addToFavorite(contact, phoneNumber);
189         }
190     }
191 
createFromLetterTile(LetterTileDrawable letterTileDrawable, int avatarSize)192     private RoundedBitmapDrawable createFromLetterTile(LetterTileDrawable letterTileDrawable,
193             int avatarSize) {
194         return createFromBitmap(letterTileDrawable.toBitmap(avatarSize), avatarSize);
195     }
196 
createFromBitmap(Bitmap bitmap, int avatarSize)197     private RoundedBitmapDrawable createFromBitmap(Bitmap bitmap, int avatarSize) {
198         RoundedBitmapDrawable roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(
199                 getResources(), bitmap);
200         float radiusPercent = getResources()
201                 .getFloat(R.dimen.contact_avatar_corner_radius_percent);
202         float radius = avatarSize * radiusPercent;
203         roundedBitmapDrawable.setCornerRadius(radius);
204         return roundedBitmapDrawable;
205     }
206 }
207