Home | History | Annotate | Download | only in sessiondata
      1 /*
      2  * Copyright (C) 2016 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.incallui.sessiondata;
     18 
     19 import android.graphics.drawable.Drawable;
     20 import android.location.Location;
     21 import android.net.Uri;
     22 import android.os.Bundle;
     23 import android.support.annotation.NonNull;
     24 import android.support.annotation.Nullable;
     25 import android.support.annotation.VisibleForTesting;
     26 import android.support.v4.app.Fragment;
     27 import android.text.TextUtils;
     28 import android.view.LayoutInflater;
     29 import android.view.View;
     30 import android.view.ViewGroup;
     31 import android.widget.FrameLayout;
     32 import android.widget.ImageView;
     33 import android.widget.TextView;
     34 import com.android.dialer.common.FragmentUtils;
     35 import com.android.dialer.common.LogUtil;
     36 import com.android.dialer.multimedia.MultimediaData;
     37 import com.android.incallui.maps.MapsComponent;
     38 import com.bumptech.glide.Glide;
     39 import com.bumptech.glide.load.DataSource;
     40 import com.bumptech.glide.load.engine.GlideException;
     41 import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
     42 import com.bumptech.glide.request.RequestListener;
     43 import com.bumptech.glide.request.target.Target;
     44 
     45 /**
     46  * Displays info from {@link MultimediaData MultimediaData}.
     47  *
     48  * <p>Currently displays image, location (as a map), and message that come bundled with
     49  * MultimediaData when calling {@link #newInstance(MultimediaData, boolean, boolean, boolean)}.
     50  */
     51 public class MultimediaFragment extends Fragment implements AvatarPresenter {
     52 
     53   private static final String ARG_SUBJECT = "subject";
     54   private static final String ARG_IMAGE = "image";
     55   private static final String ARG_LOCATION = "location";
     56   private static final String ARG_INTERACTIVE = "interactive";
     57   private static final String ARG_SHOW_AVATAR = "show_avatar";
     58   private static final String ARG_IS_SPAM = "is_spam";
     59   private ImageView avatarImageView;
     60 
     61   private boolean showAvatar;
     62   private boolean isSpam;
     63 
     64   public static MultimediaFragment newInstance(
     65       @NonNull MultimediaData multimediaData,
     66       boolean isInteractive,
     67       boolean showAvatar,
     68       boolean isSpam) {
     69     return newInstance(
     70         multimediaData.getText(),
     71         multimediaData.getImageUri(),
     72         multimediaData.getLocation(),
     73         isInteractive,
     74         showAvatar,
     75         isSpam);
     76   }
     77 
     78   @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     79   public static MultimediaFragment newInstance(
     80       @Nullable String subject,
     81       @Nullable Uri imageUri,
     82       @Nullable Location location,
     83       boolean isInteractive,
     84       boolean showAvatar,
     85       boolean isSpam) {
     86     Bundle args = new Bundle();
     87     args.putString(ARG_SUBJECT, subject);
     88     args.putParcelable(ARG_IMAGE, imageUri);
     89     args.putParcelable(ARG_LOCATION, location);
     90     args.putBoolean(ARG_INTERACTIVE, isInteractive);
     91     args.putBoolean(ARG_SHOW_AVATAR, showAvatar);
     92     args.putBoolean(ARG_IS_SPAM, isSpam);
     93     MultimediaFragment fragment = new MultimediaFragment();
     94     fragment.setArguments(args);
     95     return fragment;
     96   }
     97 
     98   @Override
     99   public void onCreate(@Nullable Bundle bundle) {
    100     super.onCreate(bundle);
    101     showAvatar = getArguments().getBoolean(ARG_SHOW_AVATAR);
    102     isSpam = getArguments().getBoolean(ARG_IS_SPAM);
    103   }
    104 
    105   @Nullable
    106   @Override
    107   public View onCreateView(
    108       LayoutInflater layoutInflater, @Nullable ViewGroup viewGroup, @Nullable Bundle bundle) {
    109     if (isSpam) {
    110       LogUtil.i("MultimediaFragment.onCreateView", "show spam layout");
    111       return layoutInflater.inflate(R.layout.fragment_spam, viewGroup, false);
    112     }
    113 
    114     boolean hasImage = getImageUri() != null;
    115     boolean hasSubject = !TextUtils.isEmpty(getSubject());
    116     boolean hasMap = getLocation() != null;
    117     if (hasMap && MapsComponent.get(getContext()).getMaps().isAvailable()) {
    118       if (hasImage) {
    119         if (hasSubject) {
    120           LogUtil.i("MultimediaFragment.onCreateView", "show text, image, location layout");
    121           return layoutInflater.inflate(
    122               R.layout.fragment_composer_text_image_frag, viewGroup, false);
    123         } else {
    124           LogUtil.i("MultimediaFragment.onCreateView", "show image, location layout");
    125           return layoutInflater.inflate(R.layout.fragment_composer_image_frag, viewGroup, false);
    126         }
    127       } else if (hasSubject) {
    128         LogUtil.i("MultimediaFragment.onCreateView", "show text, location layout");
    129         return layoutInflater.inflate(R.layout.fragment_composer_text_frag, viewGroup, false);
    130       } else {
    131         LogUtil.i("MultimediaFragment.onCreateView", "show location layout");
    132         return layoutInflater.inflate(R.layout.fragment_composer_frag, viewGroup, false);
    133       }
    134     } else if (hasImage) {
    135       if (hasSubject) {
    136         LogUtil.i("MultimediaFragment.onCreateView", "show text, image layout");
    137         return layoutInflater.inflate(R.layout.fragment_composer_text_image, viewGroup, false);
    138       } else {
    139         LogUtil.i("MultimediaFragment.onCreateView", "show image layout");
    140         return layoutInflater.inflate(R.layout.fragment_composer_image, viewGroup, false);
    141       }
    142     } else {
    143       LogUtil.i("MultimediaFragment.onCreateView", "show text layout");
    144       return layoutInflater.inflate(R.layout.fragment_composer_text, viewGroup, false);
    145     }
    146   }
    147 
    148   @Override
    149   public void onViewCreated(View view, @Nullable Bundle bundle) {
    150     super.onViewCreated(view, bundle);
    151     View container = view.findViewById(R.id.answer_message_container);
    152     if (container != null) {
    153       container.setClipToOutline(true);
    154     }
    155 
    156     // If the call is spam and only has a subject, update the view to reflect that.
    157     if (isSpam
    158         && getLocation() == null
    159         && getImageUri() == null
    160         && !TextUtils.isEmpty(getSubject())) {
    161       ((ImageView) view.findViewById(R.id.spam_image))
    162           .setImageResource(R.drawable.quantum_ic_message_white_24);
    163       ((TextView) view.findViewById(R.id.spam_text)).setText(R.string.spam_message_text);
    164     }
    165 
    166     TextView messageText = view.findViewById(R.id.answer_message_text);
    167     if (messageText != null) {
    168       messageText.setText(getSubject());
    169     }
    170     ImageView mainImage = view.findViewById(R.id.answer_message_image);
    171     if (mainImage != null) {
    172       Glide.with(this)
    173           .load(getImageUri())
    174           .transition(DrawableTransitionOptions.withCrossFade())
    175           .listener(
    176               new RequestListener<Drawable>() {
    177                 @Override
    178                 public boolean onLoadFailed(
    179                     @Nullable GlideException e,
    180                     Object model,
    181                     Target<Drawable> target,
    182                     boolean isFirstResource) {
    183                   view.findViewById(R.id.loading_spinner).setVisibility(View.GONE);
    184                   LogUtil.e("MultimediaFragment.onLoadFailed", null, e);
    185                   // TODO(b/34720074) handle error cases nicely
    186                   return false; // Let Glide handle the rest
    187                 }
    188 
    189                 @Override
    190                 public boolean onResourceReady(
    191                     Drawable drawable,
    192                     Object model,
    193                     Target<Drawable> target,
    194                     DataSource dataSource,
    195                     boolean isFirstResource) {
    196                   LogUtil.enterBlock("MultimediaFragment.onResourceReady");
    197                   view.findViewById(R.id.loading_spinner).setVisibility(View.GONE);
    198                   return false;
    199                 }
    200               })
    201           .into(mainImage);
    202       mainImage.setClipToOutline(true);
    203     }
    204     FrameLayout fragmentHolder = view.findViewById(R.id.answer_message_frag);
    205     if (fragmentHolder != null) {
    206       fragmentHolder.setClipToOutline(true);
    207       Fragment mapFragment =
    208           MapsComponent.get(getContext()).getMaps().createStaticMapFragment(getLocation());
    209       getChildFragmentManager()
    210           .beginTransaction()
    211           .replace(R.id.answer_message_frag, mapFragment)
    212           .commitNow();
    213     }
    214     avatarImageView = view.findViewById(R.id.answer_message_avatar);
    215     if (avatarImageView != null) {
    216       avatarImageView.setVisibility(showAvatar ? View.VISIBLE : View.GONE);
    217     }
    218 
    219     Holder parent = FragmentUtils.getParent(this, Holder.class);
    220     if (parent != null) {
    221       parent.updateAvatar(this);
    222     }
    223   }
    224 
    225   @Nullable
    226   @Override
    227   public ImageView getAvatarImageView() {
    228     return avatarImageView;
    229   }
    230 
    231   @Override
    232   public int getAvatarSize() {
    233     return getResources().getDimensionPixelSize(R.dimen.answer_message_avatar_size);
    234   }
    235 
    236   @Override
    237   public boolean shouldShowAnonymousAvatar() {
    238     return showAvatar;
    239   }
    240 
    241   @Nullable
    242   public String getSubject() {
    243     return getArguments().getString(ARG_SUBJECT);
    244   }
    245 
    246   @Nullable
    247   public Uri getImageUri() {
    248     return getArguments().getParcelable(ARG_IMAGE);
    249   }
    250 
    251   @Nullable
    252   public Location getLocation() {
    253     return getArguments().getParcelable(ARG_LOCATION);
    254   }
    255 
    256   /** Interface for notifying the fragment parent of changes. */
    257   public interface Holder {
    258     void updateAvatar(AvatarPresenter sessionDataScreen);
    259   }
    260 }
    261