Home | History | Annotate | Download | only in list
      1 /*
      2 
      3  * Copyright (C) 2011 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 package com.android.dialer.list;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorListenerAdapter;
     21 import android.animation.AnimatorSet;
     22 import android.animation.ObjectAnimator;
     23 import android.content.ClipData;
     24 import android.content.Context;
     25 import android.text.TextUtils;
     26 import android.util.AttributeSet;
     27 import android.util.Log;
     28 import android.view.GestureDetector;
     29 import android.view.MotionEvent;
     30 import android.view.View;
     31 import android.widget.ImageView;
     32 
     33 import com.android.contacts.common.MoreContactUtils;
     34 import com.android.contacts.common.list.ContactEntry;
     35 import com.android.contacts.common.list.ContactTileView;
     36 import com.android.dialer.R;
     37 import com.android.dialer.list.PhoneFavoritesTileAdapter.ContactTileRow;
     38 import com.android.dialer.list.PhoneFavoritesTileAdapter.ViewTypes;
     39 
     40 /**
     41  * A light version of the {@link com.android.contacts.common.list.ContactTileView} that is used in
     42  * Dialtacts for frequently called contacts. Slightly different behavior from superclass when you
     43  * tap it, you want to call the frequently-called number for the contact, even if that is not the
     44  * default number for that contact. This abstract class is the super class to both the row and tile
     45  * view.
     46  */
     47 public abstract class PhoneFavoriteTileView extends ContactTileView {
     48 
     49     private static final String TAG = PhoneFavoriteTileView.class.getSimpleName();
     50     private static final boolean DEBUG = false;
     51 
     52     /** Length of all animations in miniseconds. */
     53     private int mAnimationDuration;
     54 
     55     /** The view that holds the front layer of the favorite contact card. */
     56     private View mFavoriteContactCard;
     57     /** The view that holds the background layer of the removal dialogue. */
     58     private View mRemovalDialogue;
     59     /** Undo button for undoing favorite removal. */
     60     private View mUndoRemovalButton;
     61     /** The view that holds the list view row. */
     62     protected ContactTileRow mParentRow;
     63     /** The view that indicates whether the contact is a favorate. */
     64     protected ImageView mStarView;
     65 
     66     /** Users' most frequent phone number. */
     67     private String mPhoneNumberString;
     68 
     69     /** Custom gesture detector.*/
     70     protected GestureDetector mGestureDetector;
     71 
     72     // Dummy clip data object that is attached to drag shadows so that text views
     73     // don't crash with an NPE if the drag shadow is released in their bounds
     74     private static final ClipData EMPTY_CLIP_DATA = ClipData.newPlainText("", "");
     75 
     76     public PhoneFavoriteTileView(Context context, AttributeSet attrs) {
     77         super(context, attrs);
     78         mAnimationDuration = context.getResources().getInteger(R.integer.fade_duration);
     79     }
     80 
     81     public ContactTileRow getParentRow() {
     82         return mParentRow;
     83     }
     84 
     85     @Override
     86     protected void onFinishInflate() {
     87         super.onFinishInflate();
     88         mFavoriteContactCard = findViewById(com.android.dialer.R.id.contact_favorite_card);
     89         mRemovalDialogue = findViewById(com.android.dialer.R.id.favorite_remove_dialogue);
     90         mUndoRemovalButton = findViewById(com.android.dialer.R.id
     91                 .favorite_remove_undo_button);
     92         mStarView = (ImageView) findViewById(com.android.dialer.R.id.contact_favorite_star);
     93 
     94         mUndoRemovalButton.setOnClickListener(new OnClickListener() {
     95             @Override
     96             public void onClick(View view) {
     97                 undoRemove();
     98             }
     99         });
    100 
    101         setOnLongClickListener(new OnLongClickListener() {
    102             @Override
    103             public boolean onLongClick(View v) {
    104                 final PhoneFavoriteTileView view = (PhoneFavoriteTileView) v;
    105                 // NOTE The drag shadow is handled in the ListView.
    106                 if (view instanceof PhoneFavoriteRegularRowView) {
    107                     final ContactTileRow parent = view.getParentRow();
    108                     // If the view is regular row, start drag the row view.
    109                     // Drag is not available for the item exceeds the PIN_LIMIT.
    110                     if (parent.getRegularRowItemIndex() < PhoneFavoritesTileAdapter.PIN_LIMIT) {
    111                         parent.startDrag(EMPTY_CLIP_DATA, new View.DragShadowBuilder(), null, 0);
    112                     }
    113                 } else {
    114                     // If the view is a tile view, start drag the tile.
    115                     view.startDrag(EMPTY_CLIP_DATA, new View.DragShadowBuilder(), null, 0);
    116                 }
    117                 return true;
    118             }
    119         });
    120     }
    121 
    122     @Override
    123     public void loadFromContact(ContactEntry entry) {
    124         super.loadFromContact(entry);
    125         mPhoneNumberString = null; // ... in case we're reusing the view
    126         if (entry != null) {
    127             // Grab the phone-number to call directly... see {@link onClick()}
    128             mPhoneNumberString = entry.phoneNumber;
    129 
    130             mStarView.setVisibility(entry.isFavorite ? VISIBLE : GONE);
    131             // If this is a blank entry, don't show anything.
    132             // TODO krelease:Just hide the view for now. For this to truly look like an empty row
    133             // the entire ContactTileRow needs to be hidden.
    134             if (entry == ContactEntry.BLANK_ENTRY) {
    135                 setVisibility(View.INVISIBLE);
    136             } else {
    137                 setVisibility(View.VISIBLE);
    138             }
    139         }
    140     }
    141 
    142     public void displayRemovalDialog() {
    143         mRemovalDialogue.setVisibility(VISIBLE);
    144         mRemovalDialogue.setAlpha(0f);
    145         final ObjectAnimator fadeIn = ObjectAnimator.ofFloat(mRemovalDialogue, "alpha",
    146                 1.f).setDuration(mAnimationDuration);
    147 
    148         fadeIn.addListener(new AnimatorListenerAdapter() {
    149             @Override
    150             public void onAnimationStart(Animator animation) {
    151                 mParentRow.setHasTransientState(true);
    152             };
    153 
    154             @Override
    155             public void onAnimationEnd(Animator animation) {
    156                 mParentRow.setHasTransientState(false);
    157             }
    158         });
    159         fadeIn.start();
    160     }
    161 
    162     /**
    163      * Signals the user wants to undo removing the favorite contact.
    164      */
    165     public void undoRemove() {
    166         // Makes the removal dialogue invisible.
    167         mRemovalDialogue.setAlpha(0.0f);
    168         mRemovalDialogue.setVisibility(GONE);
    169 
    170         // Animates back the favorite contact card.
    171         final ObjectAnimator fadeIn = ObjectAnimator.ofFloat(mFavoriteContactCard, "alpha", 1.f).
    172                 setDuration(mAnimationDuration);
    173         final ObjectAnimator moveBack = ObjectAnimator.ofFloat(mFavoriteContactCard, "translationX",
    174                 0.f).setDuration(mAnimationDuration);
    175 
    176         final AnimatorSet animSet = new AnimatorSet();
    177 
    178         animSet.playTogether(fadeIn, moveBack);
    179 
    180         animSet.addListener(new AnimatorListenerAdapter() {
    181             @Override
    182             public void onAnimationStart(Animator animation) {
    183                 mParentRow.setHasTransientState(true);
    184             }
    185             @Override
    186             public void onAnimationEnd(Animator animation) {
    187                 if (mParentRow.getItemViewType() == ViewTypes.FREQUENT) {
    188                     SwipeHelper.setSwipeable(mParentRow, true);
    189                 } else {
    190                     SwipeHelper.setSwipeable(PhoneFavoriteTileView.this, true);
    191                 }
    192                 mParentRow.setHasTransientState(false);
    193             }
    194         });
    195         animSet.start();
    196         // Signals the PhoneFavoritesTileAdapter to undo the potential delete.
    197         mParentRow.getTileAdapter().undoPotentialRemoveEntryIndex();
    198     }
    199 
    200     /**
    201      * Sets up the favorite contact card.
    202      */
    203     public void setupFavoriteContactCard() {
    204         if (mRemovalDialogue != null) {
    205             mRemovalDialogue.setVisibility(GONE);
    206             mRemovalDialogue.setAlpha(0.f);
    207         }
    208         mFavoriteContactCard.setAlpha(1.0f);
    209         mFavoriteContactCard.setTranslationX(0.f);
    210     }
    211 
    212     @Override
    213     protected void onAttachedToWindow() {
    214         mParentRow = (ContactTileRow) getParent();
    215     }
    216 
    217     @Override
    218     protected boolean isDarkTheme() {
    219         return false;
    220     }
    221 
    222     @Override
    223     protected OnClickListener createClickListener() {
    224         return new OnClickListener() {
    225             @Override
    226             public void onClick(View v) {
    227                 // When the removal dialog is present, don't allow a click to call
    228                 if (mListener == null || mRemovalDialogue.isShown()) return;
    229                 if (TextUtils.isEmpty(mPhoneNumberString)) {
    230                     // Copy "superclass" implementation
    231                     mListener.onContactSelected(getLookupUri(), MoreContactUtils
    232                             .getTargetRectFromView(
    233                                     mContext, PhoneFavoriteTileView.this));
    234                 } else {
    235                     // When you tap a frequently-called contact, you want to
    236                     // call them at the number that you usually talk to them
    237                     // at (i.e. the one displayed in the UI), regardless of
    238                     // whether that's their default number.
    239                     mListener.onCallNumberDirectly(mPhoneNumberString);
    240                 }
    241             }
    242         };
    243     }
    244 }
    245