Home | History | Annotate | Download | only in list
      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.dialer.app.list;
     18 
     19 import android.content.Context;
     20 import android.content.res.Resources;
     21 import android.database.Cursor;
     22 import android.telephony.PhoneNumberUtils;
     23 import android.text.BidiFormatter;
     24 import android.text.TextDirectionHeuristics;
     25 import android.view.View;
     26 import android.view.ViewGroup;
     27 import com.android.contacts.common.list.ContactListItemView;
     28 import com.android.contacts.common.list.PhoneNumberListAdapter;
     29 import com.android.contacts.common.util.ContactDisplayUtils;
     30 import com.android.dialer.app.R;
     31 import com.android.dialer.location.GeoUtil;
     32 import com.android.dialer.util.CallUtil;
     33 
     34 /**
     35  * {@link PhoneNumberListAdapter} with the following added shortcuts, that are displayed as list
     36  * items: 1) Directly calling the phone number query 2) Adding the phone number query to a contact
     37  *
     38  * <p>These shortcuts can be enabled or disabled to toggle whether or not they show up in the list.
     39  */
     40 public class DialerPhoneNumberListAdapter extends PhoneNumberListAdapter {
     41 
     42   public static final int SHORTCUT_INVALID = -1;
     43   public static final int SHORTCUT_DIRECT_CALL = 0;
     44   public static final int SHORTCUT_CREATE_NEW_CONTACT = 1;
     45   public static final int SHORTCUT_ADD_TO_EXISTING_CONTACT = 2;
     46   public static final int SHORTCUT_SEND_SMS_MESSAGE = 3;
     47   public static final int SHORTCUT_MAKE_VIDEO_CALL = 4;
     48   public static final int SHORTCUT_BLOCK_NUMBER = 5;
     49   public static final int SHORTCUT_COUNT = 6;
     50 
     51   private final boolean[] mShortcutEnabled = new boolean[SHORTCUT_COUNT];
     52   private final BidiFormatter mBidiFormatter = BidiFormatter.getInstance();
     53   private final boolean mVideoCallingEnabled;
     54   private final String mCountryIso;
     55 
     56   private String mFormattedQueryString;
     57 
     58   public DialerPhoneNumberListAdapter(Context context) {
     59     super(context);
     60 
     61     mCountryIso = GeoUtil.getCurrentCountryIso(context);
     62     mVideoCallingEnabled = CallUtil.isVideoEnabled(context);
     63   }
     64 
     65   @Override
     66   public int getCount() {
     67     return super.getCount() + getShortcutCount();
     68   }
     69 
     70   /** @return The number of enabled shortcuts. Ranges from 0 to a maximum of SHORTCUT_COUNT */
     71   public int getShortcutCount() {
     72     int count = 0;
     73     for (int i = 0; i < mShortcutEnabled.length; i++) {
     74       if (mShortcutEnabled[i]) {
     75         count++;
     76       }
     77     }
     78     return count;
     79   }
     80 
     81   public void disableAllShortcuts() {
     82     for (int i = 0; i < mShortcutEnabled.length; i++) {
     83       mShortcutEnabled[i] = false;
     84     }
     85   }
     86 
     87   @Override
     88   public int getItemViewType(int position) {
     89     final int shortcut = getShortcutTypeFromPosition(position);
     90     if (shortcut >= 0) {
     91       // shortcutPos should always range from 1 to SHORTCUT_COUNT
     92       return super.getViewTypeCount() + shortcut;
     93     } else {
     94       return super.getItemViewType(position);
     95     }
     96   }
     97 
     98   @Override
     99   public int getViewTypeCount() {
    100     // Number of item view types in the super implementation + 2 for the 2 new shortcuts
    101     return super.getViewTypeCount() + SHORTCUT_COUNT;
    102   }
    103 
    104   @Override
    105   public View getView(int position, View convertView, ViewGroup parent) {
    106     final int shortcutType = getShortcutTypeFromPosition(position);
    107     if (shortcutType >= 0) {
    108       if (convertView != null) {
    109         assignShortcutToView((ContactListItemView) convertView, shortcutType);
    110         return convertView;
    111       } else {
    112         final ContactListItemView v =
    113             new ContactListItemView(
    114                 getContext(), null, mVideoCallingEnabled, isCallAndShareEnabled());
    115         assignShortcutToView(v, shortcutType);
    116         return v;
    117       }
    118     } else {
    119       return super.getView(position, convertView, parent);
    120     }
    121   }
    122 
    123   @Override
    124   protected ContactListItemView newView(
    125       Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
    126     final ContactListItemView view = super.newView(context, partition, cursor, position, parent);
    127 
    128     view.setSupportVideoCallIcon(mVideoCallingEnabled);
    129     view.setSupportCallAndShareIcon(isCallAndShareEnabled());
    130     return view;
    131   }
    132 
    133   /**
    134    * @param position The position of the item
    135    * @return The enabled shortcut type matching the given position if the item is a shortcut, -1
    136    *     otherwise
    137    */
    138   public int getShortcutTypeFromPosition(int position) {
    139     int shortcutCount = position - super.getCount();
    140     if (shortcutCount >= 0) {
    141       // Iterate through the array of shortcuts, looking only for shortcuts where
    142       // mShortcutEnabled[i] is true
    143       for (int i = 0; shortcutCount >= 0 && i < mShortcutEnabled.length; i++) {
    144         if (mShortcutEnabled[i]) {
    145           shortcutCount--;
    146           if (shortcutCount < 0) {
    147             return i;
    148           }
    149         }
    150       }
    151       throw new IllegalArgumentException(
    152           "Invalid position - greater than cursor count " + " but not a shortcut.");
    153     }
    154     return SHORTCUT_INVALID;
    155   }
    156 
    157   @Override
    158   public boolean isEmpty() {
    159     return getShortcutCount() == 0 && super.isEmpty();
    160   }
    161 
    162   @Override
    163   public boolean isEnabled(int position) {
    164     final int shortcutType = getShortcutTypeFromPosition(position);
    165     if (shortcutType >= 0) {
    166       return true;
    167     } else {
    168       return super.isEnabled(position);
    169     }
    170   }
    171 
    172   private void assignShortcutToView(ContactListItemView v, int shortcutType) {
    173     final CharSequence text;
    174     final int drawableId;
    175     final Resources resources = getContext().getResources();
    176     final String number = getFormattedQueryString();
    177     switch (shortcutType) {
    178       case SHORTCUT_DIRECT_CALL:
    179         text =
    180             ContactDisplayUtils.getTtsSpannedPhoneNumber(
    181                 resources,
    182                 R.string.search_shortcut_call_number,
    183                 mBidiFormatter.unicodeWrap(number, TextDirectionHeuristics.LTR));
    184         drawableId = R.drawable.ic_search_phone;
    185         break;
    186       case SHORTCUT_CREATE_NEW_CONTACT:
    187         text = resources.getString(R.string.search_shortcut_create_new_contact);
    188         drawableId = R.drawable.ic_search_add_contact;
    189         break;
    190       case SHORTCUT_ADD_TO_EXISTING_CONTACT:
    191         text = resources.getString(R.string.search_shortcut_add_to_contact);
    192         drawableId = R.drawable.quantum_ic_person_white_24;
    193         break;
    194       case SHORTCUT_SEND_SMS_MESSAGE:
    195         text = resources.getString(R.string.search_shortcut_send_sms_message);
    196         drawableId = R.drawable.quantum_ic_message_white_24;
    197         break;
    198       case SHORTCUT_MAKE_VIDEO_CALL:
    199         text = resources.getString(R.string.search_shortcut_make_video_call);
    200         drawableId = R.drawable.quantum_ic_videocam_white_24;
    201         break;
    202       case SHORTCUT_BLOCK_NUMBER:
    203         text = resources.getString(R.string.search_shortcut_block_number);
    204         drawableId = R.drawable.ic_not_interested_googblue_24dp;
    205         break;
    206       default:
    207         throw new IllegalArgumentException("Invalid shortcut type");
    208     }
    209     v.setDrawableResource(drawableId);
    210     v.setDisplayName(text);
    211     v.setPhotoPosition(super.getPhotoPosition());
    212     v.setAdjustSelectionBoundsEnabled(false);
    213   }
    214 
    215   /** @return True if the shortcut state (disabled vs enabled) was changed by this operation */
    216   public boolean setShortcutEnabled(int shortcutType, boolean visible) {
    217     final boolean changed = mShortcutEnabled[shortcutType] != visible;
    218     mShortcutEnabled[shortcutType] = visible;
    219     return changed;
    220   }
    221 
    222   public String getFormattedQueryString() {
    223     return mFormattedQueryString;
    224   }
    225 
    226   @Override
    227   public void setQueryString(String queryString) {
    228     mFormattedQueryString =
    229         PhoneNumberUtils.formatNumber(PhoneNumberUtils.normalizeNumber(queryString), mCountryIso);
    230     super.setQueryString(queryString);
    231   }
    232 }
    233