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
17package com.android.dialer.app.list;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.database.Cursor;
22import android.graphics.drawable.Drawable;
23import android.support.v4.content.ContextCompat;
24import android.telephony.PhoneNumberUtils;
25import android.text.BidiFormatter;
26import android.text.TextDirectionHeuristics;
27import android.view.View;
28import android.view.ViewGroup;
29import com.android.contacts.common.list.ContactListItemView;
30import com.android.contacts.common.list.PhoneNumberListAdapter;
31import com.android.contacts.common.util.ContactDisplayUtils;
32import com.android.dialer.app.R;
33import com.android.dialer.location.GeoUtil;
34import com.android.dialer.phonenumberutil.PhoneNumberHelper;
35
36/**
37 * {@link PhoneNumberListAdapter} with the following added shortcuts, that are displayed as list
38 * items: 1) Directly calling the phone number query 2) Adding the phone number query to a contact
39 *
40 * <p>These shortcuts can be enabled or disabled to toggle whether or not they show up in the list.
41 */
42public class DialerPhoneNumberListAdapter extends PhoneNumberListAdapter {
43
44  public static final int SHORTCUT_INVALID = -1;
45  public static final int SHORTCUT_DIRECT_CALL = 0;
46  public static final int SHORTCUT_CREATE_NEW_CONTACT = 1;
47  public static final int SHORTCUT_ADD_TO_EXISTING_CONTACT = 2;
48  public static final int SHORTCUT_SEND_SMS_MESSAGE = 3;
49  public static final int SHORTCUT_MAKE_VIDEO_CALL = 4;
50  public static final int SHORTCUT_BLOCK_NUMBER = 5;
51  public static final int SHORTCUT_COUNT = 6;
52
53  private final boolean[] shortcutEnabled = new boolean[SHORTCUT_COUNT];
54  private final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
55  private final String countryIso;
56
57  private String formattedQueryString;
58
59  public DialerPhoneNumberListAdapter(Context context) {
60    super(context);
61
62    countryIso = GeoUtil.getCurrentCountryIso(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 < shortcutEnabled.length; i++) {
74      if (shortcutEnabled[i]) {
75        count++;
76      }
77    }
78    return count;
79  }
80
81  public void disableAllShortcuts() {
82    for (int i = 0; i < shortcutEnabled.length; i++) {
83      shortcutEnabled[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(getContext(), null, mIsImsVideoEnabled);
114        assignShortcutToView(v, shortcutType);
115        return v;
116      }
117    } else {
118      return super.getView(position, convertView, parent);
119    }
120  }
121
122  @Override
123  protected ContactListItemView newView(
124      Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
125    final ContactListItemView view = super.newView(context, partition, cursor, position, parent);
126
127    view.setSupportVideoCallIcon(mIsImsVideoEnabled);
128    return view;
129  }
130
131  /**
132   * @param position The position of the item
133   * @return The enabled shortcut type matching the given position if the item is a shortcut, -1
134   *     otherwise
135   */
136  public int getShortcutTypeFromPosition(int position) {
137    int shortcutCount = position - super.getCount();
138    if (shortcutCount >= 0) {
139      // Iterate through the array of shortcuts, looking only for shortcuts where
140      // mShortcutEnabled[i] is true
141      for (int i = 0; shortcutCount >= 0 && i < shortcutEnabled.length; i++) {
142        if (shortcutEnabled[i]) {
143          shortcutCount--;
144          if (shortcutCount < 0) {
145            return i;
146          }
147        }
148      }
149      throw new IllegalArgumentException(
150          "Invalid position - greater than cursor count " + " but not a shortcut.");
151    }
152    return SHORTCUT_INVALID;
153  }
154
155  @Override
156  public boolean isEmpty() {
157    return getShortcutCount() == 0 && super.isEmpty();
158  }
159
160  @Override
161  public boolean isEnabled(int position) {
162    final int shortcutType = getShortcutTypeFromPosition(position);
163    if (shortcutType >= 0) {
164      return true;
165    } else {
166      return super.isEnabled(position);
167    }
168  }
169
170  private void assignShortcutToView(ContactListItemView v, int shortcutType) {
171    final CharSequence text;
172    final Drawable drawable;
173    final Resources resources = getContext().getResources();
174    final String number = getFormattedQueryString();
175    switch (shortcutType) {
176      case SHORTCUT_DIRECT_CALL:
177        text =
178            ContactDisplayUtils.getTtsSpannedPhoneNumber(
179                resources,
180                R.string.search_shortcut_call_number,
181                bidiFormatter.unicodeWrap(number, TextDirectionHeuristics.LTR));
182        drawable = ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_call_vd_theme_24);
183        break;
184      case SHORTCUT_CREATE_NEW_CONTACT:
185        text = resources.getString(R.string.search_shortcut_create_new_contact);
186        drawable =
187            ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_person_add_vd_theme_24);
188        drawable.setAutoMirrored(true);
189        break;
190      case SHORTCUT_ADD_TO_EXISTING_CONTACT:
191        text = resources.getString(R.string.search_shortcut_add_to_contact);
192        drawable =
193            ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_person_add_vd_theme_24);
194        break;
195      case SHORTCUT_SEND_SMS_MESSAGE:
196        text = resources.getString(R.string.search_shortcut_send_sms_message);
197        drawable =
198            ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_message_vd_theme_24);
199        break;
200      case SHORTCUT_MAKE_VIDEO_CALL:
201        text = resources.getString(R.string.search_shortcut_make_video_call);
202        drawable =
203            ContextCompat.getDrawable(getContext(), R.drawable.quantum_ic_videocam_vd_theme_24);
204        break;
205      case SHORTCUT_BLOCK_NUMBER:
206        text = resources.getString(R.string.search_shortcut_block_number);
207        drawable =
208            ContextCompat.getDrawable(getContext(), R.drawable.ic_not_interested_googblue_24dp);
209        break;
210      default:
211        throw new IllegalArgumentException("Invalid shortcut type");
212    }
213    v.setDrawable(drawable);
214    v.setDisplayName(text);
215    v.setAdjustSelectionBoundsEnabled(false);
216  }
217
218  /** @return True if the shortcut state (disabled vs enabled) was changed by this operation */
219  public boolean setShortcutEnabled(int shortcutType, boolean visible) {
220    final boolean changed = shortcutEnabled[shortcutType] != visible;
221    shortcutEnabled[shortcutType] = visible;
222    return changed;
223  }
224
225  public String getFormattedQueryString() {
226    return formattedQueryString;
227  }
228
229  @Override
230  public void setQueryString(String queryString) {
231    formattedQueryString =
232        PhoneNumberHelper.formatNumber(
233            getContext(), PhoneNumberUtils.normalizeNumber(queryString), countryIso);
234    super.setQueryString(queryString);
235  }
236}
237