QuickContactActivity.java revision fc423b4040a0ec1728ee32ff40ef430f3e16e9dc
1edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann/*
2edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Copyright (C) 2009 The Android Open Source Project
3edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann *
4edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License");
5edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * you may not use this file except in compliance with the License.
6edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * You may obtain a copy of the License at
7edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann *
8edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann *      http://www.apache.org/licenses/LICENSE-2.0
9edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann *
10edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Unless required by applicable law or agreed to in writing, software
11edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS,
12edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * See the License for the specific language governing permissions and
14edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * limitations under the License.
15edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */
16edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
17edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannpackage com.android.contacts.quickcontact;
18edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
19ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulosimport android.accounts.Account;
208a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.animation.ArgbEvaluator;
21b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport android.animation.ObjectAnimator;
22edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.app.Activity;
23d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.app.Fragment;
24cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks;
25eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.app.SearchManager;
26752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport android.content.ActivityNotFoundException;
27edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.ContentUris;
28ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulosimport android.content.ContentValues;
296bb01347eab60f95deafdfe523b0c368707210f3Brian Attwellimport android.content.Context;
30edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.Intent;
31cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmannimport android.content.Loader;
32dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulosimport android.content.pm.PackageManager;
33dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulosimport android.content.pm.ResolveInfo;
3423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulosimport android.content.res.Resources;
3531b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.graphics.Bitmap;
3695c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwellimport android.graphics.BitmapFactory;
378a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.graphics.Color;
38eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.graphics.PorterDuff;
39eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.graphics.PorterDuffColorFilter;
4031b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.graphics.drawable.BitmapDrawable;
418a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.graphics.drawable.ColorDrawable;
4231b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.graphics.drawable.Drawable;
43eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.net.ParseException;
44edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.net.Uri;
45eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.net.WebAddress;
4631b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.os.AsyncTask;
47edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.os.Bundle;
488a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.os.Trace;
49eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.CalendarContract;
50752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport android.provider.ContactsContract;
51edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Email;
52eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Event;
53eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
54eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Identity;
55eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Im;
56eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Nickname;
57eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Note;
58eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Organization;
59edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Phone;
60eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Relation;
61edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.SipAddress;
62edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
63edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Website;
64752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport android.provider.ContactsContract.Contacts;
6560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulosimport android.provider.ContactsContract.Data;
66ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulosimport android.provider.ContactsContract.Directory;
67eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.DisplayNameSources;
68ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulosimport android.provider.ContactsContract.DataUsageFeedback;
69ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulosimport android.provider.ContactsContract.Intents;
70edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.QuickContact;
71edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.RawContacts;
7231b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.support.v7.graphics.Palette;
730319222b43927d4d9ce7e2a9070f3543661b5782Tyler Gunnimport android.telecom.PhoneAccount;
740319222b43927d4d9ce7e2a9070f3543661b5782Tyler Gunnimport android.telecom.TelecomManager;
75c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwellimport android.text.BidiFormatter;
76c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwellimport android.text.TextDirectionHeuristics;
77edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.text.TextUtils;
78edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.util.Log;
792a4207fb39330e840436215c896cde911489e111Paul Soulosimport android.view.ContextMenu;
802a4207fb39330e840436215c896cde911489e111Paul Soulosimport android.view.ContextMenu.ContextMenuInfo;
81d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.view.Menu;
82d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.view.MenuInflater;
83eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.view.MenuItem;
84f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chenimport android.view.MotionEvent;
85edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.view.View;
86edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.view.View.OnClickListener;
872a4207fb39330e840436215c896cde911489e111Paul Soulosimport android.view.View.OnCreateContextMenuListener;
8810d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawaimport android.view.WindowManager;
89edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.widget.Toast;
90d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.widget.Toolbar;
91edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
9272b3ab1d8a62f228a540b05f4ed6373e494c7d72Christine Chenimport com.android.contacts.ContactSaveService;
93d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport com.android.contacts.ContactsActivity;
942d150da246632b1649999cfabed776133b097775Brian Attwellimport com.android.contacts.NfcHandler;
95e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
96eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.CallUtil;
972a4207fb39330e840436215c896cde911489e111Paul Soulosimport com.android.contacts.common.ClipboardUtils;
98eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.Collapser;
99eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.ContactsUtils;
100d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport com.android.contacts.common.editor.SelectAccountDialogFragment;
10170e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chenimport com.android.contacts.common.interactions.TouchPointManager;
10231b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport com.android.contacts.common.lettertiles.LetterTileDrawable;
103752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport com.android.contacts.common.list.ShortcutIntentBuilder;
104752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport com.android.contacts.common.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener;
1050d5588da244d0992c3ff8f25d0875fdf95a8c644Chiao Chengimport com.android.contacts.common.model.AccountTypeManager;
106cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.Contact;
107cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.ContactLoader;
108cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.RawContact;
109428f008513d1591cc08fcfe2cf0c9237fb313241Chiao Chengimport com.android.contacts.common.model.account.AccountType;
110d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport com.android.contacts.common.model.account.AccountWithDataSet;
111cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.dataitem.DataItem;
112428f008513d1591cc08fcfe2cf0c9237fb313241Chiao Chengimport com.android.contacts.common.model.dataitem.DataKind;
113cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.dataitem.EmailDataItem;
114eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.EventDataItem;
115cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.dataitem.ImDataItem;
116eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.NicknameDataItem;
117eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.NoteDataItem;
118eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.OrganizationDataItem;
119b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport com.android.contacts.common.model.dataitem.PhoneDataItem;
120eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.RelationDataItem;
121eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.SipAddressDataItem;
122eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.StructuredNameDataItem;
123eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.StructuredPostalDataItem;
124eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.WebsiteDataItem;
125eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.util.DateUtils;
126faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwellimport com.android.contacts.common.util.MaterialColorMapUtils;
127faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwellimport com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
128d41ab8ace81a2e44f8b28aa8782679b9e9cca1b9Brian Attwellimport com.android.contacts.common.util.ViewUtil;
129333091ae754ddfc25714c14b9b89534be24379f9Paul Soulosimport com.android.contacts.detail.ContactDisplayUtils;
130f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulosimport com.android.contacts.editor.ContactEditorFragment;
131899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulosimport com.android.contacts.interactions.CalendarInteractionsLoader;
132ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulosimport com.android.contacts.interactions.CallLogInteractionsLoader;
1338a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport com.android.contacts.interactions.ContactDeletionInteraction;
134b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport com.android.contacts.interactions.ContactInteraction;
135b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport com.android.contacts.interactions.SmsInteractionsLoader;
1362d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport com.android.contacts.quickcontact.ExpandingEntryCardView.Entry;
1372a4207fb39330e840436215c896cde911489e111Paul Soulosimport com.android.contacts.quickcontact.ExpandingEntryCardView.EntryContextMenuInfo;
1382ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulosimport com.android.contacts.quickcontact.ExpandingEntryCardView.EntryTag;
139e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwellimport com.android.contacts.quickcontact.ExpandingEntryCardView.ExpandingEntryCardViewListener;
140e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.ImageViewDrawableSetter;
141eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.util.PhoneCapabilityTester;
142b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport com.android.contacts.util.SchedulingUtils;
143eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.util.StructuredPostalUtils;
144b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport com.android.contacts.widget.MultiShrinkScroller;
145b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport com.android.contacts.widget.MultiShrinkScroller.MultiShrinkScrollerListener;
14602eaf11669d25fd885606b3b0700358323532cddBrian Attwellimport com.android.contacts.widget.QuickContactImageView;
147e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.base.Preconditions;
148e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.collect.Lists;
149e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
1502d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport java.util.ArrayList;
151899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulosimport java.util.Arrays;
152eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport java.util.Calendar;
153b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport java.util.Collections;
154b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport java.util.Comparator;
155eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport java.util.Date;
156edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.HashMap;
157edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.List;
158b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport java.util.Map;
159edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
160edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann/**
161edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Mostly translucent {@link Activity} that shows QuickContact dialog. It loads
162edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * data asynchronously, and then shows a popup with details centered around
163edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * {@link Intent#getSourceBounds()}.
164edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */
165d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellpublic class QuickContactActivity extends ContactsActivity {
1668a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1678a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    /**
1688a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell     * QuickContacts immediately takes up the full screen. All possible information is shown.
1698a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell     * This value for {@link android.provider.ContactsContract.QuickContact#EXTRA_MODE}
1708a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell     * should only be used by the Contacts app.
1718a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell     */
1728a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    public static final int MODE_FULLY_EXPANDED = 4;
1738a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
174edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final String TAG = "QuickContact";
175edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1769b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    private static final String KEY_THEME_COLOR = "theme_color";
1779b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
1789b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    private static final int ANIMATION_STATUS_BAR_COLOR_CHANGE_DURATION = 150;
1798a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private static final int REQUEST_CODE_CONTACT_EDITOR_ACTIVITY = 1;
1802e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos    private static final int DEFAULT_SCRIM_ALPHA = 0xC8;
1812e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos    private static final int SCRIM_COLOR = Color.argb(DEFAULT_SCRIM_ALPHA, 0, 0, 0);
182ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos    private static final int REQUEST_CODE_CONTACT_SELECTION_ACTIVITY = 2;
183ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos    private static final String MIMETYPE_SMS = "vnd.android-dir/mms-sms";
184dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
185752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    /** This is the Intent action to install a shortcut in the launcher. */
186752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private static final String ACTION_INSTALL_SHORTCUT =
187752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            "com.android.launcher.action.INSTALL_SHORTCUT";
188edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
189edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @SuppressWarnings("deprecation")
190edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final String LEGACY_AUTHORITY = android.provider.Contacts.AUTHORITY;
191edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
192e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos    private static final String MIMETYPE_GPLUS_PROFILE =
193e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            "vnd.android.cursor.item/vnd.googleplus.profile";
1946a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE = "addtocircle";
1956a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String GPLUS_PROFILE_DATA_5_VIEW_PROFILE = "view";
196e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos    private static final String MIMETYPE_HANGOUTS =
197e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            "vnd.android.cursor.item/vnd.googleplus.profile.comm";
1986a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String HANGOUTS_DATA_5_VIDEO = "hangout";
1996a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String HANGOUTS_DATA_5_MESSAGE = "conversation";
20048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos    private static final String CALL_ORIGIN_QUICK_CONTACTS_ACTIVITY =
20148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            "com.android.contacts.quickcontact.QuickContactActivity";
202e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos
20363176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell    /**
20463176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell     * The URI used to load the the Contact. Once the contact is loaded, use Contact#getLookupUri()
20563176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell     * instead of referencing this URI.
20663176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell     */
207edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private Uri mLookupUri;
208edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private String[] mExcludeMimes;
2098a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private int mExtraMode;
2108a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private int mStatusBarColor;
2118a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private boolean mHasAlreadyBeenOpened;
21297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    private boolean mOnlyOnePhoneNumber;
21397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    private boolean mOnlyOneEmail;
214edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
21502eaf11669d25fd885606b3b0700358323532cddBrian Attwell    private QuickContactImageView mPhotoView;
216eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private ExpandingEntryCardView mContactCard;
2176095369885edcca566a812b551886e29c7ff8039Brian Attwell    private ExpandingEntryCardView mNoContactDetailsCard;
218b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private ExpandingEntryCardView mRecentCard;
219eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private ExpandingEntryCardView mAboutCard;
220b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    private MultiShrinkScroller mScroller;
221d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private SelectAccountDialogFragmentListener mSelectAccountFragmentListener;
2226bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private AsyncTask<Void, Void, Cp2DataCardModel> mEntriesAndActionsTask;
22330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell    private AsyncTask<Void, Void, Void> mRecentDataTask;
2246bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    /**
2256bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * The last copy of Cp2DataCardModel that was passed to {@link #populateContactAndAboutCard}.
2266bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     */
2276bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private Cp2DataCardModel mCachedCp2DataCardModel;
228f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell    /**
229f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  This scrim's opacity is controlled in two different ways. 1) Before the initial entrance
230f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  animation finishes, the opacity is animated by a value animator. This is designed to
231f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  distract the user from the length of the initial loading time. 2) After the initial
232f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  entrance animation, the opacity is directly related to scroll position.
233f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     */
2349b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    private ColorDrawable mWindowScrim;
235f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell    private boolean mIsEntranceAnimationFinished;
236a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell    private MaterialColorMapUtils mMaterialColorMapUtils;
2378477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell    private boolean mIsExitAnimationInProgress;
2388571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell    private boolean mHasComputedThemeColor;
239edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
240a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    /**
241a42ef76251778161d27bc07db214b8c81720e476Paul Soulos     * Used to stop the ExpandingEntry cards from adjusting between an entry click and the intent
242a42ef76251778161d27bc07db214b8c81720e476Paul Soulos     * being launched.
243a42ef76251778161d27bc07db214b8c81720e476Paul Soulos     */
244a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    private boolean mHasIntentLaunched;
245a42ef76251778161d27bc07db214b8c81720e476Paul Soulos
2466cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee    private Contact mContactData;
2479815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann    private ContactLoader mContactLoader;
2489b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    private PorterDuffColorFilter mColorFilter;
2499815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann
2509758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus    private final ImageViewDrawableSetter mPhotoSetter = new ImageViewDrawableSetter();
2519758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus
252edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
253cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * {@link #LEADING_MIMETYPES} is used to sort MIME-types.
254edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     *
255edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * <p>The MIME-types in {@link #LEADING_MIMETYPES} appear in the front of the dialog,
256edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * in the order specified here.</p>
257edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
258edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final List<String> LEADING_MIMETYPES = Lists.newArrayList(
259cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos            Phone.CONTENT_ITEM_TYPE, SipAddress.CONTENT_ITEM_TYPE, Email.CONTENT_ITEM_TYPE,
260405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos            StructuredPostal.CONTENT_ITEM_TYPE);
261edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
262a153dba33c2152332c5706178a367f52b0550723Paul Soulos    private static final List<String> SORTED_ABOUT_CARD_MIMETYPES = Lists.newArrayList(
263a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Nickname.CONTENT_ITEM_TYPE,
264a153dba33c2152332c5706178a367f52b0550723Paul Soulos            // Phonetic name is inserted after nickname if it is available.
265a153dba33c2152332c5706178a367f52b0550723Paul Soulos            // No mimetype for phonetic name exists.
266a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Website.CONTENT_ITEM_TYPE,
267a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Organization.CONTENT_ITEM_TYPE,
268a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Event.CONTENT_ITEM_TYPE,
269a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Relation.CONTENT_ITEM_TYPE,
270a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Im.CONTENT_ITEM_TYPE,
271a153dba33c2152332c5706178a367f52b0550723Paul Soulos            GroupMembership.CONTENT_ITEM_TYPE,
272a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Identity.CONTENT_ITEM_TYPE,
273a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Note.CONTENT_ITEM_TYPE);
274eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
275c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell    private static final BidiFormatter sBidiFormatter = BidiFormatter.getInstance();
276c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell
277b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    /** Id for the background contact loader */
278b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private static final int LOADER_CONTACT_ID = 0;
279b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
280ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final String KEY_LOADER_EXTRA_PHONES =
281ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos            QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_PHONES";
282ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
283b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    /** Id for the background Sms Loader */
284b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private static final int LOADER_SMS_ID = 1;
285b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private static final int MAX_SMS_RETRIEVE = 3;
286ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
287ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    /** Id for the back Calendar Loader */
288899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final int LOADER_CALENDAR_ID = 2;
289ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final String KEY_LOADER_EXTRA_EMAILS =
290ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos            QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_EMAILS";
291899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final int MAX_PAST_CALENDAR_RETRIEVE = 3;
292899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final int MAX_FUTURE_CALENDAR_RETRIEVE = 3;
293899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final long PAST_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR =
29440d7a65c6e68967f3f486715b194c144d93c296fPaul Soulos            1L * 24L * 60L * 60L * 1000L /* 1 day */;
295899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final long FUTURE_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR =
29640d7a65c6e68967f3f486715b194c144d93c296fPaul Soulos            7L * 24L * 60L * 60L * 1000L /* 7 days */;
297899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos
298ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    /** Id for the background Call Log Loader */
299ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final int LOADER_CALL_LOG_ID = 3;
300ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final int MAX_CALL_LOG_RETRIEVE = 3;
3016095369885edcca566a812b551886e29c7ff8039Brian Attwell    private static final int MIN_NUM_CONTACT_ENTRIES_SHOWN = 3;
3026095369885edcca566a812b551886e29c7ff8039Brian Attwell    private static final int MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN = 3;
3036095369885edcca566a812b551886e29c7ff8039Brian Attwell    private static final int CARD_ENTRY_ID_EDIT_CONTACT = -2;
304ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
305ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
306ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final int[] mRecentLoaderIds = new int[]{
307ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        LOADER_SMS_ID,
308ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        LOADER_CALENDAR_ID,
309ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        LOADER_CALL_LOG_ID};
310a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos    private Map<Integer, List<ContactInteraction>> mRecentLoaderResults = new HashMap<>();
311b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
312d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private static final String FRAGMENT_TAG_SELECT_ACCOUNT = "select_account_fragment";
3136cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee
3142d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    final OnClickListener mEntryClickHandler = new OnClickListener() {
3152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        @Override
3162d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        public void onClick(View v) {
3172ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final Object entryTagObject = v.getTag();
3182ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            if (entryTagObject == null || !(entryTagObject instanceof EntryTag)) {
3192ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos                Log.w(TAG, "EntryTag was not used correctly");
3206095369885edcca566a812b551886e29c7ff8039Brian Attwell                return;
3216095369885edcca566a812b551886e29c7ff8039Brian Attwell            }
3222ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final EntryTag entryTag = (EntryTag) entryTagObject;
3232ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final Intent intent = entryTag.getIntent();
3242ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final int dataId = entryTag.getId();
3252ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos
3262ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            if (dataId == CARD_ENTRY_ID_EDIT_CONTACT) {
3272ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos                editContact();
3282d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                return;
3292d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            }
330ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
331ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            // Default to USAGE_TYPE_CALL. Usage is summed among all types for sorting each data id
332ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            // so the exact usage type is not necessary in all cases
333ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            String usageType = DataUsageFeedback.USAGE_TYPE_CALL;
334ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
33520bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos            final Uri intentUri = intent.getData();
33620bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos            if ((intentUri != null && intentUri.getScheme() != null &&
3371cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                    intentUri.getScheme().equals(ContactsUtils.SCHEME_SMSTO)) ||
338ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                    (intent.getType() != null && intent.getType().equals(MIMETYPE_SMS))) {
339ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                usageType = DataUsageFeedback.USAGE_TYPE_SHORT_TEXT;
340ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            }
341ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
342ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            // Data IDs start at 1 so anything less is invalid
343ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            if (dataId > 0) {
34420bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos                final Uri dataUsageUri = DataUsageFeedback.FEEDBACK_URI.buildUpon()
345ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                        .appendPath(String.valueOf(dataId))
346ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                        .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, usageType)
347ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                        .build();
348ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                final boolean successful = getContentResolver().update(
34920bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos                        dataUsageUri, new ContentValues(), null, null) > 0;
350ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                if (!successful) {
351ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                    Log.w(TAG, "DataUsageFeedback increment failed");
352ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                }
353ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            } else {
354ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                Log.w(TAG, "Invalid Data ID");
355ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            }
356ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
35770e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen            // Pass the touch point through the intent for use in the InCallUI
35870e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen            if (Intent.ACTION_CALL.equals(intent.getAction())) {
3591f8a3fda87bf61e579d61e3fdd246548943d070aNancy Chen                if (TouchPointManager.getInstance().hasValidPoint()) {
36070e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen                    Bundle extras = new Bundle();
3611f8a3fda87bf61e579d61e3fdd246548943d070aNancy Chen                    extras.putParcelable(TouchPointManager.TOUCH_POINT,
3621f8a3fda87bf61e579d61e3fdd246548943d070aNancy Chen                            TouchPointManager.getInstance().getPoint());
3630319222b43927d4d9ce7e2a9070f3543661b5782Tyler Gunn                    intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
36470e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen                }
36570e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen            }
36670e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen
367793e73c859ed839c28cc37d80d62bde0a361c78aPaul Soulos            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
368793e73c859ed839c28cc37d80d62bde0a361c78aPaul Soulos
3692e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            // Force the window dim amount to the scrim value for app transition animations
3702e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            // The scrim may be removed before the window transitions to the new activity, which
3712e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            // can cause a flicker in the status and navigation bar. Set dim alone does not work
3722e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            // well because the request is passed through IPC which makes it slow to animate.
3732e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
3742e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos                    WindowManager.LayoutParams.FLAG_DIM_BEHIND);
3752e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            getWindow().setDimAmount(mWindowScrim.getAlpha() / DEFAULT_SCRIM_ALPHA);
3762e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos
377a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            mHasIntentLaunched = true;
378ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            startActivity(intent);
3792d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
3802d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    };
3812d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
382e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    final ExpandingEntryCardViewListener mExpandingEntryCardViewListener
383e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell            = new ExpandingEntryCardViewListener() {
384e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        @Override
385e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        public void onCollapse(int heightDelta) {
386e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell            mScroller.prepareForShrinkingScrollChild(heightDelta);
387e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        }
3880cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
3890cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        @Override
3900cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        public void onExpand(int heightDelta) {
3910cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            mScroller.prepareForExpandingScrollChild();
3920cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        }
393e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    };
394e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell
39597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    private interface ContextMenuIds {
39697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        static final int COPY_TEXT = 0;
39797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        static final int CLEAR_DEFAULT = 1;
39897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        static final int SET_DEFAULT = 2;
39997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    }
40097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
4012a4207fb39330e840436215c896cde911489e111Paul Soulos    private final OnCreateContextMenuListener mEntryContextMenuListener =
4022a4207fb39330e840436215c896cde911489e111Paul Soulos            new OnCreateContextMenuListener() {
4032a4207fb39330e840436215c896cde911489e111Paul Soulos        @Override
4042a4207fb39330e840436215c896cde911489e111Paul Soulos        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
4052a4207fb39330e840436215c896cde911489e111Paul Soulos            if (menuInfo == null) {
4062a4207fb39330e840436215c896cde911489e111Paul Soulos                return;
4072a4207fb39330e840436215c896cde911489e111Paul Soulos            }
40897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            final EntryContextMenuInfo info = (EntryContextMenuInfo) menuInfo;
4092a4207fb39330e840436215c896cde911489e111Paul Soulos            menu.setHeaderTitle(info.getCopyText());
41097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            menu.add(ContextMenu.NONE, ContextMenuIds.COPY_TEXT,
41197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    ContextMenu.NONE, getString(R.string.copy_text));
41297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
41397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Don't allow setting or clearing of defaults for non-editable contacts
41497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            if (!isContactEditable()) {
41597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return;
41697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            }
41797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
41897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            final String selectedMimeType = info.getMimeType();
41997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
42097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Defaults to true will only enable the detail to be copied to the clipboard.
42197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            boolean onlyOneOfMimeType = true;
42297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
42397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Only allow primary support for Phone and Email content types
42497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            if (Phone.CONTENT_ITEM_TYPE.equals(selectedMimeType)) {
42597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                onlyOneOfMimeType = mOnlyOnePhoneNumber;
42697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            } else if (Email.CONTENT_ITEM_TYPE.equals(selectedMimeType)) {
42797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                onlyOneOfMimeType = mOnlyOneEmail;
42897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            }
42997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
43097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Checking for previously set default
43197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            if (info.isSuperPrimary()) {
43297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                menu.add(ContextMenu.NONE, ContextMenuIds.CLEAR_DEFAULT,
43397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        ContextMenu.NONE, getString(R.string.clear_default));
43497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            } else if (!onlyOneOfMimeType) {
43597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                menu.add(ContextMenu.NONE, ContextMenuIds.SET_DEFAULT,
43697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        ContextMenu.NONE, getString(R.string.set_default));
43797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            }
4382a4207fb39330e840436215c896cde911489e111Paul Soulos        }
4392a4207fb39330e840436215c896cde911489e111Paul Soulos    };
4402a4207fb39330e840436215c896cde911489e111Paul Soulos
4412a4207fb39330e840436215c896cde911489e111Paul Soulos    @Override
4422a4207fb39330e840436215c896cde911489e111Paul Soulos    public boolean onContextItemSelected(MenuItem item) {
4432a4207fb39330e840436215c896cde911489e111Paul Soulos        EntryContextMenuInfo menuInfo;
4442a4207fb39330e840436215c896cde911489e111Paul Soulos        try {
4452a4207fb39330e840436215c896cde911489e111Paul Soulos            menuInfo = (EntryContextMenuInfo) item.getMenuInfo();
4462a4207fb39330e840436215c896cde911489e111Paul Soulos        } catch (ClassCastException e) {
4472a4207fb39330e840436215c896cde911489e111Paul Soulos            Log.e(TAG, "bad menuInfo", e);
4482a4207fb39330e840436215c896cde911489e111Paul Soulos            return false;
4492a4207fb39330e840436215c896cde911489e111Paul Soulos        }
4502a4207fb39330e840436215c896cde911489e111Paul Soulos
45197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        switch (item.getItemId()) {
45297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            case ContextMenuIds.COPY_TEXT:
45397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                ClipboardUtils.copyText(this, menuInfo.getCopyLabel(), menuInfo.getCopyText(),
45497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        true);
45597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return true;
45697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            case ContextMenuIds.SET_DEFAULT:
45797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                final Intent setIntent = ContactSaveService.createSetSuperPrimaryIntent(this,
45897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        menuInfo.getId());
45997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                this.startService(setIntent);
46097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return true;
46197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            case ContextMenuIds.CLEAR_DEFAULT:
46297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                final Intent clearIntent = ContactSaveService.createClearPrimaryIntent(this,
46397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        menuInfo.getId());
46497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                this.startService(clearIntent);
46597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return true;
46697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            default:
46797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                throw new IllegalArgumentException("Unknown menu option " + item.getItemId());
46897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
4692a4207fb39330e840436215c896cde911489e111Paul Soulos    }
4702a4207fb39330e840436215c896cde911489e111Paul Soulos
471d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    /**
472d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     * Headless fragment used to handle account selection callbacks invoked from
473d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     * {@link DirectoryContactUtil}.
474d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     */
475d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public static class SelectAccountDialogFragmentListener extends Fragment
476d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            implements SelectAccountDialogFragment.Listener {
477d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
478d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        private QuickContactActivity mQuickContactActivity;
479d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
480d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public SelectAccountDialogFragmentListener() {}
481d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
482d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        @Override
483d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
484d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            DirectoryContactUtil.createCopy(mQuickContactActivity.mContactData.getContentValues(),
485d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    account, mQuickContactActivity);
486d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
487d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
488d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        @Override
489d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public void onAccountSelectorCancelled() {}
490d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
491d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        /**
492d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         * Set the parent activity. Since rotation can cause this fragment to be used across
493d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         * more than one activity instance, we need to explicitly set this value instead
494d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         * of making this class non-static.
495d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         */
496d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public void setQuickContactActivity(QuickContactActivity quickContactActivity) {
497d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mQuickContactActivity = quickContactActivity;
498d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
499d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
500d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
501b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    final MultiShrinkScrollerListener mMultiShrinkScrollerListener
502b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell            = new MultiShrinkScrollerListener() {
503b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        @Override
504b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        public void onScrolledOffBottom() {
505f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell            finish();
506b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        }
5078a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
5088a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        @Override
5098a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        public void onEnterFullscreen() {
5108a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            updateStatusBarColor();
5118a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
5128a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
5138a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        @Override
5148a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        public void onExitFullscreen() {
5158a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            updateStatusBarColor();
5168a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
5178477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell
5188477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        @Override
5198477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        public void onStartScrollOffBottom() {
5208477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            mIsExitAnimationInProgress = true;
5218477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        }
5228477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell
5238477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        @Override
524f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        public void onEntranceAnimationDone() {
525f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell            mIsEntranceAnimationFinished = true;
526f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        }
527f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell
528f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        @Override
529f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        public void onTransparentViewHeightChange(float ratio) {
530f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell            if (mIsEntranceAnimationFinished) {
531f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                mWindowScrim.setAlpha((int) (0xFF * ratio));
5328477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            }
5338477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        }
534b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    };
535b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell
536eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
537eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    /**
538eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * Data items are compared to the same mimetype based off of three qualities:
539eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * 1. Super primary
540eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * 2. Primary
541eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * 3. Times used
542eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     */
543eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final Comparator<DataItem> mWithinMimeTypeDataItemComparator =
544eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            new Comparator<DataItem>() {
545eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        @Override
546eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        public int compare(DataItem lhs, DataItem rhs) {
547eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!lhs.getMimeType().equals(rhs.getMimeType())) {
548eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                Log.wtf(TAG, "Comparing DataItems with different mimetypes lhs.getMimeType(): " +
549eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        lhs.getMimeType() + " rhs.getMimeType(): " + rhs.getMimeType());
550eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 0;
551eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
552eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
553eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (lhs.isSuperPrimary()) {
554eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return -1;
555eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (rhs.isSuperPrimary()) {
556eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 1;
557eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (lhs.isPrimary() && !rhs.isPrimary()) {
558eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return -1;
559eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (!lhs.isPrimary() && rhs.isPrimary()) {
560eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 1;
561eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else {
562eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final int lhsTimesUsed =
563eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        lhs.getTimesUsed() == null ? 0 : lhs.getTimesUsed();
564eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final int rhsTimesUsed =
565eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        rhs.getTimesUsed() == null ? 0 : rhs.getTimesUsed();
566eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
567eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return rhsTimesUsed - lhsTimesUsed;
568eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
569eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
570eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    };
571eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
572cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos    /**
573cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * Sorts among different mimetypes based off:
574cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * 1. Times used
575cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * 2. Last time used
576cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * 3. Statically defined
577cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     */
578eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final Comparator<List<DataItem>> mAmongstMimeTypeDataItemComparator =
579eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            new Comparator<List<DataItem>> () {
580eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        @Override
581eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        public int compare(List<DataItem> lhsList, List<DataItem> rhsList) {
582eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            DataItem lhs = lhsList.get(0);
583eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            DataItem rhs = rhsList.get(0);
584eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final int lhsTimesUsed = lhs.getTimesUsed() == null ? 0 : lhs.getTimesUsed();
585eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final int rhsTimesUsed = rhs.getTimesUsed() == null ? 0 : rhs.getTimesUsed();
586eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final int timesUsedDifference = rhsTimesUsed - lhsTimesUsed;
587eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (timesUsedDifference != 0) {
588eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return timesUsedDifference;
589eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
590eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
591eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final long lhsLastTimeUsed =
592eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    lhs.getLastTimeUsed() == null ? 0 : lhs.getLastTimeUsed();
593eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final long rhsLastTimeUsed =
594eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    rhs.getLastTimeUsed() == null ? 0 : rhs.getLastTimeUsed();
595eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final long lastTimeUsedDifference = rhsLastTimeUsed - lhsLastTimeUsed;
596eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (lastTimeUsedDifference > 0) {
597eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 1;
598eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (lastTimeUsedDifference < 0) {
599eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return -1;
600eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
601eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
602eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Times used and last time used are the same. Resort to statically defined.
603eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String lhsMimeType = lhs.getMimeType();
604eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String rhsMimeType = rhs.getMimeType();
605eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            for (String mimeType : LEADING_MIMETYPES) {
606eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (lhsMimeType.equals(mimeType)) {
607eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    return -1;
608eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                } else if (rhsMimeType.equals(mimeType)) {
609eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    return 1;
610eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                }
611eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
612eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            return 0;
613eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
614eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    };
615eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
616edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @Override
617f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen    public boolean dispatchTouchEvent(MotionEvent ev) {
618f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
619f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen            TouchPointManager.getInstance().setPoint((int) ev.getRawX(), (int) ev.getRawY());
620f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen        }
621f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen        return super.dispatchTouchEvent(ev);
622f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen    }
623f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen
624f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen    @Override
6258a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    protected void onCreate(Bundle savedInstanceState) {
6268a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.beginSection("onCreate()");
6278a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.onCreate(savedInstanceState);
628edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
6298a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        getWindow().setStatusBarColor(Color.TRANSPARENT);
6302426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann
631d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        processIntent(getIntent());
632dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
63310d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa        // Show QuickContact in front of soft input
63410d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
63510d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
63610d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa
637edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        setContentView(R.layout.quickcontact_activity);
638edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
639a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell        mMaterialColorMapUtils = new MaterialColorMapUtils(getResources());
640a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell
6410cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        mScroller = (MultiShrinkScroller) findViewById(R.id.multiscroller);
6420cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
643eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mContactCard = (ExpandingEntryCardView) findViewById(R.id.communication_card);
6446095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard = (ExpandingEntryCardView) findViewById(R.id.no_contact_data_card);
645b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        mRecentCard = (ExpandingEntryCardView) findViewById(R.id.recent_card);
646eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mAboutCard = (ExpandingEntryCardView) findViewById(R.id.about_card);
647edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
6486095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setOnClickListener(mEntryClickHandler);
649eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mContactCard.setOnClickListener(mEntryClickHandler);
650eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mContactCard.setExpandButtonText(
65123889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos        getResources().getString(R.string.expanding_entry_card_view_see_all));
6522a4207fb39330e840436215c896cde911489e111Paul Soulos        mContactCard.setOnCreateContextMenuListener(mEntryContextMenuListener);
653b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
654b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        mRecentCard.setOnClickListener(mEntryClickHandler);
655b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        mRecentCard.setTitle(getResources().getString(R.string.recent_card_title));
656edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
657eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mAboutCard.setOnClickListener(mEntryClickHandler);
6582a4207fb39330e840436215c896cde911489e111Paul Soulos        mAboutCard.setOnCreateContextMenuListener(mEntryContextMenuListener);
659eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
66002eaf11669d25fd885606b3b0700358323532cddBrian Attwell        mPhotoView = (QuickContactImageView) findViewById(R.id.photo);
66163176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        final View transparentView = findViewById(R.id.transparent_view);
6620d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell        if (mScroller != null) {
66363176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell            transparentView.setOnClickListener(new OnClickListener() {
6640d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                @Override
6650d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                public void onClick(View v) {
6660d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                    mScroller.scrollOffBottom();
6670d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                }
6680d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell            });
6690d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell        }
670edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
671d41ab8ace81a2e44f8b28aa8782679b9e9cca1b9Brian Attwell        // Allow a shadow to be shown under the toolbar.
672d41ab8ace81a2e44f8b28aa8782679b9e9cca1b9Brian Attwell        ViewUtil.addRectangularOutlineProvider(findViewById(R.id.toolbar_parent), getResources());
673d41ab8ace81a2e44f8b28aa8782679b9e9cca1b9Brian Attwell
674d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
675d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        setActionBar(toolbar);
6769b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        getActionBar().setTitle(null);
6779b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        // Put a TextView with a known resource id into the ActionBar. This allows us to easily
6789b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        // find the correct TextView location & size later.
6799b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        toolbar.addView(getLayoutInflater().inflate(R.layout.quickcontact_title_placeholder, null));
6806219668d0612f7522bd15a9d34c6232cb15b9a6cYorke Lee
6818a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mHasAlreadyBeenOpened = savedInstanceState != null;
682f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        mIsEntranceAnimationFinished = mHasAlreadyBeenOpened;
6839b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        mWindowScrim = new ColorDrawable(SCRIM_COLOR);
684f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        mWindowScrim.setAlpha(0);
6859b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        getWindow().setBackgroundDrawable(mWindowScrim);
686edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
687c33ae17c9816b770041ee1f9ccde10e7c7eee491Brian Attwell        mScroller.initialize(mMultiShrinkScrollerListener, mExtraMode == MODE_FULLY_EXPANDED);
688ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell        // mScroller needs to perform asynchronous measurements after initalize(), therefore
689ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell        // we can't mark this as GONE.
690ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell        mScroller.setVisibility(View.INVISIBLE);
6918a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
6929b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        setHeaderNameText(R.string.missing_name);
6939b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
694d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mSelectAccountFragmentListener= (SelectAccountDialogFragmentListener) getFragmentManager()
695d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                .findFragmentByTag(FRAGMENT_TAG_SELECT_ACCOUNT);
696d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (mSelectAccountFragmentListener == null) {
697d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mSelectAccountFragmentListener = new SelectAccountDialogFragmentListener();
698d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            getFragmentManager().beginTransaction().add(0, mSelectAccountFragmentListener,
699d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    FRAGMENT_TAG_SELECT_ACCOUNT).commit();
700d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mSelectAccountFragmentListener.setRetainInstance(true);
701d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
702d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mSelectAccountFragmentListener.setQuickContactActivity(this);
70323889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos
704f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        SchedulingUtils.doOnPreDraw(mScroller, /* drawNextFrame = */ true,
705f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                new Runnable() {
706f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                    @Override
707f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                    public void run() {
708f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                        if (!mHasAlreadyBeenOpened) {
709f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            // The initial scrim opacity must match the scrim opacity that would be
710f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            // achieved by scrolling to the starting position.
711f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            final float alphaRatio = mExtraMode == MODE_FULLY_EXPANDED ?
712f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                                    1 : mScroller.getStartingTransparentHeightRatio();
713f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            final int duration = getResources().getInteger(
714f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                                    android.R.integer.config_shortAnimTime);
715f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            final int desiredAlpha = (int) (0xFF * alphaRatio);
716f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            ObjectAnimator o = ObjectAnimator.ofInt(mWindowScrim, "alpha", 0,
717f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                                    desiredAlpha).setDuration(duration);
718f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell
719f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            o.start();
720f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                        }
721f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                    }
722f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                });
723f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell
7249b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        if (savedInstanceState != null) {
7259b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            final int color = savedInstanceState.getInt(KEY_THEME_COLOR, 0);
726ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell            SchedulingUtils.doOnPreDraw(mScroller, /* drawNextFrame = */ false,
727ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                    new Runnable() {
728ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                        @Override
729ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                        public void run() {
730ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // Need to wait for the pre draw before setting the initial scroll
731ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // value. Prior to pre draw all scroll values are invalid.
732ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            if (mHasAlreadyBeenOpened) {
733ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                                mScroller.setVisibility(View.VISIBLE);
734ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                                mScroller.setScroll(mScroller.getScrollNeededToBeFullScreen());
735ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            }
736ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // Need to wait for pre draw for setting the theme color. Setting the
737ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // header tint before the MultiShrinkScroller has been measured will
738ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // cause incorrect tinting calculations.
739ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            if (color != 0) {
740a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                                setThemeColor(mMaterialColorMapUtils
741a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                                        .calculatePrimaryAndSecondaryColor(color));
7429b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell                            }
743ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                        }
744ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                    });
7459b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        }
7469b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
7478a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
7488a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
7498a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
750405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos    @Override
751405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
7528a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (requestCode == REQUEST_CODE_CONTACT_EDITOR_ACTIVITY &&
7538a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                resultCode == ContactDeletionInteraction.RESULT_CODE_DELETED) {
7548a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // The contact that we were showing has been deleted.
7558a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            finish();
756ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos        } else if (requestCode == REQUEST_CODE_CONTACT_SELECTION_ACTIVITY &&
757ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                resultCode != RESULT_CANCELED) {
758ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos            processIntent(data);
759b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        }
7608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
761dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
7628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    @Override
7638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    protected void onNewIntent(Intent intent) {
7648a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.onNewIntent(intent);
7658a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mHasAlreadyBeenOpened = true;
766f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        mIsEntranceAnimationFinished = true;
7678571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell        mHasComputedThemeColor = false;
768d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        processIntent(intent);
769d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
770d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
7719b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    @Override
7729b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    public void onSaveInstanceState(Bundle savedInstanceState) {
7739b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        super.onSaveInstanceState(savedInstanceState);
7749b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        if (mColorFilter != null) {
7759b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            savedInstanceState.putInt(KEY_THEME_COLOR, mColorFilter.getColor());
7769b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        }
7779b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    }
7789b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
779d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private void processIntent(Intent intent) {
780f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos        if (intent == null) {
781f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos            finish();
782f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos            return;
783f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos        }
784d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        Uri lookupUri = intent.getData();
785d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
786d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        // Check to see whether it comes from the old version.
787d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (lookupUri != null && LEGACY_AUTHORITY.equals(lookupUri.getAuthority())) {
788d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final long rawContactId = ContentUris.parseId(lookupUri);
789d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            lookupUri = RawContacts.getContactLookupUri(getContentResolver(),
790d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
791d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
792d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mExtraMode = getIntent().getIntExtra(QuickContact.EXTRA_MODE,
793d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                QuickContact.MODE_LARGE);
794d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        final Uri oldLookupUri = mLookupUri;
795d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
796d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mLookupUri = Preconditions.checkNotNull(lookupUri, "missing lookupUri");
797d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mExcludeMimes = intent.getStringArrayExtra(QuickContact.EXTRA_EXCLUDE_MIMES);
798d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (oldLookupUri == null) {
799d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mContactLoader = (ContactLoader) getLoaderManager().initLoader(
800d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    LOADER_CONTACT_ID, null, mLoaderContactCallbacks);
801d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        } else if (oldLookupUri != mLookupUri) {
802d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // After copying a directory contact, the contact URI changes. Therefore,
803d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // we need to restart the loader and reload the new contact.
804899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos            for (int interactionLoaderId : mRecentLoaderIds) {
805899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                getLoaderManager().destroyLoader(interactionLoaderId);
806899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos            }
807405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos            mContactLoader = (ContactLoader) getLoaderManager().restartLoader(
808405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos                    LOADER_CONTACT_ID, null, mLoaderContactCallbacks);
809d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
8102d150da246632b1649999cfabed776133b097775Brian Attwell
8112d150da246632b1649999cfabed776133b097775Brian Attwell        NfcHandler.register(this, mLookupUri);
8122426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann    }
813edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
814b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    private void runEntranceAnimation() {
8158a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mHasAlreadyBeenOpened) {
8168a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            return;
8178a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
8188a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mHasAlreadyBeenOpened = true;
819c33ae17c9816b770041ee1f9ccde10e7c7eee491Brian Attwell        mScroller.scrollUpForEntranceAnimation(mExtraMode != MODE_FULLY_EXPANDED);
820b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    }
821b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell
82281281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /** Assign this string to the view if it is not empty. */
823d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private void setHeaderNameText(int resId) {
8249b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        if (mScroller != null) {
825f43f573340fd9de5d30b43d7c96cac1ec9021e58Brian Attwell            mScroller.setTitle(getText(resId) == null ? null : getText(resId).toString());
8269b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        }
82781281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    }
82881281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan
82981281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /** Assign this string to the view if it is not empty. */
830f43f573340fd9de5d30b43d7c96cac1ec9021e58Brian Attwell    private void setHeaderNameText(String value) {
831d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (!TextUtils.isEmpty(value)) {
8329b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            if (mScroller != null) {
833f43f573340fd9de5d30b43d7c96cac1ec9021e58Brian Attwell                mScroller.setTitle(value);
8349b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            }
83581281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        }
83681281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    }
83781281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan
83881281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /**
839edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Check if the given MIME-type appears in the list of excluded MIME-types
840edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * that the most-recent caller requested.
841edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
842edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private boolean isMimeExcluded(String mimeType) {
843edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        if (mExcludeMimes == null) return false;
844edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String excludedMime : mExcludeMimes) {
845edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (TextUtils.equals(excludedMime, mimeType)) {
846edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                return true;
847edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
848edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
849edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        return false;
850edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
851edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
852edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
853cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann     * Handle the result from the ContactLoader
854edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
8558a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private void bindContactData(final Contact data) {
8568a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.beginSection("bindContactData");
8576cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee        mContactData = data;
858d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        invalidateOptionsMenu();
859edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
8608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
8618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.beginSection("Set display photo & name");
862dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
86302eaf11669d25fd885606b3b0700358323532cddBrian Attwell        mPhotoView.setIsBusiness(mContactData.isDisplayNameFromOrganization());
8646219668d0612f7522bd15a9d34c6232cb15b9a6cYorke Lee        mPhotoSetter.setupContactPhoto(data, mPhotoView);
86531b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        extractAndApplyTintFromPhotoViewAsynchronously();
8664936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        analyzeWhitenessOfPhotoAsynchronously();
867333091ae754ddfc25714c14b9b89534be24379f9Paul Soulos        setHeaderNameText(ContactDisplayUtils.getDisplayName(this, data).toString());
868edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
8698a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
870dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
8716bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        mEntriesAndActionsTask = new AsyncTask<Void, Void, Cp2DataCardModel>() {
8728a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
8738a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            @Override
8746bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            protected Cp2DataCardModel doInBackground(
875eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    Void... params) {
876eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return generateDataModelFromContact(data);
8778a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            }
8788a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
8798a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            @Override
8806bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            protected void onPostExecute(Cp2DataCardModel cardDataModel) {
8816bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                super.onPostExecute(cardDataModel);
8828a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                // Check that original AsyncTask parameters are still valid and the activity
8838a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                // is still running before binding to UI. A new intent could invalidate
8848a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                // the results, for example.
8858a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                if (data == mContactData && !isCancelled()) {
8866bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                    bindDataToCards(cardDataModel);
8878a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    showActivity();
8888a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                }
8898a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            }
8908a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        };
8918a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mEntriesAndActionsTask.execute();
8928a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
8938a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
8946bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private void bindDataToCards(Cp2DataCardModel cp2DataCardModel) {
8956bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        startInteractionLoaders(cp2DataCardModel);
8966bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        populateContactAndAboutCard(cp2DataCardModel);
897eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
898eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
8996bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private void startInteractionLoaders(Cp2DataCardModel cp2DataCardModel) {
9006bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final Map<String, List<DataItem>> dataItemsMap = cp2DataCardModel.dataItemsMap;
9016bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<DataItem> phoneDataItems = dataItemsMap.get(Phone.CONTENT_ITEM_TYPE);
90297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        if (phoneDataItems != null && phoneDataItems.size() == 1) {
90397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            mOnlyOnePhoneNumber = true;
90497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
905eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String[] phoneNumbers = null;
906eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (phoneDataItems != null) {
907eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            phoneNumbers = new String[phoneDataItems.size()];
908eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            for (int i = 0; i < phoneDataItems.size(); ++i) {
909eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                phoneNumbers[i] = ((PhoneDataItem) phoneDataItems.get(i)).getNumber();
910eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
911eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
912ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        final Bundle phonesExtraBundle = new Bundle();
913eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        phonesExtraBundle.putStringArray(KEY_LOADER_EXTRA_PHONES, phoneNumbers);
914eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
915eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("start sms loader");
9168a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        getLoaderManager().initLoader(
9178a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                LOADER_SMS_ID,
918ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                phonesExtraBundle,
919ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                mLoaderInteractionsCallbacks);
920ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        Trace.endSection();
921ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
922ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        Trace.beginSection("start call log loader");
923ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        getLoaderManager().initLoader(
924ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                LOADER_CALL_LOG_ID,
925ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                phonesExtraBundle,
9268a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                mLoaderInteractionsCallbacks);
927899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos        Trace.endSection();
9288a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
929eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
930899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos        Trace.beginSection("start calendar loader");
9316bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<DataItem> emailDataItems = dataItemsMap.get(Email.CONTENT_ITEM_TYPE);
93297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        if (emailDataItems != null && emailDataItems.size() == 1) {
93397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            mOnlyOneEmail = true;
93497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
935eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String[] emailAddresses = null;
936eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (emailDataItems != null) {
937eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            emailAddresses = new String[emailDataItems.size()];
938eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            for (int i = 0; i < emailDataItems.size(); ++i) {
939eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                emailAddresses[i] = ((EmailDataItem) emailDataItems.get(i)).getAddress();
940eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
941eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
942ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        final Bundle emailsExtraBundle = new Bundle();
943eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        emailsExtraBundle.putStringArray(KEY_LOADER_EXTRA_EMAILS, emailAddresses);
944899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos        getLoaderManager().initLoader(
945899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                LOADER_CALENDAR_ID,
946ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                emailsExtraBundle,
947899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                mLoaderInteractionsCallbacks);
9488a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
9498a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
9508a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
9518a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private void showActivity() {
9528a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mScroller != null) {
9538a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            mScroller.setVisibility(View.VISIBLE);
9548a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            SchedulingUtils.doOnPreDraw(mScroller, /* drawNextFrame = */ false,
9558a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    new Runnable() {
9568a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                        @Override
9578a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                        public void run() {
9588a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                            runEntranceAnimation();
9598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                        }
9608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    });
9618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
9628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
9638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
9646bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private List<List<Entry>> buildAboutCardEntries(Map<String, List<DataItem>> dataItemsMap) {
965a153dba33c2152332c5706178a367f52b0550723Paul Soulos        final List<List<Entry>> aboutCardEntries = new ArrayList<>();
966a153dba33c2152332c5706178a367f52b0550723Paul Soulos        for (String mimetype : SORTED_ABOUT_CARD_MIMETYPES) {
9676bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final List<DataItem> mimeTypeItems = dataItemsMap.get(mimetype);
968a153dba33c2152332c5706178a367f52b0550723Paul Soulos            if (mimeTypeItems == null) {
969a153dba33c2152332c5706178a367f52b0550723Paul Soulos                continue;
970a153dba33c2152332c5706178a367f52b0550723Paul Soulos            }
9716bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            // Set aboutCardTitleOut = null, since SORTED_ABOUT_CARD_MIMETYPES doesn't contain
9726bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            // the name mimetype.
9736bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final List<Entry> aboutEntries = dataItemsToEntries(mimeTypeItems,
9746bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                    /* aboutCardTitleOut = */ null);
975a153dba33c2152332c5706178a367f52b0550723Paul Soulos            if (aboutEntries.size() > 0) {
976a153dba33c2152332c5706178a367f52b0550723Paul Soulos                aboutCardEntries.add(aboutEntries);
977a153dba33c2152332c5706178a367f52b0550723Paul Soulos            }
978a153dba33c2152332c5706178a367f52b0550723Paul Soulos        }
979a153dba33c2152332c5706178a367f52b0550723Paul Soulos        return aboutCardEntries;
980a153dba33c2152332c5706178a367f52b0550723Paul Soulos    }
981a153dba33c2152332c5706178a367f52b0550723Paul Soulos
982a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    @Override
983a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    protected void onResume() {
984a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        super.onResume();
985a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        // If returning from a launched activity, repopulate the contact and about card
986a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        if (mHasIntentLaunched) {
987a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            mHasIntentLaunched = false;
9886bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            populateContactAndAboutCard(mCachedCp2DataCardModel);
989a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        }
990a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    }
991a42ef76251778161d27bc07db214b8c81720e476Paul Soulos
9926bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private void populateContactAndAboutCard(Cp2DataCardModel cp2DataCardModel) {
9936bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        mCachedCp2DataCardModel = cp2DataCardModel;
9946bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        if (mHasIntentLaunched || cp2DataCardModel == null) {
995a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            return;
996a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        }
997eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("bind contact card");
998eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
9996bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> contactCardEntries = cp2DataCardModel.contactCardEntries;
10006bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> aboutCardEntries = cp2DataCardModel.aboutCardEntries;
10016bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final String customAboutCardName = cp2DataCardModel.customAboutCardName;
1002eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1003eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (contactCardEntries.size() > 0) {
1004eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            mContactCard.initialize(contactCardEntries,
1005eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    /* numInitialVisibleEntries = */ MIN_NUM_CONTACT_ENTRIES_SHOWN,
1006c8e2a91807b581194566eb45019fa16e2268b462Paul Soulos                    /* isExpanded = */ mContactCard.isExpanded(),
100789966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos                    /* isAlwaysExpanded = */ false,
10080cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                    mExpandingEntryCardViewListener,
10090cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                    mScroller);
1010eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            mContactCard.setVisibility(View.VISIBLE);
1011eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else {
1012eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            mContactCard.setVisibility(View.GONE);
1013eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1014eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
10158a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1016eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("bind about card");
1017c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        // Phonetic name is not a data item, so the entry needs to be created separately
1018c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        final String phoneticName = mContactData.getPhoneticName();
1019c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        if (!TextUtils.isEmpty(phoneticName)) {
1020c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos            Entry phoneticEntry = new Entry(/* viewId = */ -1,
1021c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* icon = */ null,
1022c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    getResources().getString(R.string.name_phonetic),
1023c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    phoneticName,
1024c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* text = */ null,
102523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    /* primaryContentDescription = */ null,
1026c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* intent = */ null,
1027c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* alternateIcon = */ null,
1028c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* alternateIntent = */ null,
1029c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* alternateContentDescription = */ null,
1030c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* shouldApplyColor = */ false,
10312a4207fb39330e840436215c896cde911489e111Paul Soulos                    /* isEditable = */ false,
10322a4207fb39330e840436215c896cde911489e111Paul Soulos                    /* EntryContextMenuInfo = */ new EntryContextMenuInfo(phoneticName,
103397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                            getResources().getString(R.string.name_phonetic),
103497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                            /* mimeType = */ null, /* id = */ -1, /* isPrimary = */ false),
103548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIcon = */ null,
103648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIntent = */ null,
103748290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    /* thirdContentDescription = */ null,
103848290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    /* iconResourceId = */ 0);
1039c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos            List<Entry> phoneticList = new ArrayList<>();
1040c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos            phoneticList.add(phoneticEntry);
1041a153dba33c2152332c5706178a367f52b0550723Paul Soulos            // Phonetic name comes after nickname. Check to see if the first entry type is nickname
1042a0fa4c18dc111ceea9ff47f35ee01fecc1003578Paul Soulos            if (aboutCardEntries.size() > 0 && aboutCardEntries.get(0).get(0).getHeader().equals(
1043a153dba33c2152332c5706178a367f52b0550723Paul Soulos                    getResources().getString(R.string.header_nickname_entry))) {
1044a153dba33c2152332c5706178a367f52b0550723Paul Soulos                aboutCardEntries.add(1, phoneticList);
1045a153dba33c2152332c5706178a367f52b0550723Paul Soulos            } else {
1046a153dba33c2152332c5706178a367f52b0550723Paul Soulos                aboutCardEntries.add(0, phoneticList);
1047a153dba33c2152332c5706178a367f52b0550723Paul Soulos            }
1048c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        }
1049c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos
10506bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        if (!TextUtils.isEmpty(customAboutCardName)) {
10516bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            mAboutCard.setTitle(customAboutCardName);
10526bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        }
10536bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
1054cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos        if (aboutCardEntries.size() > 0) {
1055cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos            mAboutCard.initialize(aboutCardEntries,
1056cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    /* numInitialVisibleEntries = */ 1,
1057cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    /* isExpanded = */ true,
1058cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    /* isAlwaysExpanded = */ true,
1059cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    mExpandingEntryCardViewListener,
1060cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    mScroller);
1061cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos        }
10626095369885edcca566a812b551886e29c7ff8039Brian Attwell
10636095369885edcca566a812b551886e29c7ff8039Brian Attwell        if (contactCardEntries.size() == 0 && aboutCardEntries.size() == 0) {
10646095369885edcca566a812b551886e29c7ff8039Brian Attwell            initializeNoContactDetailCard();
10656095369885edcca566a812b551886e29c7ff8039Brian Attwell        } else {
10666095369885edcca566a812b551886e29c7ff8039Brian Attwell            mNoContactDetailsCard.setVisibility(View.GONE);
10676095369885edcca566a812b551886e29c7ff8039Brian Attwell        }
10686095369885edcca566a812b551886e29c7ff8039Brian Attwell
1069a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        // If the Recent card is already initialized (all recent data is loaded), show the About
1070a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        // card if it has entries. Otherwise About card visibility will be set in bindRecentData()
1071a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        if (isAllRecentDataLoaded() && aboutCardEntries.size() > 0) {
1072a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos            mAboutCard.setVisibility(View.VISIBLE);
1073a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        }
1074eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
1075eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
1076eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1077eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    /**
10786095369885edcca566a812b551886e29c7ff8039Brian Attwell     * Create a card that shows "Add email" and "Add phone number" entries in grey.
10796095369885edcca566a812b551886e29c7ff8039Brian Attwell     */
10806095369885edcca566a812b551886e29c7ff8039Brian Attwell    private void initializeNoContactDetailCard() {
10816095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Drawable phoneIcon = getResources().getDrawable(
10826095369885edcca566a812b551886e29c7ff8039Brian Attwell                R.drawable.ic_phone_24dp).mutate();
10836095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Entry phonePromptEntry = new Entry(CARD_ENTRY_ID_EDIT_CONTACT,
10846095369885edcca566a812b551886e29c7ff8039Brian Attwell                phoneIcon, getString(R.string.quickcontact_add_phone_number),
108523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                /* subHeader = */ null, /* text = */ null, /* primaryContentDescription = */ null,
108623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                getEditContactIntent(),
1087dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                /* alternateIcon = */ null, /* alternateIntent = */ null,
1088714455bba22b99d168a2e864dfbc74a6e30dfdb6Paul Soulos                /* alternateContentDescription = */ null, /* shouldApplyColor = */ true,
108948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                /* isEditable = */ false, /* EntryContextMenuInfo = */ null,
109048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                /* thirdIcon = */ null, /* thirdIntent = */ null,
109148290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                /* thirdContentDescription = */ null, R.drawable.ic_phone_24dp);
10926095369885edcca566a812b551886e29c7ff8039Brian Attwell
10936095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Drawable emailIcon = getResources().getDrawable(
10946095369885edcca566a812b551886e29c7ff8039Brian Attwell                R.drawable.ic_email_24dp).mutate();
10956095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Entry emailPromptEntry = new Entry(CARD_ENTRY_ID_EDIT_CONTACT,
10966095369885edcca566a812b551886e29c7ff8039Brian Attwell                emailIcon, getString(R.string.quickcontact_add_email), /* subHeader = */ null,
109723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                /* text = */ null, /* primaryContentDescription = */ null,
109823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                getEditContactIntent(), /* alternateIcon = */ null,
1099dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                /* alternateIntent = */ null, /* alternateContentDescription = */ null,
11002a4207fb39330e840436215c896cde911489e111Paul Soulos                /* shouldApplyColor = */ true, /* isEditable = */ false,
110148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                /* EntryContextMenuInfo = */ null, /* thirdIcon = */ null,
110248290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                /* thirdIntent = */ null, /* thirdContentDescription = */ null,
110348290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                R.drawable.ic_email_24dp);
11046095369885edcca566a812b551886e29c7ff8039Brian Attwell
11056095369885edcca566a812b551886e29c7ff8039Brian Attwell        final List<List<Entry>> promptEntries = new ArrayList<>();
11066095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.add(new ArrayList<Entry>(1));
11076095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.add(new ArrayList<Entry>(1));
11086095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.get(0).add(phonePromptEntry);
11096095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.get(1).add(emailPromptEntry);
11106095369885edcca566a812b551886e29c7ff8039Brian Attwell
11116095369885edcca566a812b551886e29c7ff8039Brian Attwell        final int subHeaderTextColor = getResources().getColor(
11126095369885edcca566a812b551886e29c7ff8039Brian Attwell                R.color.quickcontact_entry_sub_header_text_color);
11136095369885edcca566a812b551886e29c7ff8039Brian Attwell        final PorterDuffColorFilter greyColorFilter =
11146095369885edcca566a812b551886e29c7ff8039Brian Attwell                new PorterDuffColorFilter(subHeaderTextColor, PorterDuff.Mode.SRC_ATOP);
1115c8e2a91807b581194566eb45019fa16e2268b462Paul Soulos        mNoContactDetailsCard.initialize(promptEntries, 2, /* isExpanded = */ true,
11160cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                /* isAlwaysExpanded = */ true, mExpandingEntryCardViewListener, mScroller);
11176095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setVisibility(View.VISIBLE);
11186095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setEntryHeaderColor(subHeaderTextColor);
11196095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setColorAndFilter(subHeaderTextColor, greyColorFilter);
11206095369885edcca566a812b551886e29c7ff8039Brian Attwell    }
11216095369885edcca566a812b551886e29c7ff8039Brian Attwell
11226095369885edcca566a812b551886e29c7ff8039Brian Attwell    /**
1123eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * Builds the {@link DataItem}s Map out of the Contact.
1124eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @param data The contact to build the data from.
1125eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @return A pair containing a list of data items sorted within mimetype and sorted
1126eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     *  amongst mimetype. The map goes from mimetype string to the sorted list of data items within
1127eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     *  mimetype
1128eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     */
11296bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private Cp2DataCardModel generateDataModelFromContact(
1130eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            Contact data) {
1131eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("Build data items map");
1132eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1133eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final Map<String, List<DataItem>> dataItemsMap = new HashMap<>();
11348bf96e78497ea9c8c893bcb357fc1e3175fb2e9bBrian Attwell
11358a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final ResolveCache cache = ResolveCache.getInstance(this);
1136851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        for (RawContact rawContact : data.getRawContacts()) {
1137851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            for (DataItem dataItem : rawContact.getDataItems()) {
1138eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                dataItem.setRawContactId(rawContact.getId());
1139eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1140851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final String mimeType = dataItem.getMimeType();
1141eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (mimeType == null) continue;
1142eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
114347b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                final AccountType accountType = rawContact.getAccountType(this);
114447b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                final DataKind dataKind = AccountTypeManager.getInstance(this)
114547b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                        .getKindOrFallback(accountType, mimeType);
1146eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (dataKind == null) continue;
1147cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1148eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                dataItem.setDataKind(dataKind);
1149b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1150eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final boolean hasData = !TextUtils.isEmpty(dataItem.buildDataString(this,
1151eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        dataKind));
1152899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos
1153eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (isMimeExcluded(mimeType) || !hasData) continue;
1154edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1155eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                List<DataItem> dataItemListByType = dataItemsMap.get(mimeType);
1156eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (dataItemListByType == null) {
1157eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    dataItemListByType = new ArrayList<>();
1158eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    dataItemsMap.put(mimeType, dataItemListByType);
1159edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                }
1160eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                dataItemListByType.add(dataItem);
1161edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
1162edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
11638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
1164edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1165eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("sort within mimetypes");
116616339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos        /*
116716339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos         * Sorting is a multi part step. The end result is to a have a sorted list of the most
1168eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos         * used data items, one per mimetype. Then, within each mimetype, the list of data items
1169eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos         * for that type is also sorted, based off of {super primary, primary, times used} in that
1170eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos         * order.
117116339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos         */
1172eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<List<DataItem>> dataItemsList = new ArrayList<>();
1173eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        for (List<DataItem> mimeTypeDataItems : dataItemsMap.values()) {
1174eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Remove duplicate data items
1175eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            Collapser.collapseList(mimeTypeDataItems, this);
1176eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Sort within mimetype
1177eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            Collections.sort(mimeTypeDataItems, mWithinMimeTypeDataItemComparator);
1178eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Add to the list of data item lists
1179eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            dataItemsList.add(mimeTypeDataItems);
1180edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
1181eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
1182edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1183eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("sort amongst mimetypes");
1184eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        // Sort amongst mimetypes to bubble up the top data items for the contact card
1185eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Collections.sort(dataItemsList, mAmongstMimeTypeDataItemComparator);
1186eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
118716339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos
11886bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        Trace.beginSection("cp2 data items to entries");
11896bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
11906bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> contactCardEntries = new ArrayList<>();
11916bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> aboutCardEntries = buildAboutCardEntries(dataItemsMap);
11926bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final MutableString aboutCardName = new MutableString();
11936bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
11946bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        for (int i = 0; i < dataItemsList.size(); ++i) {
11956bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final List<DataItem> dataItemsByMimeType = dataItemsList.get(i);
11966bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final DataItem topDataItem = dataItemsByMimeType.get(0);
11976bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            if (SORTED_ABOUT_CARD_MIMETYPES.contains(topDataItem.getMimeType())) {
11986bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                // About card mimetypes are built in buildAboutCardEntries, skip here
11996bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                continue;
12006bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            } else {
12016bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                List<Entry> contactEntries = dataItemsToEntries(dataItemsList.get(i),
12026bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        aboutCardName);
12036bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                if (contactEntries.size() > 0) {
12046bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                    contactCardEntries.add(contactEntries);
12056bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                }
12066bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            }
12076bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        }
12086bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12096bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        Trace.endSection();
12106bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12116bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final Cp2DataCardModel dataModel = new Cp2DataCardModel();
12126bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.customAboutCardName = aboutCardName.value;
12136bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.aboutCardEntries = aboutCardEntries;
12146bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.contactCardEntries = contactCardEntries;
12156bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.dataItemsMap = dataItemsMap;
12166bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        return dataModel;
12176bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    }
12186bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12196bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    /**
12206bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * Class used to hold the About card and Contact cards' data model that gets generated
12216bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * on a background thread. All data is from CP2.
12226bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     */
12236bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private static class Cp2DataCardModel {
12246bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        /**
12256bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell         * A map between a mimetype string and the corresponding list of data items. The data items
12266bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell         * are in sorted order using mWithinMimeTypeDataItemComparator.
12276bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell         */
12286bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public Map<String, List<DataItem>> dataItemsMap;
12296bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public List<List<Entry>> aboutCardEntries;
12306bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public List<List<Entry>> contactCardEntries;
12316bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public String customAboutCardName;
12326bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    }
12336bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12346bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private static class MutableString {
12356bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public String value;
1236eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
1237edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1238eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    /**
1239eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * Converts a {@link DataItem} into an {@link ExpandingEntryCardView.Entry} for display.
1240eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * If the {@link ExpandingEntryCardView.Entry} has no visual elements, null is returned.
12416bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     *
12426bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * This runs on a background thread. This is set as static to avoid accidentally adding
12436bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * additional dependencies on unsafe things (like the Activity).
12446bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     *
1245eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @param dataItem The {@link DataItem} to convert.
12466a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * @param secondDataItem A second {@link DataItem} to help build a full entry for some
12476a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     *  mimetypes
1248eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @return The {@link ExpandingEntryCardView.Entry}, or null if no visual elements are present.
1249eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     */
12506a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static Entry dataItemToEntry(DataItem dataItem, DataItem secondDataItem,
12516bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            Context context, Contact contactData,
12526bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final MutableString aboutCardName) {
1253eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Drawable icon = null;
1254eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String header = null;
1255eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String subHeader = null;
1256eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Drawable subHeaderIcon = null;
1257eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String text = null;
1258eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Drawable textIcon = null;
125923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        StringBuilder primaryContentDescription = new StringBuilder();
1260eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Intent intent = null;
126148ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos        boolean shouldApplyColor = true;
1262dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        Drawable alternateIcon = null;
1263dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        Intent alternateIntent = null;
126423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        StringBuilder alternateContentDescription = new StringBuilder();
1265eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final boolean isEditable = false;
12662a4207fb39330e840436215c896cde911489e111Paul Soulos        EntryContextMenuInfo entryContextMenuInfo = null;
126748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        Drawable thirdIcon = null;
126848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        Intent thirdIntent = null;
126948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        String thirdContentDescription = null;
127048290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos        int iconResourceId = 0;
1271eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
12726bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        context = context.getApplicationContext();
127323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        final Resources res = context.getResources();
1274eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        DataKind kind = dataItem.getDataKind();
1275eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1276eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (dataItem instanceof ImDataItem) {
1277eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final ImDataItem im = (ImDataItem) dataItem;
12786bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            intent = ContactsUtils.buildImIntent(context, im).first;
1279eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final boolean isEmail = im.isCreatedFromEmail();
12807de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            final int protocol;
12817de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            if (!im.isProtocolValid()) {
12827de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                protocol = Im.PROTOCOL_CUSTOM;
12837de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            } else {
12847de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : im.getProtocol();
12857de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            }
12867de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            if (protocol == Im.PROTOCOL_CUSTOM) {
12877de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                // If the protocol is custom, display the "IM" entry header as well to distinguish
12887de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                // this entry from other ones
128923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                header = res.getString(R.string.header_im_entry);
129023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                subHeader = Im.getProtocolLabel(res, protocol,
12917de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                        im.getCustomProtocol()).toString();
12927de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                text = im.getData();
12937de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            } else {
129423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                header = Im.getProtocolLabel(res, protocol,
12957de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                        im.getCustomProtocol()).toString();
12967de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                subHeader = im.getData();
12977de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            }
129897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(im.getData(), header,
129997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1300eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof OrganizationDataItem) {
1301eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final OrganizationDataItem organization = (OrganizationDataItem) dataItem;
130223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_organization_entry);
1303eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = organization.getCompany();
130497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
130597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1306eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            text = organization.getTitle();
1307eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof NicknameDataItem) {
1308eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final NicknameDataItem nickname = (NicknameDataItem) dataItem;
1309eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Build nickname entries
1310eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final boolean isNameRawContact =
13116bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                (contactData.getNameRawContactId() == dataItem.getRawContactId());
1312eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1313eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final boolean duplicatesTitle =
1314eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                isNameRawContact
13156bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                && contactData.getDisplayNameSource() == DisplayNameSources.NICKNAME;
1316eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1317eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!duplicatesTitle) {
131823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                header = res.getString(R.string.header_nickname_entry);
1319eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                subHeader = nickname.getName();
132097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
132197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1322eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1323eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof NoteDataItem) {
1324eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final NoteDataItem note = (NoteDataItem) dataItem;
132523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_note_entry);
1326eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = note.getNote();
132797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
132897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1329eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof WebsiteDataItem) {
1330eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final WebsiteDataItem website = (WebsiteDataItem) dataItem;
133123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_website_entry);
1332eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = website.getUrl();
133397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
133497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1335eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            try {
13366bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                final WebAddress webAddress = new WebAddress(website.buildDataString(context,
13376bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        kind));
1338eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_VIEW, Uri.parse(webAddress.toString()));
1339eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } catch (final ParseException e) {
13406bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                Log.e(TAG, "Couldn't parse website: " + website.buildDataString(context, kind));
1341eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1342eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof EventDataItem) {
1343eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final EventDataItem event = (EventDataItem) dataItem;
13446bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final String dataString = event.buildDataString(context, kind);
1345eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final Calendar cal = DateUtils.parseDate(dataString, false);
1346eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (cal != null) {
1347eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final Date nextAnniversary =
1348eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        DateUtils.getNextAnnualDate(cal);
1349eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
1350eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                builder.appendPath("time");
1351eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                ContentUris.appendId(builder, nextAnniversary.getTime());
1352eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_VIEW).setData(builder.build());
1353eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
135423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_event_entry);
1355f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            if (event.hasKindTypeColumn(kind)) {
135623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                subHeader = Event.getTypeLabel(res, event.getKindTypeColumn(kind),
13577de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                        event.getLabel()).toString();
1358f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            }
13596bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            text = DateUtils.formatDate(context, dataString);
136097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(text, header,
136197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1362eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof RelationDataItem) {
1363eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final RelationDataItem relation = (RelationDataItem) dataItem;
13646bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final String dataString = relation.buildDataString(context, kind);
1365eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(dataString)) {
1366eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_SEARCH);
1367eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent.putExtra(SearchManager.QUERY, dataString);
1368eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent.setType(Contacts.CONTENT_TYPE);
1369eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
137023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_relation_entry);
1371eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = relation.getName();
137297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
137397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1374f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            if (relation.hasKindTypeColumn(kind)) {
137523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                text = Relation.getTypeLabel(res,
13766bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        relation.getKindTypeColumn(kind),
1377f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                        relation.getLabel()).toString();
1378f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            }
1379eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof PhoneDataItem) {
1380eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final PhoneDataItem phone = (PhoneDataItem) dataItem;
1381eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(phone.getNumber())) {
138223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(res.getString(R.string.call_other)).append(" ");
1383c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell                header = sBidiFormatter.unicodeWrap(phone.buildDataString(context, kind),
1384c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell                        TextDirectionHeuristics.LTR);
13852a4207fb39330e840436215c896cde911489e111Paul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(header,
138697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        res.getString(R.string.phoneLabelsGroup), dataItem.getMimeType(),
138797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getId(), dataItem.isSuperPrimary());
1388f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                if (phone.hasKindTypeColumn(kind)) {
138923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    text = Phone.getTypeLabel(res, phone.getKindTypeColumn(kind),
1390f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                            phone.getLabel()).toString();
139123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(text).append(" ");
1392f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                }
139323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(header);
139423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                icon = res.getDrawable(R.drawable.ic_phone_24dp);
139548290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId = R.drawable.ic_phone_24dp;
13966bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                if (PhoneCapabilityTester.isPhone(context)) {
1397eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    intent = CallUtil.getCallIntent(phone.getNumber());
139816339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos                }
1399dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                alternateIntent = new Intent(Intent.ACTION_SENDTO,
14001cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                        Uri.fromParts(ContactsUtils.SCHEME_SMSTO, phone.getNumber(), null));
140148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
140223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateIcon = res.getDrawable(R.drawable.ic_message_24dp);
140323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.append(res.getString(R.string.sms_custom, header));
140448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
140548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                // Add video call button if supported
1406f764730a34da560db87206f9a48390d4c8085365Paul Soulos                if (CallUtil.isVideoEnabled(context)) {
140723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    thirdIcon = res.getDrawable(R.drawable.ic_videocam);
140848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    thirdIntent = CallUtil.getVideoCallIntent(phone.getNumber(),
140948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                            CALL_ORIGIN_QUICK_CONTACTS_ACTIVITY);
141048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    thirdContentDescription =
141123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                            res.getString(R.string.description_video_call);
141248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                }
1413eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1414eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof EmailDataItem) {
1415eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final EmailDataItem email = (EmailDataItem) dataItem;
1416eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String address = email.getData();
1417eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(address)) {
141823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(res.getString(R.string.email_other)).append(" ");
14191cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                final Uri mailUri = Uri.fromParts(ContactsUtils.SCHEME_MAILTO, address, null);
1420eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_SENDTO, mailUri);
1421eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                header = email.getAddress();
14222a4207fb39330e840436215c896cde911489e111Paul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(header,
142397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        res.getString(R.string.emailLabelsGroup), dataItem.getMimeType(),
142497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getId(), dataItem.isSuperPrimary());
1425f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                if (email.hasKindTypeColumn(kind)) {
142623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    text = Email.getTypeLabel(res, email.getKindTypeColumn(kind),
1427f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                            email.getLabel()).toString();
142823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(text).append(" ");
1429f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                }
143023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(header);
143123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                icon = res.getDrawable(R.drawable.ic_email_24dp);
143248290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId = R.drawable.ic_email_24dp;
1433eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1434eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof StructuredPostalDataItem) {
1435eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            StructuredPostalDataItem postal = (StructuredPostalDataItem) dataItem;
1436eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String postalAddress = postal.getFormattedAddress();
1437eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(postalAddress)) {
143823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(res.getString(R.string.map_other)).append(" ");
1439eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = StructuredPostalUtils.getViewPostalAddressIntent(postalAddress);
1440eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                header = postal.getFormattedAddress();
14412a4207fb39330e840436215c896cde911489e111Paul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(header,
144297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        res.getString(R.string.postalLabelsGroup), dataItem.getMimeType(),
144397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getId(), dataItem.isSuperPrimary());
1444f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                if (postal.hasKindTypeColumn(kind)) {
144523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    text = StructuredPostal.getTypeLabel(res,
1446f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                            postal.getKindTypeColumn(kind), postal.getLabel()).toString();
144723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(text).append(" ");
1448f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                }
144923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(header);
14506a4d2736d772cc5cbb79d04e115f2d6117826860Paul Soulos                alternateIntent =
14516a4d2736d772cc5cbb79d04e115f2d6117826860Paul Soulos                        StructuredPostalUtils.getViewPostalAddressDirectionsIntent(postalAddress);
145223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateIcon = res.getDrawable(R.drawable.ic_directions_24dp);
145323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.append(res.getString(
145423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                        R.string.content_description_directions)).append(" ").append(header);
145523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                icon = res.getDrawable(R.drawable.ic_place_24dp);
145648290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId = R.drawable.ic_place_24dp;
1457eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1458eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof SipAddressDataItem) {
14596bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            if (PhoneCapabilityTester.isSipPhone(context)) {
1460eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final SipAddressDataItem sip = (SipAddressDataItem) dataItem;
1461eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final String address = sip.getSipAddress();
1462eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (!TextUtils.isEmpty(address)) {
146323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(res.getString(R.string.call_other)).append(
146423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                            " ");
14651cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                    final Uri callUri = Uri.fromParts(PhoneAccount.SCHEME_SIP, address, null);
1466eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    intent = CallUtil.getCallIntent(callUri);
14671cda01b35a37f79b22e907cc970314b8c0a9e00cPaul Soulos                    header = address;
14682a4207fb39330e840436215c896cde911489e111Paul Soulos                    entryContextMenuInfo = new EntryContextMenuInfo(header,
146997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                            res.getString(R.string.phoneLabelsGroup), dataItem.getMimeType(),
147097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                            dataItem.getId(), dataItem.isSuperPrimary());
14711cda01b35a37f79b22e907cc970314b8c0a9e00cPaul Soulos                    if (sip.hasKindTypeColumn(kind)) {
147223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                        text = SipAddress.getTypeLabel(res,
14736bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                                sip.getKindTypeColumn(kind), sip.getLabel()).toString();
147423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                        primaryContentDescription.append(text).append(" ");
14751cda01b35a37f79b22e907cc970314b8c0a9e00cPaul Soulos                    }
147623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(header);
147723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    icon = res.getDrawable(R.drawable.ic_dialer_sip_black_24dp);
147848290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    iconResourceId = R.drawable.ic_dialer_sip_black_24dp;
147916339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos                }
1480edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
1481eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof StructuredNameDataItem) {
1482eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String givenName = ((StructuredNameDataItem) dataItem).getGivenName();
1483eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(givenName)) {
148423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                aboutCardName.value = res.getString(R.string.about_card_title) +
14856bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        " " + givenName;
1486eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else {
148723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                aboutCardName.value = res.getString(R.string.about_card_title);
1488eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1489eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else {
1490eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Custom DataItem
14916bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            header = dataItem.buildDataStringForDisplay(context, kind);
1492eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            text = kind.typeColumn;
1493eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            intent = new Intent(Intent.ACTION_VIEW);
149460e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            final Uri uri = ContentUris.withAppendedId(Data.CONTENT_URI, dataItem.getId());
149560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            intent.setDataAndType(uri, dataItem.getMimeType());
1496e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos
1497e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            if (intent != null) {
1498e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                final String mimetype = intent.getType();
1499e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos
15006a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                // Build advanced entry for known 3p types. Otherwise default to ResolveCache icon.
1501e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                switch (mimetype) {
1502e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                    case MIMETYPE_GPLUS_PROFILE:
15036a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // If a secondDataItem is available, use it to build an entry with
15046a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // alternate actions
15056a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        if (secondDataItem != null) {
150623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                            icon = res.getDrawable(R.drawable.ic_google_plus_24dp);
15076a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            alternateIcon = res.getDrawable(R.drawable.ic_add_to_circles_black_24);
15086a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            final GPlusOrHangoutsDataItemModel itemModel =
15096a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                    new GPlusOrHangoutsDataItemModel(intent, alternateIntent,
15106a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            dataItem, secondDataItem, alternateContentDescription,
15116a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            header, text, context);
15126a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
151397b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            populateGPlusOrHangoutsDataItemModel(itemModel);
151497b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            intent = itemModel.intent;
151597b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateIntent = itemModel.alternateIntent;
151697b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateContentDescription = itemModel.alternateContentDescription;
151797b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            header = itemModel.header;
151897b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            text = itemModel.text;
15196a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        } else {
15206a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            if (GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE.equals(
15216a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                    intent.getDataString())) {
15226a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_add_to_circles_black_24);
15236a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            } else {
15246a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_google_plus_24dp);
15256a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            }
1526e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        }
1527e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        break;
1528e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                    case MIMETYPE_HANGOUTS:
15296a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // If a secondDataItem is available, use it to build an entry with
15306a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // alternate actions
15316a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        if (secondDataItem != null) {
153223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                            icon = res.getDrawable(R.drawable.ic_hangout_24dp);
15336a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            alternateIcon = res.getDrawable(R.drawable.ic_hangout_video_24dp);
153497b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            final GPlusOrHangoutsDataItemModel itemModel =
15356a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                    new GPlusOrHangoutsDataItemModel(intent, alternateIntent,
15366a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            dataItem, secondDataItem, alternateContentDescription,
15376a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            header, text, context);
15386a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
153997b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            populateGPlusOrHangoutsDataItemModel(itemModel);
154097b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            intent = itemModel.intent;
154197b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateIntent = itemModel.alternateIntent;
154297b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateContentDescription = itemModel.alternateContentDescription;
154397b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            header = itemModel.header;
154497b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            text = itemModel.text;
15456a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        } else {
15466a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            if (HANGOUTS_DATA_5_VIDEO.equals(intent.getDataString())) {
15476a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_hangout_video_24dp);
15486a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            } else {
15496a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_hangout_24dp);
15506a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            }
1551e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        }
1552e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        break;
1553e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                    default:
155497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        entryContextMenuInfo = new EntryContextMenuInfo(header, mimetype,
155597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                                dataItem.getMimeType(), dataItem.getId(),
155697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                                dataItem.isSuperPrimary());
15576bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        icon = ResolveCache.getInstance(context).getIcon(
1558e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                                dataItem.getMimeType(), intent);
1559e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        // Call mutate to create a new Drawable.ConstantState for color filtering
1560e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        if (icon != null) {
1561e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                            icon.mutate();
1562e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        }
156348ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                        shouldApplyColor = false;
1564e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                }
1565e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            }
1566eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1567b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1568eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (intent != null) {
1569eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Do not set the intent is there are no resolves
15706bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            if (!PhoneCapabilityTester.isIntentRegistered(context, intent)) {
1571eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = null;
1572eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1573eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1574eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1575dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        if (alternateIntent != null) {
1576dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            // Do not set the alternate intent is there are no resolves
15776bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            if (!PhoneCapabilityTester.isIntentRegistered(context, alternateIntent)) {
1578dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                alternateIntent = null;
1579f0d04c11b649e953177e79722d05fa048e53273dJay Shrauner            } else if (TextUtils.isEmpty(alternateContentDescription)) {
1580f0d04c11b649e953177e79722d05fa048e53273dJay Shrauner                // Attempt to use package manager to find a suitable content description if needed
158123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.append(getIntentResolveLabel(alternateIntent, context));
1582dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            }
1583dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
1584dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1585eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        // If the Entry has no visual elements, return null
1586eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (icon == null && TextUtils.isEmpty(header) && TextUtils.isEmpty(subHeader) &&
1587eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                subHeaderIcon == null && TextUtils.isEmpty(text) && textIcon == null) {
1588eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            return null;
1589eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1590eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1591fa238949855fba3b28a57fad3d585b13e80362bbBrian Attwell        // Ignore dataIds from the Me profile.
1592ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos        final int dataId = dataItem.getId() > Integer.MAX_VALUE ?
1593ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                -1 : (int) dataItem.getId();
1594ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
159523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        return new Entry(dataId, icon, header, subHeader, subHeaderIcon, text, textIcon,
159623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.toString(), intent, alternateIcon, alternateIntent,
159723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.toString(), shouldApplyColor, isEditable,
159848290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                entryContextMenuInfo, thirdIcon, thirdIntent, thirdContentDescription,
159948290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId);
1600eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
1601eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
16026bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private List<Entry> dataItemsToEntries(List<DataItem> dataItems,
16036bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            MutableString aboutCardTitleOut) {
16046a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Hangouts and G+ use two data items to create one entry.
16056a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        if (dataItems.get(0).getMimeType().equals(MIMETYPE_GPLUS_PROFILE) ||
16066a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataItems.get(0).getMimeType().equals(MIMETYPE_HANGOUTS)) {
16076a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            return gPlusOrHangoutsDataItemsToEntries(dataItems);
16086a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        } else {
16096a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            final List<Entry> entries = new ArrayList<>();
16106a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            for (DataItem dataItem : dataItems) {
16116a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                final Entry entry = dataItemToEntry(dataItem, /* secondDataItem = */ null,
16126a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        this, mContactData, aboutCardTitleOut);
16136a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                if (entry != null) {
16146a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    entries.add(entry);
16156a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                }
16166a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            }
16176a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            return entries;
16186a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
16196a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    }
16206a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
16216a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    /**
16226a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * G+ and Hangout entries are unique in that a single ExpandingEntryCardView.Entry consists
16236a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * of two data items. This method attempts to build each entry using the two data items if
16246a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * they are available. If there are more or less than two data items, a fall back is used
16256a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * and each data item gets its own entry.
16266a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     */
16276a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private List<Entry> gPlusOrHangoutsDataItemsToEntries(List<DataItem> dataItems) {
1628eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<Entry> entries = new ArrayList<>();
16296a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        final Map<Long, List<DataItem>> buckets = new HashMap<>();
16306a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Put the data items into buckets based on the raw contact id
1631eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        for (DataItem dataItem : dataItems) {
16326a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            List<DataItem> bucket = buckets.get(dataItem.getRawContactId());
16336a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            if (bucket == null) {
16346a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                bucket = new ArrayList<>();
16356a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                buckets.put(dataItem.getRawContactId(), bucket);
16366a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            }
16376a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            bucket.add(dataItem);
16386a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
16396a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
16406a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Use the buckets to build entries. If a bucket contains two data items, build the special
16416a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // entry, otherwise fall back to the normal entry.
16426a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        for (List<DataItem> bucket : buckets.values()) {
16436a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            if (bucket.size() == 2) {
16446a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                // Use the pair to build an entry
16456a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                final Entry entry = dataItemToEntry(bucket.get(0),
16466a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        /* secondDataItem = */ bucket.get(1), this, mContactData,
16476a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        /* aboutCardName = */ null);
16486a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                if (entry != null) {
16496a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    entries.add(entry);
16506a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                }
16516a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            } else {
16526a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                for (DataItem dataItem : bucket) {
16536a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    final Entry entry = dataItemToEntry(dataItem, /* secondDataItem = */ null,
16546a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            this, mContactData, /* aboutCardName = */ null);
16556a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    if (entry != null) {
16566a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        entries.add(entry);
16576a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    }
16586a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                }
1659eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1660eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1661eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        return entries;
1662edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
1663edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
16646a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    /**
16656a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * Used for statically passing around G+ or Hangouts data items and entry fields to
16666a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * populateGPlusOrHangoutsDataItemModel.
16676a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     */
16686a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final class GPlusOrHangoutsDataItemModel {
16696a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public Intent intent;
16706a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public Intent alternateIntent;
16716a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public DataItem dataItem;
16726a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public DataItem secondDataItem;
16736a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public StringBuilder alternateContentDescription;
16746a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public String header;
16756a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public String text;
16766a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public Context context;
16776a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
16786a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public GPlusOrHangoutsDataItemModel(Intent intent, Intent alternateIntent, DataItem dataItem,
16796a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                DataItem secondDataItem, StringBuilder alternateContentDescription, String header,
16806a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                String text, Context context) {
16816a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.intent = intent;
16826a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.alternateIntent = alternateIntent;
16836a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.dataItem = dataItem;
16846a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.secondDataItem = secondDataItem;
16856a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.alternateContentDescription = alternateContentDescription;
16866a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.header = header;
16876a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.text = text;
16886a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.context = context;
16896a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
16906a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    }
16916a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
16926a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static void populateGPlusOrHangoutsDataItemModel(
16936a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            GPlusOrHangoutsDataItemModel dataModel) {
16946a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        final Intent secondIntent = new Intent(Intent.ACTION_VIEW);
16956a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        secondIntent.setDataAndType(ContentUris.withAppendedId(Data.CONTENT_URI,
16966a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataModel.secondDataItem.getId()), dataModel.secondDataItem.getMimeType());
16976a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // There is no guarantee the order the data items come in. Second
16986a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // data item does not necessarily mean it's the alternate.
16996a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Hangouts video and Add to circles should be alternate. Swap if needed
17006a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        if (HANGOUTS_DATA_5_VIDEO.equals(
17016a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataModel.dataItem.getContentValues().getAsString(Data.DATA5)) ||
17026a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE.equals(
17036a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
17046a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateIntent = dataModel.intent;
17056a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateContentDescription = new StringBuilder(dataModel.header);
17066a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
17076a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.intent = secondIntent;
17086a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.header = dataModel.secondDataItem.buildDataStringForDisplay(dataModel.context,
17096a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    dataModel.secondDataItem.getDataKind());
17106a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.text = dataModel.secondDataItem.getDataKind().typeColumn;
17116a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        } else if (HANGOUTS_DATA_5_MESSAGE.equals(
17126a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataModel.dataItem.getContentValues().getAsString(Data.DATA5)) ||
17136a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                GPLUS_PROFILE_DATA_5_VIEW_PROFILE.equals(
17146a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
17156a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateIntent = secondIntent;
17166a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateContentDescription = new StringBuilder(
17176a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    dataModel.secondDataItem.buildDataStringForDisplay(dataModel.context,
17186a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            dataModel.secondDataItem.getDataKind()));
17196a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
17206a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    }
17216a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
17226bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private static String getIntentResolveLabel(Intent intent, Context context) {
17236bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<ResolveInfo> matches = context.getPackageManager().queryIntentActivities(intent,
1724dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                PackageManager.MATCH_DEFAULT_ONLY);
1725dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1726dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        // Pick first match, otherwise best found
1727dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        ResolveInfo bestResolve = null;
1728dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final int size = matches.size();
1729dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        if (size == 1) {
1730dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            bestResolve = matches.get(0);
1731dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        } else if (size > 1) {
17326bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            bestResolve = ResolveCache.getInstance(context).getBestResolve(intent, matches);
1733dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
1734dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1735dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        if (bestResolve == null) {
1736dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            return null;
1737dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
1738dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
17396bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        return String.valueOf(bestResolve.loadLabel(context.getPackageManager()));
1740dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos    }
1741dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1742edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
174331b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     * Asynchronously extract the most vibrant color from the PhotoView. Once extracted,
174431b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     * apply this tint to {@link MultiShrinkScroller}. This operation takes about 20-30ms
174531b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     * on a Nexus 5.
174631b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     */
174731b2d42fb0889e61515d27314aa5a245147100daBrian Attwell    private void extractAndApplyTintFromPhotoViewAsynchronously() {
174831b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        if (mScroller == null) {
174931b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            return;
175031b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        }
175131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        final Drawable imageViewDrawable = mPhotoView.getDrawable();
1752faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        new AsyncTask<Void, Void, MaterialPalette>() {
175331b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            @Override
1754faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell            protected MaterialPalette doInBackground(Void... params) {
1755faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell
175695c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                if (imageViewDrawable instanceof BitmapDrawable
175795c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        && mContactData.getThumbnailPhotoBinaryData() != null
175895c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        && mContactData.getThumbnailPhotoBinaryData().length > 0) {
175995c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    // Perform the color analysis on the thumbnail instead of the full sized
176095c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    // image, so that our results will be as similar as possible to the Bugle
176195c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    // app.
176295c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    final Bitmap bitmap = BitmapFactory.decodeByteArray(
176395c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                            mContactData.getThumbnailPhotoBinaryData(), 0,
176495c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                            mContactData.getThumbnailPhotoBinaryData().length);
176595c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    try {
176695c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        final int primaryColor = colorFromBitmap(bitmap);
176795c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        if (primaryColor != 0) {
176895c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                            return mMaterialColorMapUtils.calculatePrimaryAndSecondaryColor(
176995c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                                    primaryColor);
177095c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        }
177195c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    } finally {
177295c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        bitmap.recycle();
1773faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                    }
17748a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                }
17758a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                if (imageViewDrawable instanceof LetterTileDrawable) {
1776faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                    final int primaryColor = ((LetterTileDrawable) imageViewDrawable).getColor();
1777a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                    return mMaterialColorMapUtils.calculatePrimaryAndSecondaryColor(primaryColor);
177831b2d42fb0889e61515d27314aa5a245147100daBrian Attwell                }
1779a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                return MaterialColorMapUtils.getDefaultPrimaryAndSecondaryColors(getResources());
178031b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            }
178131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell
178231b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            @Override
1783faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell            protected void onPostExecute(MaterialPalette palette) {
1784faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                super.onPostExecute(palette);
17858571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                if (mHasComputedThemeColor) {
17868571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // If we had previously computed a theme color from the contact photo,
17878571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // then do not update the theme color. Changing the theme color several
17888571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // seconds after QC has started, as a result of an updated/upgraded photo,
17898571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // is a jarring experience. On the other hand, changing the theme color after
17908571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // a rotation or onNewIntent() is perfectly fine.
17918571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    return;
17928571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                }
17938571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                // Check that the Photo has not changed. If it has changed, the new tint
17948571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                // color needs to be extracted
17958571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                if (imageViewDrawable == mPhotoView.getDrawable()) {
17968571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    mHasComputedThemeColor = true;
1797faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                    setThemeColor(palette);
179831b2d42fb0889e61515d27314aa5a245147100daBrian Attwell                }
179931b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            }
180031b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        }.execute();
180131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell    }
180231b2d42fb0889e61515d27314aa5a245147100daBrian Attwell
18034936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell    /**
18044936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell     * Examine how many white pixels are in the bitmap in order to determine whether or not
18054936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell     * we need gradient overlays on top of the image.
18064936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell     */
18074936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell    private void analyzeWhitenessOfPhotoAsynchronously() {
18084936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        final Drawable imageViewDrawable = mPhotoView.getDrawable();
18094936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        new AsyncTask<Void, Void, Boolean>() {
18104936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            @Override
18114936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            protected Boolean doInBackground(Void... params) {
18124936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                if (imageViewDrawable instanceof BitmapDrawable) {
18134936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                    final Bitmap bitmap = ((BitmapDrawable) imageViewDrawable).getBitmap();
18144936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                    return WhitenessUtils.isBitmapWhiteAtTopOrBottom(bitmap);
18154936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                }
18164936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                return !(imageViewDrawable instanceof LetterTileDrawable);
18174936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            }
18184936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell
18194936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            @Override
18204936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            protected void onPostExecute(Boolean isWhite) {
18214936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                super.onPostExecute(isWhite);
18224936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                mScroller.setUseGradient(isWhite);
18234936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            }
18244936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        }.execute();
18254936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell    }
18264936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell
1827faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell    private void setThemeColor(MaterialPalette palette) {
18289b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        // If the color is invalid, use the predefined default
1829faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        final int primaryColor = palette.mPrimaryColor;
1830faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mScroller.setHeaderTintColor(primaryColor);
1831faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mStatusBarColor = palette.mSecondaryColor;
18329b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        updateStatusBarColor();
18338571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell
18349b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        mColorFilter =
1835faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                new PorterDuffColorFilter(primaryColor, PorterDuff.Mode.SRC_ATOP);
1836faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mContactCard.setColorAndFilter(primaryColor, mColorFilter);
1837faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mRecentCard.setColorAndFilter(primaryColor, mColorFilter);
1838faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mAboutCard.setColorAndFilter(primaryColor, mColorFilter);
18399b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    }
18409b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
18418a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private void updateStatusBarColor() {
18428a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mScroller == null) {
18438a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            return;
18448a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
18458a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final int desiredStatusBarColor;
18468a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // Only use a custom status bar color if QuickContacts touches the top of the viewport.
18478a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mScroller.getScrollNeededToBeFullScreen() <= 0) {
18488a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            desiredStatusBarColor = mStatusBarColor;
18498a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        } else {
18508a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            desiredStatusBarColor = Color.TRANSPARENT;
18518a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
18528a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // Animate to the new color.
1853847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        final ObjectAnimator animation = ObjectAnimator.ofInt(getWindow(), "statusBarColor",
1854847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell                getWindow().getStatusBarColor(), desiredStatusBarColor);
1855847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        animation.setDuration(ANIMATION_STATUS_BAR_COLOR_CHANGE_DURATION);
1856847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        animation.setEvaluator(new ArgbEvaluator());
1857847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        animation.start();
18588a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
18598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
18608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private int colorFromBitmap(Bitmap bitmap) {
18618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // Author of Palette recommends using 24 colors when analyzing profile photos.
18628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final int NUMBER_OF_PALETTE_COLORS = 24;
18638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final Palette palette = Palette.generate(bitmap, NUMBER_OF_PALETTE_COLORS);
1864a0f20f77e1b4f6cde5934d8b3348d93b58fd6362Brian Attwell        if (palette != null && palette.getVibrantSwatch() != null) {
1865a0f20f77e1b4f6cde5934d8b3348d93b58fd6362Brian Attwell            return palette.getVibrantSwatch().getRgb();
18668a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
18678a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        return 0;
18688a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
18698a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1870b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private List<Entry> contactInteractionsToEntries(List<ContactInteraction> interactions) {
1871eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<Entry> entries = new ArrayList<>();
1872b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        for (ContactInteraction interaction : interactions) {
1873ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            entries.add(new Entry(/* id = */ -1,
1874ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                    interaction.getIcon(this),
1875b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getViewHeader(this),
1876b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getViewBody(this),
1877b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getBodyIcon(this),
1878b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getViewFooter(this),
1879b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getFooterIcon(this),
188023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    interaction.getContentDescription(this),
1881b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getIntent(),
1882dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    /* alternateIcon = */ null,
1883dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    /* alternateIntent = */ null,
1884dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    /* alternateContentDescription = */ null,
188548ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                    /* shouldApplyColor = */ true,
18862a4207fb39330e840436215c896cde911489e111Paul Soulos                    /* isEditable = */ false,
188748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* EntryContextMenuInfo = */ null,
188848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIcon = */ null,
188948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIntent = */ null,
189048290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    /* thirdContentDescription = */ null,
189148290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    interaction.getIconResourceId()));
1892b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
1893b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        return entries;
1894b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    }
1895b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1896eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final LoaderCallbacks<Contact> mLoaderContactCallbacks =
1897851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            new LoaderCallbacks<Contact>() {
1898cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
1899851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoaderReset(Loader<Contact> loader) {
1900405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos            mContactData = null;
1901cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
1902cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1903cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
1904851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoadFinished(Loader<Contact> loader, Contact data) {
19058a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            Trace.beginSection("onLoadFinished()");
19068a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1907cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (isFinishing()) {
1908cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                return;
1909cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
1910cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (data.isError()) {
1911cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                // This shouldn't ever happen, so throw an exception. The {@link ContactLoader}
1912cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                // should log the actual exception.
1913cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                throw new IllegalStateException("Failed to load contact", data.getException());
1914cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
1915cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (data.isNotFound()) {
19168a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                if (mHasAlreadyBeenOpened) {
19178a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    finish();
19188a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                } else {
19198a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    Log.i(TAG, "No contact found: " + ((ContactLoader)loader).getLookupUri());
19208a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    Toast.makeText(QuickContactActivity.this, R.string.invalidContactMessage,
19218a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                            Toast.LENGTH_LONG).show();
19228a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                }
1923cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                return;
1924cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
1925cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1926b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            bindContactData(data);
1927cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
19288a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            Trace.endSection();
1929cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
1930cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1931cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
1932851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public Loader<Contact> onCreateLoader(int id, Bundle args) {
1933cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (mLookupUri == null) {
1934cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                Log.wtf(TAG, "Lookup uri wasn't initialized. Loader was started too early");
1935cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
1936d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Load all contact data. We need loadGroupMetaData=true to determine whether the
1937d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // contact is invisible. If it is, we need to display an "Add to Contacts" MenuItem.
1938b2b435a944947fbf1965c3bb7c202a97f0273259Yorke Lee            return new ContactLoader(getApplicationContext(), mLookupUri,
1939d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    true /*loadGroupMetaData*/, false /*loadInvitableAccountTypes*/,
19408571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    true /*postViewNotification*/, true /*computeFormattedPhoneNumber*/);
1941cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
1942cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann    };
1943b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1944b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    @Override
1945b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    public void onBackPressed() {
1946b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        if (mScroller != null) {
19478477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            if (!mIsExitAnimationInProgress) {
19488477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell                mScroller.scrollOffBottom();
19498477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            }
1950b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        } else {
1951b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell            super.onBackPressed();
1952b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        }
1953b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    }
1954b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
19558a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    @Override
19568a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    public void finish() {
19578a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.finish();
19588a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
19598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // override transitions to skip the standard window animations
19608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        overridePendingTransition(0, 0);
19618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
19628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1963eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final LoaderCallbacks<List<ContactInteraction>> mLoaderInteractionsCallbacks =
1964b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            new LoaderCallbacks<List<ContactInteraction>>() {
1965b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1966b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        @Override
1967b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        public Loader<List<ContactInteraction>> onCreateLoader(int id, Bundle args) {
1968b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            Loader<List<ContactInteraction>> loader = null;
1969b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            switch (id) {
1970b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                case LOADER_SMS_ID:
1971b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    loader = new SmsInteractionsLoader(
1972b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                            QuickContactActivity.this,
1973ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            args.getStringArray(KEY_LOADER_EXTRA_PHONES),
1974b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                            MAX_SMS_RETRIEVE);
1975b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    break;
1976899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                case LOADER_CALENDAR_ID:
1977ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    final String[] emailsArray = args.getStringArray(KEY_LOADER_EXTRA_EMAILS);
1978ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    List<String> emailsList = null;
1979ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    if (emailsArray != null) {
1980ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                        emailsList = Arrays.asList(args.getStringArray(KEY_LOADER_EXTRA_EMAILS));
1981ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    }
1982899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                    loader = new CalendarInteractionsLoader(
1983899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            QuickContactActivity.this,
1984ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                            emailsList,
1985899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            MAX_FUTURE_CALENDAR_RETRIEVE,
1986899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            MAX_PAST_CALENDAR_RETRIEVE,
1987899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            FUTURE_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR,
1988899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            PAST_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR);
1989899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                    break;
1990ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                case LOADER_CALL_LOG_ID:
1991ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                    loader = new CallLogInteractionsLoader(
1992ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            QuickContactActivity.this,
1993ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            args.getStringArray(KEY_LOADER_EXTRA_PHONES),
1994ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            MAX_CALL_LOG_RETRIEVE);
1995b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            }
1996b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            return loader;
1997b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
1998b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1999b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        @Override
2000b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        public void onLoadFinished(Loader<List<ContactInteraction>> loader,
2001b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                List<ContactInteraction> data) {
2002b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            mRecentLoaderResults.put(loader.getId(), data);
2003b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2004b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            if (isAllRecentDataLoaded()) {
2005b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                bindRecentData();
2006b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            }
2007b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
2008b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2009b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        @Override
2010b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        public void onLoaderReset(Loader<List<ContactInteraction>> loader) {
2011b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            mRecentLoaderResults.remove(loader.getId());
2012b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
2013b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    };
2014b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2015b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private boolean isAllRecentDataLoaded() {
2016b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        return mRecentLoaderResults.size() == mRecentLoaderIds.length;
2017b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    }
2018b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2019b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private void bindRecentData() {
2020eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<ContactInteraction> allInteractions = new ArrayList<>();
202130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        final List<List<Entry>> interactionsWrapper = new ArrayList<>();
2022b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
202330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        mRecentDataTask = new AsyncTask<Void, Void, Void>() {
2024b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            @Override
202530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            protected Void doInBackground(Void... params) {
202630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.beginSection("sort recent loader results");
202730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
202830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                for (List<ContactInteraction> loaderInteractions : mRecentLoaderResults.values()) {
202930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    allInteractions.addAll(loaderInteractions);
203030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
203130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
203230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // Sort the interactions by most recent
203330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Collections.sort(allInteractions, new Comparator<ContactInteraction>() {
203430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    @Override
203530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    public int compare(ContactInteraction a, ContactInteraction b) {
203630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                        return a.getInteractionDate() >= b.getInteractionDate() ? -1 : 1;
203730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    }
203830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                });
203930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
204030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.endSection();
204130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.beginSection("contactInteractionsToEntries");
204230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
204330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // Wrap each interaction in its own list so that an icon is displayed for each entry
204430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                for (Entry contactInteraction : contactInteractionsToEntries(allInteractions)) {
204530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    List<Entry> entryListWrapper = new ArrayList<>(1);
204630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    entryListWrapper.add(contactInteraction);
204730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    interactionsWrapper.add(entryListWrapper);
204830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
204930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
205030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.endSection();
205130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                return null;
2052b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            }
205330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
205430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            @Override
205530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            protected void onPostExecute(Void aVoid) {
205630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                super.onPostExecute(aVoid);
205730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.beginSection("initialize recents card");
205830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
205930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                if (allInteractions.size() > 0) {
206030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mRecentCard.initialize(interactionsWrapper,
2061b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    /* numInitialVisibleEntries = */ MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN,
2062c8e2a91807b581194566eb45019fa16e2268b462Paul Soulos                    /* isExpanded = */ mRecentCard.isExpanded(), /* isAlwaysExpanded = */ false,
206330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                            mExpandingEntryCardViewListener, mScroller);
206430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mRecentCard.setVisibility(View.VISIBLE);
206530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
2066eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
206730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.endSection();
206830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
206930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // About card is initialized along with the contact card, but since it appears after
207030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // the recent card in the UI, we hold off until making it visible until the recent
207130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // card is also ready to avoid stuttering.
207230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                if (mAboutCard.shouldShow()) {
207330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mAboutCard.setVisibility(View.VISIBLE);
207430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                } else {
207530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mAboutCard.setVisibility(View.GONE);
207630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
207730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                mRecentDataTask = null;
207830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            }
207930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        };
208030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        mRecentDataTask.execute();
2081b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    }
20828a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
20838a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    @Override
20848a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    protected void onStop() {
20858a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.onStop();
20868a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
20878a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mEntriesAndActionsTask != null) {
20888a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // Once the activity is stopped, we will no longer want to bind mEntriesAndActionsTask's
20898a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // results on the UI thread. In some circumstances Activities are killed without
20908a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // onStop() being called. This is not a problem, because in these circumstances
20918a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // the entire process will be killed.
20928a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            mEntriesAndActionsTask.cancel(/* mayInterruptIfRunning = */ false);
20938a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
209430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        if (mRecentDataTask != null) {
209530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            mRecentDataTask.cancel(/* mayInterruptIfRunning = */ false);
209630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        }
20978a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
209823889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos
209923889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos    /**
2100d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     * Returns true if it is possible to edit the current contact.
2101d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     */
2102d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private boolean isContactEditable() {
2103d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        return mContactData != null && !mContactData.isDirectoryEntry();
2104d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2105d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2106a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell    /**
2107a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell     * Returns true if it is possible to share the current contact.
2108a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell     */
2109a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell    private boolean isContactShareable() {
2110a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell        return mContactData != null && !mContactData.isDirectoryEntry();
2111a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell    }
2112a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
21136095369885edcca566a812b551886e29c7ff8039Brian Attwell    private Intent getEditContactIntent() {
211463176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        final Intent intent = new Intent(Intent.ACTION_EDIT, mContactData.getLookupUri());
2115d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
21166095369885edcca566a812b551886e29c7ff8039Brian Attwell        return intent;
21176095369885edcca566a812b551886e29c7ff8039Brian Attwell    }
21186095369885edcca566a812b551886e29c7ff8039Brian Attwell
21196095369885edcca566a812b551886e29c7ff8039Brian Attwell    private void editContact() {
2120a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        mHasIntentLaunched = true;
2121c00a0b5370f0714f6af1ea9b3e29b10f25e91af0Zheng Fu        mContactLoader.cacheResult();
21226095369885edcca566a812b551886e29c7ff8039Brian Attwell        startActivityForResult(getEditContactIntent(), REQUEST_CODE_CONTACT_EDITOR_ACTIVITY);
2123d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2124d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2125d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private void toggleStar(MenuItem starredMenuItem) {
2126d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        // Make sure there is a contact
212763176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        if (mContactData != null) {
2128d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Read the current starred value from the UI instead of using the last
2129d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // loaded state. This allows rapid tapping without writing the same
2130d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // value several times
2131d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final boolean isStarred = starredMenuItem.isChecked();
2132d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2133d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // To improve responsiveness, swap out the picture (and tag) in the UI already
2134333091ae754ddfc25714c14b9b89534be24379f9Paul Soulos            ContactDisplayUtils.configureStarredMenuItem(starredMenuItem,
2135d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    mContactData.isDirectoryEntry(), mContactData.isUserProfile(),
2136d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    !isStarred);
2137d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2138d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Now perform the real save
2139eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final Intent intent = ContactSaveService.createSetStarredIntent(
214063176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell                    QuickContactActivity.this, mContactData.getLookupUri(), !isStarred);
2141d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            startService(intent);
214235ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell
214335ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            final CharSequence accessibilityText = !isStarred
214435ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell                    ? getResources().getText(R.string.description_action_menu_add_star)
214535ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell                    : getResources().getText(R.string.description_action_menu_remove_star);
214635ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            // Accessibility actions need to have an associated view. We can't access the MenuItem's
214735ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            // underlying view, so put this accessibility action on the root view.
214835ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            mScroller.announceForAccessibility(accessibilityText);
2149d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
2150d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2151d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2152752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    /**
2153752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     * Calls into the contacts provider to get a pre-authorized version of the given URI.
2154752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     */
2155752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private Uri getPreAuthorizedUri(Uri uri) {
2156752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Bundle uriBundle = new Bundle();
2157752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        uriBundle.putParcelable(ContactsContract.Authorization.KEY_URI_TO_AUTHORIZE, uri);
2158752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Bundle authResponse = getContentResolver().call(
2159752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                ContactsContract.AUTHORITY_URI,
2160752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                ContactsContract.Authorization.AUTHORIZATION_METHOD,
2161752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                null,
2162752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                uriBundle);
2163752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        if (authResponse != null) {
2164752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            return (Uri) authResponse.getParcelable(
2165752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    ContactsContract.Authorization.KEY_AUTHORIZED_URI);
2166752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        } else {
2167752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            return uri;
2168752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        }
2169752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    }
21702d150da246632b1649999cfabed776133b097775Brian Attwell
2171752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private void shareContact() {
2172752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final String lookupKey = mContactData.getLookupKey();
2173752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        Uri shareUri = Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, lookupKey);
2174752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        if (mContactData.isUserProfile()) {
2175752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            // User is sharing the profile.  We don't want to force the receiver to have
2176752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            // the highly-privileged READ_PROFILE permission, so we need to request a
2177752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            // pre-authorized URI from the provider.
2178752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            shareUri = getPreAuthorizedUri(shareUri);
2179752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        }
2180752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2181752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Intent intent = new Intent(Intent.ACTION_SEND);
2182752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        intent.setType(Contacts.CONTENT_VCARD_TYPE);
2183752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        intent.putExtra(Intent.EXTRA_STREAM, shareUri);
2184752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2185752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        // Launch chooser to share contact via
2186752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final CharSequence chooseTitle = getText(R.string.share_via);
2187752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Intent chooseIntent = Intent.createChooser(intent, chooseTitle);
2188752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2189752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        try {
2190a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            mHasIntentLaunched = true;
2191752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            this.startActivity(chooseIntent);
2192eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } catch (final ActivityNotFoundException ex) {
2193752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            Toast.makeText(this, R.string.share_error, Toast.LENGTH_SHORT).show();
2194752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        }
2195752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    }
2196752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2197752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    /**
2198752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     * Creates a launcher shortcut with the current contact.
2199752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     */
2200752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private void createLauncherShortcutWithContact() {
2201752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final ShortcutIntentBuilder builder = new ShortcutIntentBuilder(this,
2202752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                new OnShortcutIntentCreatedListener() {
2203752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2204752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    @Override
2205752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    public void onShortcutIntentCreated(Uri uri, Intent shortcutIntent) {
2206752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // Broadcast the shortcutIntent to the launcher to create a
2207752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // shortcut to this contact
2208752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        shortcutIntent.setAction(ACTION_INSTALL_SHORTCUT);
2209752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        QuickContactActivity.this.sendBroadcast(shortcutIntent);
2210752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2211752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // Send a toast to give feedback to the user that a shortcut to this
2212752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // contact was added to the launcher.
2213752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        Toast.makeText(QuickContactActivity.this,
2214752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                                R.string.createContactShortcutSuccessful,
2215752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                                Toast.LENGTH_SHORT).show();
2216752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    }
2217752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2218752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                });
221963176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        builder.createContactShortcutIntent(mContactData.getLookupUri());
2220752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    }
2221752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
222266965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell    private boolean isShortcutCreatable() {
222366965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        final Intent createShortcutIntent = new Intent();
222466965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        createShortcutIntent.setAction(ACTION_INSTALL_SHORTCUT);
222566965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        final List<ResolveInfo> receivers = getPackageManager()
222666965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell                .queryBroadcastReceivers(createShortcutIntent, 0);
222766965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        return receivers != null && receivers.size() > 0;
222866965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell    }
222966965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell
2230d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    @Override
2231d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public boolean onCreateOptionsMenu(Menu menu) {
2232eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final MenuInflater inflater = getMenuInflater();
2233d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        inflater.inflate(R.menu.quickcontact, menu);
2234d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        return true;
2235d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2236d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2237d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    @Override
2238d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public boolean onPrepareOptionsMenu(Menu menu) {
2239d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (mContactData != null) {
2240d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final MenuItem starredMenuItem = menu.findItem(R.id.menu_star);
2241333091ae754ddfc25714c14b9b89534be24379f9Paul Soulos            ContactDisplayUtils.configureStarredMenuItem(starredMenuItem,
2242d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    mContactData.isDirectoryEntry(), mContactData.isUserProfile(),
2243d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    mContactData.getStarred());
2244a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
2245d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Configure edit MenuItem
2246d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final MenuItem editMenuItem = menu.findItem(R.id.menu_edit);
2247d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            editMenuItem.setVisible(true);
2248d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            if (DirectoryContactUtil.isDirectoryContact(mContactData) || InvisibleContactUtil
2249d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    .isInvisibleAndAddable(mContactData, this)) {
225030cfd121ad8c8adb83cf417ff1d40a8ba1e3761dBrian Attwell                editMenuItem.setIcon(R.drawable.ic_person_add_tinted_24dp);
22512e4214c79170cdb6c1b8b6ff0408925d3f512becBrian Attwell                editMenuItem.setTitle(R.string.menu_add_contact);
2252d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            } else if (isContactEditable()) {
2253d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                editMenuItem.setIcon(R.drawable.ic_create_24dp);
22542e4214c79170cdb6c1b8b6ff0408925d3f512becBrian Attwell                editMenuItem.setTitle(R.string.menu_editContact);
2255d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            } else {
2256d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                editMenuItem.setVisible(false);
2257d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            }
2258a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
2259a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell            final MenuItem shareMenuItem = menu.findItem(R.id.menu_share);
2260a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell            shareMenuItem.setVisible(isContactShareable());
2261a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
226266965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell            final MenuItem shortcutMenuItem = menu.findItem(R.id.menu_create_contact_shortcut);
226366965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell            shortcutMenuItem.setVisible(isShortcutCreatable());
226466965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell
22658a6d0022b07640d4a1fb8b264c8822bbab2981adPaul Soulos            return true;
2266d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
22678a6d0022b07640d4a1fb8b264c8822bbab2981adPaul Soulos        return false;
2268d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2269d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2270d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    @Override
2271d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public boolean onOptionsItemSelected(MenuItem item) {
2272d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        switch (item.getItemId()) {
2273d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            case R.id.menu_star:
2274d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                toggleStar(item);
2275d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                return true;
2276d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            case R.id.menu_edit:
2277d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                if (DirectoryContactUtil.isDirectoryContact(mContactData)) {
2278ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // This action is used to launch the contact selector, with the option of
2279ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // creating a new contact. Creating a new contact is an INSERT, while selecting
2280ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // an exisiting one is an edit. The fields in the edit screen will be
2281ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // prepopulated with data.
2282ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2283ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
2284ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    intent.setType(Contacts.CONTENT_ITEM_TYPE);
2285ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2286fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    ArrayList<ContentValues> values = mContactData.getContentValues();
2287fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell
2288fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    // Only pre-fill the name field if the provided display name is an nickname
2289fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    // or better (e.g. structured name, nickname)
2290fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    if (mContactData.getDisplayNameSource() >= DisplayNameSources.NICKNAME) {
2291ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        intent.putExtra(Intents.Insert.NAME, mContactData.getDisplayName());
2292fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    } else if (mContactData.getDisplayNameSource()
2293fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                            == DisplayNameSources.ORGANIZATION) {
2294fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        // This is probably an organization. Instead of copying the organization
2295fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        // name into a name entry, copy it into the organization entry. This
2296fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        // way we will still consider the contact an organization.
2297fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        final ContentValues organization = new ContentValues();
2298fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        organization.put(Organization.COMPANY, mContactData.getDisplayName());
2299fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        organization.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
2300fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        values.add(organization);
2301ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    }
2302fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell
2303ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // Last time used and times used are aggregated values from the usage stat
2304ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // table. They need to be removed from data values so the SQL table can insert
2305ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // properly
2306ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    for (ContentValues value : values) {
2307ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        value.remove(Data.LAST_TIME_USED);
2308ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        value.remove(Data.TIMES_USED);
2309ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    }
2310ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    intent.putExtra(Intents.Insert.DATA, values);
2311ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2312ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // If the contact can only export to the same account, add it to the intent.
2313ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // Otherwise the ContactEditorFragment will show a dialog for selecting an
2314ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // account.
2315ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    if (mContactData.getDirectoryExportSupport() ==
2316ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                            Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY) {
2317ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        intent.putExtra(Intents.Insert.ACCOUNT,
2318ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                                new Account(mContactData.getDirectoryAccountName(),
2319ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                                        mContactData.getDirectoryAccountType()));
2320ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        intent.putExtra(Intents.Insert.DATA_SET,
2321ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                                mContactData.getRawContacts().get(0).getDataSet());
2322ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    }
2323ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2324f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                    // Add this flag to disable the delete menu option on directory contact joins
2325f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                    // with local contacts. The delete option is ambiguous when joining contacts.
2326f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                    intent.putExtra(ContactEditorFragment.INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION,
2327f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                            true);
2328f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos
2329ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    startActivityForResult(intent, REQUEST_CODE_CONTACT_SELECTION_ACTIVITY);
2330d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                } else if (InvisibleContactUtil.isInvisibleAndAddable(mContactData, this)) {
2331d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    InvisibleContactUtil.addToDefaultGroup(mContactData, this);
2332d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                } else if (isContactEditable()) {
2333d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    editContact();
2334d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                }
2335d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                return true;
2336752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            case R.id.menu_share:
2337752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                shareContact();
2338752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                return true;
2339752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            case R.id.menu_create_contact_shortcut:
2340752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                createLauncherShortcutWithContact();
2341752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                return true;
2342d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            default:
2343d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                return super.onOptionsItemSelected(item);
2344d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
234523889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos    }
2346edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann}
2347