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