QuickContactActivity.java revision 8a3fe52802135be2402a5b216325615fb796a509
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;
1800b267fec5cb5b2d836057b16d0085be349be5243Brian Attwell    private static final int SCRIM_COLOR = Color.argb(0xC8, 0, 0, 0);
181ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos    private static final int REQUEST_CODE_CONTACT_SELECTION_ACTIVITY = 2;
182ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos    private static final String MIMETYPE_SMS = "vnd.android-dir/mms-sms";
183dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
184752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    /** This is the Intent action to install a shortcut in the launcher. */
185752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private static final String ACTION_INSTALL_SHORTCUT =
186752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            "com.android.launcher.action.INSTALL_SHORTCUT";
187edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
188edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @SuppressWarnings("deprecation")
189edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final String LEGACY_AUTHORITY = android.provider.Contacts.AUTHORITY;
190edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
191e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos    private static final String MIMETYPE_GPLUS_PROFILE =
192e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            "vnd.android.cursor.item/vnd.googleplus.profile";
1936a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE = "addtocircle";
1946a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String GPLUS_PROFILE_DATA_5_VIEW_PROFILE = "view";
195e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos    private static final String MIMETYPE_HANGOUTS =
196e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            "vnd.android.cursor.item/vnd.googleplus.profile.comm";
1976a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String HANGOUTS_DATA_5_VIDEO = "hangout";
1986a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String HANGOUTS_DATA_5_MESSAGE = "conversation";
19948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos    private static final String CALL_ORIGIN_QUICK_CONTACTS_ACTIVITY =
20048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            "com.android.contacts.quickcontact.QuickContactActivity";
201e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos
20263176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell    /**
20363176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell     * The URI used to load the the Contact. Once the contact is loaded, use Contact#getLookupUri()
20463176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell     * instead of referencing this URI.
20563176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell     */
206edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private Uri mLookupUri;
207edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private String[] mExcludeMimes;
2088a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private int mExtraMode;
2098a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private int mStatusBarColor;
2108a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private boolean mHasAlreadyBeenOpened;
21197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    private boolean mOnlyOnePhoneNumber;
21297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    private boolean mOnlyOneEmail;
213edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
21402eaf11669d25fd885606b3b0700358323532cddBrian Attwell    private QuickContactImageView mPhotoView;
215eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private ExpandingEntryCardView mContactCard;
2166095369885edcca566a812b551886e29c7ff8039Brian Attwell    private ExpandingEntryCardView mNoContactDetailsCard;
217b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private ExpandingEntryCardView mRecentCard;
218eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private ExpandingEntryCardView mAboutCard;
219b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    private MultiShrinkScroller mScroller;
220d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private SelectAccountDialogFragmentListener mSelectAccountFragmentListener;
2216bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private AsyncTask<Void, Void, Cp2DataCardModel> mEntriesAndActionsTask;
22230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell    private AsyncTask<Void, Void, Void> mRecentDataTask;
2236bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    /**
2246bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * The last copy of Cp2DataCardModel that was passed to {@link #populateContactAndAboutCard}.
2256bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     */
2266bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private Cp2DataCardModel mCachedCp2DataCardModel;
227f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell    /**
228f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  This scrim's opacity is controlled in two different ways. 1) Before the initial entrance
229f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  animation finishes, the opacity is animated by a value animator. This is designed to
230f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  distract the user from the length of the initial loading time. 2) After the initial
231f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  entrance animation, the opacity is directly related to scroll position.
232f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     */
2339b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    private ColorDrawable mWindowScrim;
234f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell    private boolean mIsEntranceAnimationFinished;
235a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell    private MaterialColorMapUtils mMaterialColorMapUtils;
2368477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell    private boolean mIsExitAnimationInProgress;
2378571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell    private boolean mHasComputedThemeColor;
238edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
239a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    /**
240a42ef76251778161d27bc07db214b8c81720e476Paul Soulos     * Used to stop the ExpandingEntry cards from adjusting between an entry click and the intent
241a42ef76251778161d27bc07db214b8c81720e476Paul Soulos     * being launched.
242a42ef76251778161d27bc07db214b8c81720e476Paul Soulos     */
243a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    private boolean mHasIntentLaunched;
244a42ef76251778161d27bc07db214b8c81720e476Paul Soulos
2456cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee    private Contact mContactData;
2469815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann    private ContactLoader mContactLoader;
2479b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    private PorterDuffColorFilter mColorFilter;
2489815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann
2499758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus    private final ImageViewDrawableSetter mPhotoSetter = new ImageViewDrawableSetter();
2509758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus
251edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
252cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * {@link #LEADING_MIMETYPES} is used to sort MIME-types.
253edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     *
254edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * <p>The MIME-types in {@link #LEADING_MIMETYPES} appear in the front of the dialog,
255edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * in the order specified here.</p>
256edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
257edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final List<String> LEADING_MIMETYPES = Lists.newArrayList(
258cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos            Phone.CONTENT_ITEM_TYPE, SipAddress.CONTENT_ITEM_TYPE, Email.CONTENT_ITEM_TYPE,
259405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos            StructuredPostal.CONTENT_ITEM_TYPE);
260edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
261a153dba33c2152332c5706178a367f52b0550723Paul Soulos    private static final List<String> SORTED_ABOUT_CARD_MIMETYPES = Lists.newArrayList(
262a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Nickname.CONTENT_ITEM_TYPE,
263a153dba33c2152332c5706178a367f52b0550723Paul Soulos            // Phonetic name is inserted after nickname if it is available.
264a153dba33c2152332c5706178a367f52b0550723Paul Soulos            // No mimetype for phonetic name exists.
265a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Website.CONTENT_ITEM_TYPE,
266a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Organization.CONTENT_ITEM_TYPE,
267a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Event.CONTENT_ITEM_TYPE,
268a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Relation.CONTENT_ITEM_TYPE,
269a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Im.CONTENT_ITEM_TYPE,
270a153dba33c2152332c5706178a367f52b0550723Paul Soulos            GroupMembership.CONTENT_ITEM_TYPE,
271a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Identity.CONTENT_ITEM_TYPE,
272a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Note.CONTENT_ITEM_TYPE);
273eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
274c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell    private static final BidiFormatter sBidiFormatter = BidiFormatter.getInstance();
275c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell
276b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    /** Id for the background contact loader */
277b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private static final int LOADER_CONTACT_ID = 0;
278b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
279ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final String KEY_LOADER_EXTRA_PHONES =
280ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos            QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_PHONES";
281ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
282b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    /** Id for the background Sms Loader */
283b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private static final int LOADER_SMS_ID = 1;
284b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private static final int MAX_SMS_RETRIEVE = 3;
285ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
286ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    /** Id for the back Calendar Loader */
287899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final int LOADER_CALENDAR_ID = 2;
288ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final String KEY_LOADER_EXTRA_EMAILS =
289ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos            QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_EMAILS";
290899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final int MAX_PAST_CALENDAR_RETRIEVE = 3;
291899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final int MAX_FUTURE_CALENDAR_RETRIEVE = 3;
292899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final long PAST_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR =
29340d7a65c6e68967f3f486715b194c144d93c296fPaul Soulos            1L * 24L * 60L * 60L * 1000L /* 1 day */;
294899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final long FUTURE_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR =
29540d7a65c6e68967f3f486715b194c144d93c296fPaul Soulos            7L * 24L * 60L * 60L * 1000L /* 7 days */;
296899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos
297ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    /** Id for the background Call Log Loader */
298ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final int LOADER_CALL_LOG_ID = 3;
299ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final int MAX_CALL_LOG_RETRIEVE = 3;
3006095369885edcca566a812b551886e29c7ff8039Brian Attwell    private static final int MIN_NUM_CONTACT_ENTRIES_SHOWN = 3;
3016095369885edcca566a812b551886e29c7ff8039Brian Attwell    private static final int MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN = 3;
3026095369885edcca566a812b551886e29c7ff8039Brian Attwell    private static final int CARD_ENTRY_ID_EDIT_CONTACT = -2;
303ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
304ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
305ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final int[] mRecentLoaderIds = new int[]{
306ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        LOADER_SMS_ID,
307ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        LOADER_CALENDAR_ID,
308ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        LOADER_CALL_LOG_ID};
309a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos    private Map<Integer, List<ContactInteraction>> mRecentLoaderResults = new HashMap<>();
310b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
311d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private static final String FRAGMENT_TAG_SELECT_ACCOUNT = "select_account_fragment";
3126cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee
3132d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    final OnClickListener mEntryClickHandler = new OnClickListener() {
3142d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        @Override
3152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        public void onClick(View v) {
3162ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final Object entryTagObject = v.getTag();
3172ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            if (entryTagObject == null || !(entryTagObject instanceof EntryTag)) {
3182ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos                Log.w(TAG, "EntryTag was not used correctly");
3196095369885edcca566a812b551886e29c7ff8039Brian Attwell                return;
3206095369885edcca566a812b551886e29c7ff8039Brian Attwell            }
3212ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final EntryTag entryTag = (EntryTag) entryTagObject;
3222ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final Intent intent = entryTag.getIntent();
3232ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final int dataId = entryTag.getId();
3242ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos
3252ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            if (dataId == CARD_ENTRY_ID_EDIT_CONTACT) {
3262ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos                editContact();
3272d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                return;
3282d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            }
329ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
330ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            // Default to USAGE_TYPE_CALL. Usage is summed among all types for sorting each data id
331ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            // so the exact usage type is not necessary in all cases
332ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            String usageType = DataUsageFeedback.USAGE_TYPE_CALL;
333ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
33420bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos            final Uri intentUri = intent.getData();
33520bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos            if ((intentUri != null && intentUri.getScheme() != null &&
3361cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                    intentUri.getScheme().equals(ContactsUtils.SCHEME_SMSTO)) ||
337ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                    (intent.getType() != null && intent.getType().equals(MIMETYPE_SMS))) {
338ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                usageType = DataUsageFeedback.USAGE_TYPE_SHORT_TEXT;
339ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            }
340ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
341ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            // Data IDs start at 1 so anything less is invalid
342ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            if (dataId > 0) {
34320bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos                final Uri dataUsageUri = DataUsageFeedback.FEEDBACK_URI.buildUpon()
344ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                        .appendPath(String.valueOf(dataId))
345ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                        .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, usageType)
346ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                        .build();
347ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                final boolean successful = getContentResolver().update(
34820bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos                        dataUsageUri, new ContentValues(), null, null) > 0;
349ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                if (!successful) {
350ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                    Log.w(TAG, "DataUsageFeedback increment failed");
351ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                }
352ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            } else {
353ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                Log.w(TAG, "Invalid Data ID");
354ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            }
355ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
35670e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen            // Pass the touch point through the intent for use in the InCallUI
35770e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen            if (Intent.ACTION_CALL.equals(intent.getAction())) {
3581f8a3fda87bf61e579d61e3fdd246548943d070aNancy Chen                if (TouchPointManager.getInstance().hasValidPoint()) {
35970e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen                    Bundle extras = new Bundle();
3601f8a3fda87bf61e579d61e3fdd246548943d070aNancy Chen                    extras.putParcelable(TouchPointManager.TOUCH_POINT,
3611f8a3fda87bf61e579d61e3fdd246548943d070aNancy Chen                            TouchPointManager.getInstance().getPoint());
3620319222b43927d4d9ce7e2a9070f3543661b5782Tyler Gunn                    intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
36370e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen                }
36470e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen            }
36570e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen
366793e73c859ed839c28cc37d80d62bde0a361c78aPaul Soulos            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
367793e73c859ed839c28cc37d80d62bde0a361c78aPaul Soulos
368a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            mHasIntentLaunched = true;
369417309a770568d7b278abc91c46a739020e48157Jay Shrauner            try {
370417309a770568d7b278abc91c46a739020e48157Jay Shrauner                startActivity(intent);
371417309a770568d7b278abc91c46a739020e48157Jay Shrauner            } catch (ActivityNotFoundException ex) {
372417309a770568d7b278abc91c46a739020e48157Jay Shrauner                Toast.makeText(QuickContactActivity.this, R.string.missing_app,
373417309a770568d7b278abc91c46a739020e48157Jay Shrauner                        Toast.LENGTH_SHORT).show();
374417309a770568d7b278abc91c46a739020e48157Jay Shrauner            }
3752d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
3762d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    };
3772d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
378e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    final ExpandingEntryCardViewListener mExpandingEntryCardViewListener
379e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell            = new ExpandingEntryCardViewListener() {
380e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        @Override
381e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        public void onCollapse(int heightDelta) {
382e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell            mScroller.prepareForShrinkingScrollChild(heightDelta);
383e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        }
3840cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
3850cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        @Override
3860cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        public void onExpand(int heightDelta) {
3870cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            mScroller.prepareForExpandingScrollChild();
3880cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        }
389e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    };
390e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell
39197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    private interface ContextMenuIds {
39297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        static final int COPY_TEXT = 0;
39397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        static final int CLEAR_DEFAULT = 1;
39497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        static final int SET_DEFAULT = 2;
39597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    }
39697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
3972a4207fb39330e840436215c896cde911489e111Paul Soulos    private final OnCreateContextMenuListener mEntryContextMenuListener =
3982a4207fb39330e840436215c896cde911489e111Paul Soulos            new OnCreateContextMenuListener() {
3992a4207fb39330e840436215c896cde911489e111Paul Soulos        @Override
4002a4207fb39330e840436215c896cde911489e111Paul Soulos        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
4012a4207fb39330e840436215c896cde911489e111Paul Soulos            if (menuInfo == null) {
4022a4207fb39330e840436215c896cde911489e111Paul Soulos                return;
4032a4207fb39330e840436215c896cde911489e111Paul Soulos            }
40497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            final EntryContextMenuInfo info = (EntryContextMenuInfo) menuInfo;
4052a4207fb39330e840436215c896cde911489e111Paul Soulos            menu.setHeaderTitle(info.getCopyText());
40697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            menu.add(ContextMenu.NONE, ContextMenuIds.COPY_TEXT,
40797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    ContextMenu.NONE, getString(R.string.copy_text));
40897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
40997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Don't allow setting or clearing of defaults for non-editable contacts
41097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            if (!isContactEditable()) {
41197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return;
41297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            }
41397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
41497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            final String selectedMimeType = info.getMimeType();
41597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
41697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Defaults to true will only enable the detail to be copied to the clipboard.
41797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            boolean onlyOneOfMimeType = true;
41897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
41997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Only allow primary support for Phone and Email content types
42097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            if (Phone.CONTENT_ITEM_TYPE.equals(selectedMimeType)) {
42197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                onlyOneOfMimeType = mOnlyOnePhoneNumber;
42297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            } else if (Email.CONTENT_ITEM_TYPE.equals(selectedMimeType)) {
42397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                onlyOneOfMimeType = mOnlyOneEmail;
42497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            }
42597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
42697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Checking for previously set default
42797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            if (info.isSuperPrimary()) {
42897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                menu.add(ContextMenu.NONE, ContextMenuIds.CLEAR_DEFAULT,
42997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        ContextMenu.NONE, getString(R.string.clear_default));
43097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            } else if (!onlyOneOfMimeType) {
43197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                menu.add(ContextMenu.NONE, ContextMenuIds.SET_DEFAULT,
43297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        ContextMenu.NONE, getString(R.string.set_default));
43397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            }
4342a4207fb39330e840436215c896cde911489e111Paul Soulos        }
4352a4207fb39330e840436215c896cde911489e111Paul Soulos    };
4362a4207fb39330e840436215c896cde911489e111Paul Soulos
4372a4207fb39330e840436215c896cde911489e111Paul Soulos    @Override
4382a4207fb39330e840436215c896cde911489e111Paul Soulos    public boolean onContextItemSelected(MenuItem item) {
4392a4207fb39330e840436215c896cde911489e111Paul Soulos        EntryContextMenuInfo menuInfo;
4402a4207fb39330e840436215c896cde911489e111Paul Soulos        try {
4412a4207fb39330e840436215c896cde911489e111Paul Soulos            menuInfo = (EntryContextMenuInfo) item.getMenuInfo();
4422a4207fb39330e840436215c896cde911489e111Paul Soulos        } catch (ClassCastException e) {
4432a4207fb39330e840436215c896cde911489e111Paul Soulos            Log.e(TAG, "bad menuInfo", e);
4442a4207fb39330e840436215c896cde911489e111Paul Soulos            return false;
4452a4207fb39330e840436215c896cde911489e111Paul Soulos        }
4462a4207fb39330e840436215c896cde911489e111Paul Soulos
44797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        switch (item.getItemId()) {
44897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            case ContextMenuIds.COPY_TEXT:
44997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                ClipboardUtils.copyText(this, menuInfo.getCopyLabel(), menuInfo.getCopyText(),
45097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        true);
45197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return true;
45297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            case ContextMenuIds.SET_DEFAULT:
45397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                final Intent setIntent = ContactSaveService.createSetSuperPrimaryIntent(this,
45497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        menuInfo.getId());
45597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                this.startService(setIntent);
45697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return true;
45797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            case ContextMenuIds.CLEAR_DEFAULT:
45897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                final Intent clearIntent = ContactSaveService.createClearPrimaryIntent(this,
45997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        menuInfo.getId());
46097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                this.startService(clearIntent);
46197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return true;
46297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            default:
46397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                throw new IllegalArgumentException("Unknown menu option " + item.getItemId());
46497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
4652a4207fb39330e840436215c896cde911489e111Paul Soulos    }
4662a4207fb39330e840436215c896cde911489e111Paul Soulos
467d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    /**
468d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     * Headless fragment used to handle account selection callbacks invoked from
469d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     * {@link DirectoryContactUtil}.
470d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     */
471d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public static class SelectAccountDialogFragmentListener extends Fragment
472d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            implements SelectAccountDialogFragment.Listener {
473d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
474d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        private QuickContactActivity mQuickContactActivity;
475d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
476d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public SelectAccountDialogFragmentListener() {}
477d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
478d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        @Override
479d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
480d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            DirectoryContactUtil.createCopy(mQuickContactActivity.mContactData.getContentValues(),
481d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    account, mQuickContactActivity);
482d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
483d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
484d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        @Override
485d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public void onAccountSelectorCancelled() {}
486d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
487d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        /**
488d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         * Set the parent activity. Since rotation can cause this fragment to be used across
489d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         * more than one activity instance, we need to explicitly set this value instead
490d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         * of making this class non-static.
491d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         */
492d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public void setQuickContactActivity(QuickContactActivity quickContactActivity) {
493d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mQuickContactActivity = quickContactActivity;
494d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
495d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
496d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
497b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    final MultiShrinkScrollerListener mMultiShrinkScrollerListener
498b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell            = new MultiShrinkScrollerListener() {
499b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        @Override
500b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        public void onScrolledOffBottom() {
501f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell            finish();
502b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        }
5038a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
5048a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        @Override
5058a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        public void onEnterFullscreen() {
5068a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            updateStatusBarColor();
5078a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
5088a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
5098a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        @Override
5108a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        public void onExitFullscreen() {
5118a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            updateStatusBarColor();
5128a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
5138477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell
5148477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        @Override
5158477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        public void onStartScrollOffBottom() {
5168477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            mIsExitAnimationInProgress = true;
5178477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        }
5188477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell
5198477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        @Override
520f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        public void onEntranceAnimationDone() {
521f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell            mIsEntranceAnimationFinished = true;
522f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        }
523f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell
524f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        @Override
525f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        public void onTransparentViewHeightChange(float ratio) {
526f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell            if (mIsEntranceAnimationFinished) {
527f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                mWindowScrim.setAlpha((int) (0xFF * ratio));
5288477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            }
5298477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        }
530b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    };
531b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell
532eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
533eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    /**
534eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * Data items are compared to the same mimetype based off of three qualities:
535eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * 1. Super primary
536eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * 2. Primary
537eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * 3. Times used
538eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     */
539eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final Comparator<DataItem> mWithinMimeTypeDataItemComparator =
540eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            new Comparator<DataItem>() {
541eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        @Override
542eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        public int compare(DataItem lhs, DataItem rhs) {
543eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!lhs.getMimeType().equals(rhs.getMimeType())) {
544eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                Log.wtf(TAG, "Comparing DataItems with different mimetypes lhs.getMimeType(): " +
545eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        lhs.getMimeType() + " rhs.getMimeType(): " + rhs.getMimeType());
546eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 0;
547eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
548eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
549eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (lhs.isSuperPrimary()) {
550eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return -1;
551eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (rhs.isSuperPrimary()) {
552eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 1;
553eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (lhs.isPrimary() && !rhs.isPrimary()) {
554eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return -1;
555eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (!lhs.isPrimary() && rhs.isPrimary()) {
556eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 1;
557eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else {
558eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final int lhsTimesUsed =
559eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        lhs.getTimesUsed() == null ? 0 : lhs.getTimesUsed();
560eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final int rhsTimesUsed =
561eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        rhs.getTimesUsed() == null ? 0 : rhs.getTimesUsed();
562eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
563eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return rhsTimesUsed - lhsTimesUsed;
564eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
565eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
566eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    };
567eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
568cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos    /**
569cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * Sorts among different mimetypes based off:
570cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * 1. Times used
571cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * 2. Last time used
572cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * 3. Statically defined
573cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     */
574eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final Comparator<List<DataItem>> mAmongstMimeTypeDataItemComparator =
575eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            new Comparator<List<DataItem>> () {
576eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        @Override
577eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        public int compare(List<DataItem> lhsList, List<DataItem> rhsList) {
578eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            DataItem lhs = lhsList.get(0);
579eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            DataItem rhs = rhsList.get(0);
580eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final int lhsTimesUsed = lhs.getTimesUsed() == null ? 0 : lhs.getTimesUsed();
581eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final int rhsTimesUsed = rhs.getTimesUsed() == null ? 0 : rhs.getTimesUsed();
582eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final int timesUsedDifference = rhsTimesUsed - lhsTimesUsed;
583eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (timesUsedDifference != 0) {
584eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return timesUsedDifference;
585eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
586eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
587eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final long lhsLastTimeUsed =
588eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    lhs.getLastTimeUsed() == null ? 0 : lhs.getLastTimeUsed();
589eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final long rhsLastTimeUsed =
590eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    rhs.getLastTimeUsed() == null ? 0 : rhs.getLastTimeUsed();
591eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final long lastTimeUsedDifference = rhsLastTimeUsed - lhsLastTimeUsed;
592eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (lastTimeUsedDifference > 0) {
593eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 1;
594eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (lastTimeUsedDifference < 0) {
595eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return -1;
596eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
597eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
598eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Times used and last time used are the same. Resort to statically defined.
599eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String lhsMimeType = lhs.getMimeType();
600eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String rhsMimeType = rhs.getMimeType();
601eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            for (String mimeType : LEADING_MIMETYPES) {
602eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (lhsMimeType.equals(mimeType)) {
603eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    return -1;
604eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                } else if (rhsMimeType.equals(mimeType)) {
605eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    return 1;
606eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                }
607eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
608eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            return 0;
609eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
610eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    };
611eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
612edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @Override
613f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen    public boolean dispatchTouchEvent(MotionEvent ev) {
614f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
615f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen            TouchPointManager.getInstance().setPoint((int) ev.getRawX(), (int) ev.getRawY());
616f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen        }
617f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen        return super.dispatchTouchEvent(ev);
618f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen    }
619f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen
620f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen    @Override
6218a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    protected void onCreate(Bundle savedInstanceState) {
6228a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.beginSection("onCreate()");
6238a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.onCreate(savedInstanceState);
624edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
6258a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        getWindow().setStatusBarColor(Color.TRANSPARENT);
6262426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann
627d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        processIntent(getIntent());
628dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
62910d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa        // Show QuickContact in front of soft input
63010d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
63110d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
63210d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa
633edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        setContentView(R.layout.quickcontact_activity);
634edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
635a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell        mMaterialColorMapUtils = new MaterialColorMapUtils(getResources());
636a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell
6370cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        mScroller = (MultiShrinkScroller) findViewById(R.id.multiscroller);
6380cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
639eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mContactCard = (ExpandingEntryCardView) findViewById(R.id.communication_card);
6406095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard = (ExpandingEntryCardView) findViewById(R.id.no_contact_data_card);
641b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        mRecentCard = (ExpandingEntryCardView) findViewById(R.id.recent_card);
642eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mAboutCard = (ExpandingEntryCardView) findViewById(R.id.about_card);
643edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
6446095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setOnClickListener(mEntryClickHandler);
645eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mContactCard.setOnClickListener(mEntryClickHandler);
646eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mContactCard.setExpandButtonText(
64723889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos        getResources().getString(R.string.expanding_entry_card_view_see_all));
6482a4207fb39330e840436215c896cde911489e111Paul Soulos        mContactCard.setOnCreateContextMenuListener(mEntryContextMenuListener);
649b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
650b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        mRecentCard.setOnClickListener(mEntryClickHandler);
651b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        mRecentCard.setTitle(getResources().getString(R.string.recent_card_title));
652edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
653eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mAboutCard.setOnClickListener(mEntryClickHandler);
6542a4207fb39330e840436215c896cde911489e111Paul Soulos        mAboutCard.setOnCreateContextMenuListener(mEntryContextMenuListener);
655eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
65602eaf11669d25fd885606b3b0700358323532cddBrian Attwell        mPhotoView = (QuickContactImageView) findViewById(R.id.photo);
65763176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        final View transparentView = findViewById(R.id.transparent_view);
6580d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell        if (mScroller != null) {
65963176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell            transparentView.setOnClickListener(new OnClickListener() {
6600d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                @Override
6610d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                public void onClick(View v) {
6620d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                    mScroller.scrollOffBottom();
6630d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                }
6640d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell            });
6650d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell        }
666edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
667d41ab8ace81a2e44f8b28aa8782679b9e9cca1b9Brian Attwell        // Allow a shadow to be shown under the toolbar.
668d41ab8ace81a2e44f8b28aa8782679b9e9cca1b9Brian Attwell        ViewUtil.addRectangularOutlineProvider(findViewById(R.id.toolbar_parent), getResources());
669d41ab8ace81a2e44f8b28aa8782679b9e9cca1b9Brian Attwell
670d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
671d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        setActionBar(toolbar);
6729b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        getActionBar().setTitle(null);
6739b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        // Put a TextView with a known resource id into the ActionBar. This allows us to easily
6749b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        // find the correct TextView location & size later.
6759b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        toolbar.addView(getLayoutInflater().inflate(R.layout.quickcontact_title_placeholder, null));
6766219668d0612f7522bd15a9d34c6232cb15b9a6cYorke Lee
6778a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mHasAlreadyBeenOpened = savedInstanceState != null;
678f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        mIsEntranceAnimationFinished = mHasAlreadyBeenOpened;
6799b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        mWindowScrim = new ColorDrawable(SCRIM_COLOR);
680f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        mWindowScrim.setAlpha(0);
6819b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        getWindow().setBackgroundDrawable(mWindowScrim);
682edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
683c33ae17c9816b770041ee1f9ccde10e7c7eee491Brian Attwell        mScroller.initialize(mMultiShrinkScrollerListener, mExtraMode == MODE_FULLY_EXPANDED);
684ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell        // mScroller needs to perform asynchronous measurements after initalize(), therefore
685ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell        // we can't mark this as GONE.
686ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell        mScroller.setVisibility(View.INVISIBLE);
6878a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
6889b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        setHeaderNameText(R.string.missing_name);
6899b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
690d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mSelectAccountFragmentListener= (SelectAccountDialogFragmentListener) getFragmentManager()
691d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                .findFragmentByTag(FRAGMENT_TAG_SELECT_ACCOUNT);
692d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (mSelectAccountFragmentListener == null) {
693d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mSelectAccountFragmentListener = new SelectAccountDialogFragmentListener();
694d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            getFragmentManager().beginTransaction().add(0, mSelectAccountFragmentListener,
695d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    FRAGMENT_TAG_SELECT_ACCOUNT).commit();
696d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mSelectAccountFragmentListener.setRetainInstance(true);
697d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
698d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mSelectAccountFragmentListener.setQuickContactActivity(this);
69923889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos
700f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        SchedulingUtils.doOnPreDraw(mScroller, /* drawNextFrame = */ true,
701f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                new Runnable() {
702f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                    @Override
703f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                    public void run() {
704f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                        if (!mHasAlreadyBeenOpened) {
705f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            // The initial scrim opacity must match the scrim opacity that would be
706f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            // achieved by scrolling to the starting position.
707f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            final float alphaRatio = mExtraMode == MODE_FULLY_EXPANDED ?
708f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                                    1 : mScroller.getStartingTransparentHeightRatio();
709f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            final int duration = getResources().getInteger(
710f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                                    android.R.integer.config_shortAnimTime);
711f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            final int desiredAlpha = (int) (0xFF * alphaRatio);
712f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            ObjectAnimator o = ObjectAnimator.ofInt(mWindowScrim, "alpha", 0,
713f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                                    desiredAlpha).setDuration(duration);
714f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell
715f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            o.start();
716f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                        }
717f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                    }
718f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                });
719f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell
7209b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        if (savedInstanceState != null) {
7219b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            final int color = savedInstanceState.getInt(KEY_THEME_COLOR, 0);
722ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell            SchedulingUtils.doOnPreDraw(mScroller, /* drawNextFrame = */ false,
723ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                    new Runnable() {
724ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                        @Override
725ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                        public void run() {
726ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // Need to wait for the pre draw before setting the initial scroll
727ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // value. Prior to pre draw all scroll values are invalid.
728ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            if (mHasAlreadyBeenOpened) {
729ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                                mScroller.setVisibility(View.VISIBLE);
730ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                                mScroller.setScroll(mScroller.getScrollNeededToBeFullScreen());
731ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            }
732ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // Need to wait for pre draw for setting the theme color. Setting the
733ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // header tint before the MultiShrinkScroller has been measured will
734ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // cause incorrect tinting calculations.
735ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            if (color != 0) {
736a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                                setThemeColor(mMaterialColorMapUtils
737a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                                        .calculatePrimaryAndSecondaryColor(color));
7389b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell                            }
739ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                        }
740ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                    });
7419b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        }
7429b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
7438a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
7448a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
7458a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
746405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos    @Override
747405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
7488a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (requestCode == REQUEST_CODE_CONTACT_EDITOR_ACTIVITY &&
7498a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                resultCode == ContactDeletionInteraction.RESULT_CODE_DELETED) {
7508a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // The contact that we were showing has been deleted.
7518a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            finish();
752ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos        } else if (requestCode == REQUEST_CODE_CONTACT_SELECTION_ACTIVITY &&
753ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                resultCode != RESULT_CANCELED) {
754ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos            processIntent(data);
755b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        }
7568a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
757dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
7588a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    @Override
7598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    protected void onNewIntent(Intent intent) {
7608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.onNewIntent(intent);
7618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mHasAlreadyBeenOpened = true;
762f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        mIsEntranceAnimationFinished = true;
7638571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell        mHasComputedThemeColor = false;
764d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        processIntent(intent);
765d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
766d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
7679b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    @Override
7689b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    public void onSaveInstanceState(Bundle savedInstanceState) {
7699b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        super.onSaveInstanceState(savedInstanceState);
7709b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        if (mColorFilter != null) {
7719b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            savedInstanceState.putInt(KEY_THEME_COLOR, mColorFilter.getColor());
7729b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        }
7739b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    }
7749b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
775d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private void processIntent(Intent intent) {
776f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos        if (intent == null) {
777f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos            finish();
778f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos            return;
779f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos        }
780d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        Uri lookupUri = intent.getData();
781d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
782d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        // Check to see whether it comes from the old version.
783d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (lookupUri != null && LEGACY_AUTHORITY.equals(lookupUri.getAuthority())) {
784d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final long rawContactId = ContentUris.parseId(lookupUri);
785d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            lookupUri = RawContacts.getContactLookupUri(getContentResolver(),
786d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
787d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
788d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mExtraMode = getIntent().getIntExtra(QuickContact.EXTRA_MODE,
789d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                QuickContact.MODE_LARGE);
790d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        final Uri oldLookupUri = mLookupUri;
791d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
792d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mLookupUri = Preconditions.checkNotNull(lookupUri, "missing lookupUri");
793d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mExcludeMimes = intent.getStringArrayExtra(QuickContact.EXTRA_EXCLUDE_MIMES);
794d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (oldLookupUri == null) {
795d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mContactLoader = (ContactLoader) getLoaderManager().initLoader(
796d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    LOADER_CONTACT_ID, null, mLoaderContactCallbacks);
797d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        } else if (oldLookupUri != mLookupUri) {
798d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // After copying a directory contact, the contact URI changes. Therefore,
799d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // we need to restart the loader and reload the new contact.
80059a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell            destroyInteractionLoaders();
801405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos            mContactLoader = (ContactLoader) getLoaderManager().restartLoader(
802405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos                    LOADER_CONTACT_ID, null, mLoaderContactCallbacks);
80359a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell            mCachedCp2DataCardModel = null;
804d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
8052d150da246632b1649999cfabed776133b097775Brian Attwell
8062d150da246632b1649999cfabed776133b097775Brian Attwell        NfcHandler.register(this, mLookupUri);
8072426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann    }
808edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
80959a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell    private void destroyInteractionLoaders() {
81059a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        for (int interactionLoaderId : mRecentLoaderIds) {
81159a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell            getLoaderManager().destroyLoader(interactionLoaderId);
81259a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        }
81359a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell    }
81459a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell
815b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    private void runEntranceAnimation() {
8168a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mHasAlreadyBeenOpened) {
8178a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            return;
8188a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
8198a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mHasAlreadyBeenOpened = true;
820c33ae17c9816b770041ee1f9ccde10e7c7eee491Brian Attwell        mScroller.scrollUpForEntranceAnimation(mExtraMode != MODE_FULLY_EXPANDED);
821b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    }
822b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell
82381281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /** Assign this string to the view if it is not empty. */
824d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private void setHeaderNameText(int resId) {
8259b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        if (mScroller != null) {
826f43f573340fd9de5d30b43d7c96cac1ec9021e58Brian Attwell            mScroller.setTitle(getText(resId) == null ? null : getText(resId).toString());
8279b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        }
82881281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    }
82981281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan
83081281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /** Assign this string to the view if it is not empty. */
831f43f573340fd9de5d30b43d7c96cac1ec9021e58Brian Attwell    private void setHeaderNameText(String value) {
832d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (!TextUtils.isEmpty(value)) {
8339b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            if (mScroller != null) {
834f43f573340fd9de5d30b43d7c96cac1ec9021e58Brian Attwell                mScroller.setTitle(value);
8359b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            }
83681281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        }
83781281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    }
83881281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan
83981281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /**
840edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Check if the given MIME-type appears in the list of excluded MIME-types
841edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * that the most-recent caller requested.
842edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
843edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private boolean isMimeExcluded(String mimeType) {
844edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        if (mExcludeMimes == null) return false;
845edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String excludedMime : mExcludeMimes) {
846edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (TextUtils.equals(excludedMime, mimeType)) {
847edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                return true;
848edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
849edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
850edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        return false;
851edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
852edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
853edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
854cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann     * Handle the result from the ContactLoader
855edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
8568a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private void bindContactData(final Contact data) {
8578a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.beginSection("bindContactData");
8586cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee        mContactData = data;
859d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        invalidateOptionsMenu();
860edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
8618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
8628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.beginSection("Set display photo & name");
863dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
86402eaf11669d25fd885606b3b0700358323532cddBrian Attwell        mPhotoView.setIsBusiness(mContactData.isDisplayNameFromOrganization());
8656219668d0612f7522bd15a9d34c6232cb15b9a6cYorke Lee        mPhotoSetter.setupContactPhoto(data, mPhotoView);
86631b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        extractAndApplyTintFromPhotoViewAsynchronously();
8674936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        analyzeWhitenessOfPhotoAsynchronously();
868333091ae754ddfc25714c14b9b89534be24379f9Paul Soulos        setHeaderNameText(ContactDisplayUtils.getDisplayName(this, data).toString());
869edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
8708a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
871dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
8726bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        mEntriesAndActionsTask = new AsyncTask<Void, Void, Cp2DataCardModel>() {
8738a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
8748a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            @Override
8756bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            protected Cp2DataCardModel doInBackground(
876eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    Void... params) {
877eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return generateDataModelFromContact(data);
8788a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            }
8798a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
8808a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            @Override
8816bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            protected void onPostExecute(Cp2DataCardModel cardDataModel) {
8826bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                super.onPostExecute(cardDataModel);
8838a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                // Check that original AsyncTask parameters are still valid and the activity
8848a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                // is still running before binding to UI. A new intent could invalidate
8858a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                // the results, for example.
8868a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                if (data == mContactData && !isCancelled()) {
8876bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                    bindDataToCards(cardDataModel);
8888a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    showActivity();
8898a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                }
8908a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            }
8918a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        };
8928a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mEntriesAndActionsTask.execute();
8938a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
8948a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
8956bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private void bindDataToCards(Cp2DataCardModel cp2DataCardModel) {
8966bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        startInteractionLoaders(cp2DataCardModel);
8976bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        populateContactAndAboutCard(cp2DataCardModel);
898eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
899eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
9006bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private void startInteractionLoaders(Cp2DataCardModel cp2DataCardModel) {
9016bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final Map<String, List<DataItem>> dataItemsMap = cp2DataCardModel.dataItemsMap;
9026bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<DataItem> phoneDataItems = dataItemsMap.get(Phone.CONTENT_ITEM_TYPE);
90397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        if (phoneDataItems != null && phoneDataItems.size() == 1) {
90497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            mOnlyOnePhoneNumber = true;
90597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
906eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String[] phoneNumbers = null;
907eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (phoneDataItems != null) {
908eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            phoneNumbers = new String[phoneDataItems.size()];
909eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            for (int i = 0; i < phoneDataItems.size(); ++i) {
910eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                phoneNumbers[i] = ((PhoneDataItem) phoneDataItems.get(i)).getNumber();
911eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
912eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
913ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        final Bundle phonesExtraBundle = new Bundle();
914eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        phonesExtraBundle.putStringArray(KEY_LOADER_EXTRA_PHONES, phoneNumbers);
915eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
916eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("start sms loader");
9178a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        getLoaderManager().initLoader(
9188a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                LOADER_SMS_ID,
919ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                phonesExtraBundle,
920ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                mLoaderInteractionsCallbacks);
921ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        Trace.endSection();
922ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
923ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        Trace.beginSection("start call log loader");
924ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        getLoaderManager().initLoader(
925ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                LOADER_CALL_LOG_ID,
926ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                phonesExtraBundle,
9278a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                mLoaderInteractionsCallbacks);
928899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos        Trace.endSection();
9298a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
930eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
931899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos        Trace.beginSection("start calendar loader");
9326bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<DataItem> emailDataItems = dataItemsMap.get(Email.CONTENT_ITEM_TYPE);
93397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        if (emailDataItems != null && emailDataItems.size() == 1) {
93497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            mOnlyOneEmail = true;
93597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
936eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String[] emailAddresses = null;
937eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (emailDataItems != null) {
938eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            emailAddresses = new String[emailDataItems.size()];
939eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            for (int i = 0; i < emailDataItems.size(); ++i) {
940eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                emailAddresses[i] = ((EmailDataItem) emailDataItems.get(i)).getAddress();
941eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
942eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
943ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        final Bundle emailsExtraBundle = new Bundle();
944eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        emailsExtraBundle.putStringArray(KEY_LOADER_EXTRA_EMAILS, emailAddresses);
945899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos        getLoaderManager().initLoader(
946899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                LOADER_CALENDAR_ID,
947ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                emailsExtraBundle,
948899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                mLoaderInteractionsCallbacks);
9498a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
9508a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
9518a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
9528a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private void showActivity() {
9538a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mScroller != null) {
9548a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            mScroller.setVisibility(View.VISIBLE);
9558a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            SchedulingUtils.doOnPreDraw(mScroller, /* drawNextFrame = */ false,
9568a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    new Runnable() {
9578a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                        @Override
9588a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                        public void run() {
9598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                            runEntranceAnimation();
9608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                        }
9618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    });
9628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
9638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
9648a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
9656bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private List<List<Entry>> buildAboutCardEntries(Map<String, List<DataItem>> dataItemsMap) {
966a153dba33c2152332c5706178a367f52b0550723Paul Soulos        final List<List<Entry>> aboutCardEntries = new ArrayList<>();
967a153dba33c2152332c5706178a367f52b0550723Paul Soulos        for (String mimetype : SORTED_ABOUT_CARD_MIMETYPES) {
9686bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final List<DataItem> mimeTypeItems = dataItemsMap.get(mimetype);
969a153dba33c2152332c5706178a367f52b0550723Paul Soulos            if (mimeTypeItems == null) {
970a153dba33c2152332c5706178a367f52b0550723Paul Soulos                continue;
971a153dba33c2152332c5706178a367f52b0550723Paul Soulos            }
9726bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            // Set aboutCardTitleOut = null, since SORTED_ABOUT_CARD_MIMETYPES doesn't contain
9736bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            // the name mimetype.
9746bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final List<Entry> aboutEntries = dataItemsToEntries(mimeTypeItems,
9756bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                    /* aboutCardTitleOut = */ null);
976a153dba33c2152332c5706178a367f52b0550723Paul Soulos            if (aboutEntries.size() > 0) {
977a153dba33c2152332c5706178a367f52b0550723Paul Soulos                aboutCardEntries.add(aboutEntries);
978a153dba33c2152332c5706178a367f52b0550723Paul Soulos            }
979a153dba33c2152332c5706178a367f52b0550723Paul Soulos        }
980a153dba33c2152332c5706178a367f52b0550723Paul Soulos        return aboutCardEntries;
981a153dba33c2152332c5706178a367f52b0550723Paul Soulos    }
982a153dba33c2152332c5706178a367f52b0550723Paul Soulos
983a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    @Override
984a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    protected void onResume() {
985a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        super.onResume();
986a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        // If returning from a launched activity, repopulate the contact and about card
987a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        if (mHasIntentLaunched) {
988a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            mHasIntentLaunched = false;
9896bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            populateContactAndAboutCard(mCachedCp2DataCardModel);
990a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        }
99159a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell
99259a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        // When exiting the activity and resuming, we want to force a full reload of all the
99359a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        // interaction data in case something changed in the background. On screen rotation,
99459a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        // we don't need to do this. And, mCachedCp2DataCardModel will be null, so we won't.
99559a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        if (mCachedCp2DataCardModel != null) {
99659a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell            destroyInteractionLoaders();
99759a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell            startInteractionLoaders(mCachedCp2DataCardModel);
99859a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        }
999a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    }
1000a42ef76251778161d27bc07db214b8c81720e476Paul Soulos
10016bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private void populateContactAndAboutCard(Cp2DataCardModel cp2DataCardModel) {
10026bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        mCachedCp2DataCardModel = cp2DataCardModel;
10036bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        if (mHasIntentLaunched || cp2DataCardModel == null) {
1004a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            return;
1005a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        }
1006eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("bind contact card");
1007eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
10086bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> contactCardEntries = cp2DataCardModel.contactCardEntries;
10096bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> aboutCardEntries = cp2DataCardModel.aboutCardEntries;
10106bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final String customAboutCardName = cp2DataCardModel.customAboutCardName;
1011eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1012eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (contactCardEntries.size() > 0) {
1013eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            mContactCard.initialize(contactCardEntries,
1014eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    /* numInitialVisibleEntries = */ MIN_NUM_CONTACT_ENTRIES_SHOWN,
1015c8e2a91807b581194566eb45019fa16e2268b462Paul Soulos                    /* isExpanded = */ mContactCard.isExpanded(),
101689966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos                    /* isAlwaysExpanded = */ false,
10170cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                    mExpandingEntryCardViewListener,
10180cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                    mScroller);
1019eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            mContactCard.setVisibility(View.VISIBLE);
1020eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else {
1021eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            mContactCard.setVisibility(View.GONE);
1022eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1023eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
10248a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1025eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("bind about card");
1026c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        // Phonetic name is not a data item, so the entry needs to be created separately
1027c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        final String phoneticName = mContactData.getPhoneticName();
1028c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        if (!TextUtils.isEmpty(phoneticName)) {
1029c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos            Entry phoneticEntry = new Entry(/* viewId = */ -1,
1030c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* icon = */ null,
1031c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    getResources().getString(R.string.name_phonetic),
1032c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    phoneticName,
10338a3fe52802135be2402a5b216325615fb796a509Walter Jang                    /* subHeaderIcon = */ null,
1034c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* text = */ null,
10358a3fe52802135be2402a5b216325615fb796a509Walter Jang                    /* textIcon = */ null,
103623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    /* primaryContentDescription = */ null,
1037c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* intent = */ null,
1038c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* alternateIcon = */ null,
1039c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* alternateIntent = */ null,
1040c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* alternateContentDescription = */ null,
1041c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* shouldApplyColor = */ false,
10422a4207fb39330e840436215c896cde911489e111Paul Soulos                    /* isEditable = */ false,
10432a4207fb39330e840436215c896cde911489e111Paul Soulos                    /* EntryContextMenuInfo = */ new EntryContextMenuInfo(phoneticName,
104497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                            getResources().getString(R.string.name_phonetic),
104597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                            /* mimeType = */ null, /* id = */ -1, /* isPrimary = */ false),
104648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIcon = */ null,
104748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIntent = */ null,
104848290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    /* thirdContentDescription = */ null,
104948290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    /* iconResourceId = */ 0);
1050c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos            List<Entry> phoneticList = new ArrayList<>();
1051c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos            phoneticList.add(phoneticEntry);
1052a153dba33c2152332c5706178a367f52b0550723Paul Soulos            // Phonetic name comes after nickname. Check to see if the first entry type is nickname
1053a0fa4c18dc111ceea9ff47f35ee01fecc1003578Paul Soulos            if (aboutCardEntries.size() > 0 && aboutCardEntries.get(0).get(0).getHeader().equals(
1054a153dba33c2152332c5706178a367f52b0550723Paul Soulos                    getResources().getString(R.string.header_nickname_entry))) {
1055a153dba33c2152332c5706178a367f52b0550723Paul Soulos                aboutCardEntries.add(1, phoneticList);
1056a153dba33c2152332c5706178a367f52b0550723Paul Soulos            } else {
1057a153dba33c2152332c5706178a367f52b0550723Paul Soulos                aboutCardEntries.add(0, phoneticList);
1058a153dba33c2152332c5706178a367f52b0550723Paul Soulos            }
1059c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        }
1060c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos
10616bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        if (!TextUtils.isEmpty(customAboutCardName)) {
10626bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            mAboutCard.setTitle(customAboutCardName);
10636bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        }
10646bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
1065cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos        if (aboutCardEntries.size() > 0) {
1066cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos            mAboutCard.initialize(aboutCardEntries,
1067cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    /* numInitialVisibleEntries = */ 1,
1068cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    /* isExpanded = */ true,
1069cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    /* isAlwaysExpanded = */ true,
1070cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    mExpandingEntryCardViewListener,
1071cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    mScroller);
1072cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos        }
10736095369885edcca566a812b551886e29c7ff8039Brian Attwell
10746095369885edcca566a812b551886e29c7ff8039Brian Attwell        if (contactCardEntries.size() == 0 && aboutCardEntries.size() == 0) {
10756095369885edcca566a812b551886e29c7ff8039Brian Attwell            initializeNoContactDetailCard();
10766095369885edcca566a812b551886e29c7ff8039Brian Attwell        } else {
10776095369885edcca566a812b551886e29c7ff8039Brian Attwell            mNoContactDetailsCard.setVisibility(View.GONE);
10786095369885edcca566a812b551886e29c7ff8039Brian Attwell        }
10796095369885edcca566a812b551886e29c7ff8039Brian Attwell
1080a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        // If the Recent card is already initialized (all recent data is loaded), show the About
1081a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        // card if it has entries. Otherwise About card visibility will be set in bindRecentData()
1082a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        if (isAllRecentDataLoaded() && aboutCardEntries.size() > 0) {
1083a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos            mAboutCard.setVisibility(View.VISIBLE);
1084a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        }
1085eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
1086eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
1087eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1088eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    /**
10896095369885edcca566a812b551886e29c7ff8039Brian Attwell     * Create a card that shows "Add email" and "Add phone number" entries in grey.
10906095369885edcca566a812b551886e29c7ff8039Brian Attwell     */
10916095369885edcca566a812b551886e29c7ff8039Brian Attwell    private void initializeNoContactDetailCard() {
10926095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Drawable phoneIcon = getResources().getDrawable(
10936095369885edcca566a812b551886e29c7ff8039Brian Attwell                R.drawable.ic_phone_24dp).mutate();
10946095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Entry phonePromptEntry = new Entry(CARD_ENTRY_ID_EDIT_CONTACT,
10956095369885edcca566a812b551886e29c7ff8039Brian Attwell                phoneIcon, getString(R.string.quickcontact_add_phone_number),
10968a3fe52802135be2402a5b216325615fb796a509Walter Jang                /* subHeader = */ null, /* subHeaderIcon = */ null, /* text = */ null,
10978a3fe52802135be2402a5b216325615fb796a509Walter Jang                /* textIcon = */ null, /* primaryContentDescription = */ null,
109823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                getEditContactIntent(),
1099dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                /* alternateIcon = */ null, /* alternateIntent = */ null,
1100714455bba22b99d168a2e864dfbc74a6e30dfdb6Paul Soulos                /* alternateContentDescription = */ null, /* shouldApplyColor = */ true,
110148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                /* isEditable = */ false, /* EntryContextMenuInfo = */ null,
110248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                /* thirdIcon = */ null, /* thirdIntent = */ null,
110348290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                /* thirdContentDescription = */ null, R.drawable.ic_phone_24dp);
11046095369885edcca566a812b551886e29c7ff8039Brian Attwell
11056095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Drawable emailIcon = getResources().getDrawable(
11066095369885edcca566a812b551886e29c7ff8039Brian Attwell                R.drawable.ic_email_24dp).mutate();
11076095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Entry emailPromptEntry = new Entry(CARD_ENTRY_ID_EDIT_CONTACT,
11086095369885edcca566a812b551886e29c7ff8039Brian Attwell                emailIcon, getString(R.string.quickcontact_add_email), /* subHeader = */ null,
11098a3fe52802135be2402a5b216325615fb796a509Walter Jang                /* subHeaderIcon = */ null,
11108a3fe52802135be2402a5b216325615fb796a509Walter Jang                /* text = */ null, /* textIcon = */ null, /* primaryContentDescription = */ null,
111123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                getEditContactIntent(), /* alternateIcon = */ null,
1112dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                /* alternateIntent = */ null, /* alternateContentDescription = */ null,
11132a4207fb39330e840436215c896cde911489e111Paul Soulos                /* shouldApplyColor = */ true, /* isEditable = */ false,
111448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                /* EntryContextMenuInfo = */ null, /* thirdIcon = */ null,
111548290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                /* thirdIntent = */ null, /* thirdContentDescription = */ null,
111648290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                R.drawable.ic_email_24dp);
11176095369885edcca566a812b551886e29c7ff8039Brian Attwell
11186095369885edcca566a812b551886e29c7ff8039Brian Attwell        final List<List<Entry>> promptEntries = new ArrayList<>();
11196095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.add(new ArrayList<Entry>(1));
11206095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.add(new ArrayList<Entry>(1));
11216095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.get(0).add(phonePromptEntry);
11226095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.get(1).add(emailPromptEntry);
11236095369885edcca566a812b551886e29c7ff8039Brian Attwell
11246095369885edcca566a812b551886e29c7ff8039Brian Attwell        final int subHeaderTextColor = getResources().getColor(
11256095369885edcca566a812b551886e29c7ff8039Brian Attwell                R.color.quickcontact_entry_sub_header_text_color);
11266095369885edcca566a812b551886e29c7ff8039Brian Attwell        final PorterDuffColorFilter greyColorFilter =
11276095369885edcca566a812b551886e29c7ff8039Brian Attwell                new PorterDuffColorFilter(subHeaderTextColor, PorterDuff.Mode.SRC_ATOP);
1128c8e2a91807b581194566eb45019fa16e2268b462Paul Soulos        mNoContactDetailsCard.initialize(promptEntries, 2, /* isExpanded = */ true,
11290cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                /* isAlwaysExpanded = */ true, mExpandingEntryCardViewListener, mScroller);
11306095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setVisibility(View.VISIBLE);
11316095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setEntryHeaderColor(subHeaderTextColor);
11326095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setColorAndFilter(subHeaderTextColor, greyColorFilter);
11336095369885edcca566a812b551886e29c7ff8039Brian Attwell    }
11346095369885edcca566a812b551886e29c7ff8039Brian Attwell
11356095369885edcca566a812b551886e29c7ff8039Brian Attwell    /**
1136eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * Builds the {@link DataItem}s Map out of the Contact.
1137eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @param data The contact to build the data from.
1138eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @return A pair containing a list of data items sorted within mimetype and sorted
1139eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     *  amongst mimetype. The map goes from mimetype string to the sorted list of data items within
1140eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     *  mimetype
1141eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     */
11426bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private Cp2DataCardModel generateDataModelFromContact(
1143eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            Contact data) {
1144eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("Build data items map");
1145eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1146eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final Map<String, List<DataItem>> dataItemsMap = new HashMap<>();
11478bf96e78497ea9c8c893bcb357fc1e3175fb2e9bBrian Attwell
11488a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final ResolveCache cache = ResolveCache.getInstance(this);
1149851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        for (RawContact rawContact : data.getRawContacts()) {
1150851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            for (DataItem dataItem : rawContact.getDataItems()) {
1151eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                dataItem.setRawContactId(rawContact.getId());
1152eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1153851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final String mimeType = dataItem.getMimeType();
1154eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (mimeType == null) continue;
1155eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
115647b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                final AccountType accountType = rawContact.getAccountType(this);
115747b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                final DataKind dataKind = AccountTypeManager.getInstance(this)
115847b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                        .getKindOrFallback(accountType, mimeType);
1159eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (dataKind == null) continue;
1160cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1161eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                dataItem.setDataKind(dataKind);
1162b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1163eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final boolean hasData = !TextUtils.isEmpty(dataItem.buildDataString(this,
1164eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        dataKind));
1165899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos
1166eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (isMimeExcluded(mimeType) || !hasData) continue;
1167edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1168eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                List<DataItem> dataItemListByType = dataItemsMap.get(mimeType);
1169eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (dataItemListByType == null) {
1170eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    dataItemListByType = new ArrayList<>();
1171eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    dataItemsMap.put(mimeType, dataItemListByType);
1172edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                }
1173eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                dataItemListByType.add(dataItem);
1174edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
1175edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
11768a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
1177edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1178eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("sort within mimetypes");
117916339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos        /*
118016339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos         * Sorting is a multi part step. The end result is to a have a sorted list of the most
1181eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos         * used data items, one per mimetype. Then, within each mimetype, the list of data items
1182eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos         * for that type is also sorted, based off of {super primary, primary, times used} in that
1183eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos         * order.
118416339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos         */
1185eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<List<DataItem>> dataItemsList = new ArrayList<>();
1186eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        for (List<DataItem> mimeTypeDataItems : dataItemsMap.values()) {
1187eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Remove duplicate data items
1188eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            Collapser.collapseList(mimeTypeDataItems, this);
1189eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Sort within mimetype
1190eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            Collections.sort(mimeTypeDataItems, mWithinMimeTypeDataItemComparator);
1191eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Add to the list of data item lists
1192eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            dataItemsList.add(mimeTypeDataItems);
1193edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
1194eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
1195edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1196eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("sort amongst mimetypes");
1197eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        // Sort amongst mimetypes to bubble up the top data items for the contact card
1198eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Collections.sort(dataItemsList, mAmongstMimeTypeDataItemComparator);
1199eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
120016339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos
12016bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        Trace.beginSection("cp2 data items to entries");
12026bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12036bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> contactCardEntries = new ArrayList<>();
12046bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> aboutCardEntries = buildAboutCardEntries(dataItemsMap);
12056bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final MutableString aboutCardName = new MutableString();
12066bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12076bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        for (int i = 0; i < dataItemsList.size(); ++i) {
12086bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final List<DataItem> dataItemsByMimeType = dataItemsList.get(i);
12096bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final DataItem topDataItem = dataItemsByMimeType.get(0);
12106bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            if (SORTED_ABOUT_CARD_MIMETYPES.contains(topDataItem.getMimeType())) {
12116bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                // About card mimetypes are built in buildAboutCardEntries, skip here
12126bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                continue;
12136bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            } else {
12146bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                List<Entry> contactEntries = dataItemsToEntries(dataItemsList.get(i),
12156bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        aboutCardName);
12166bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                if (contactEntries.size() > 0) {
12176bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                    contactCardEntries.add(contactEntries);
12186bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                }
12196bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            }
12206bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        }
12216bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12226bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        Trace.endSection();
12236bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12246bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final Cp2DataCardModel dataModel = new Cp2DataCardModel();
12256bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.customAboutCardName = aboutCardName.value;
12266bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.aboutCardEntries = aboutCardEntries;
12276bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.contactCardEntries = contactCardEntries;
12286bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.dataItemsMap = dataItemsMap;
12296bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        return dataModel;
12306bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    }
12316bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12326bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    /**
12336bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * Class used to hold the About card and Contact cards' data model that gets generated
12346bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * on a background thread. All data is from CP2.
12356bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     */
12366bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private static class Cp2DataCardModel {
12376bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        /**
12386bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell         * A map between a mimetype string and the corresponding list of data items. The data items
12396bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell         * are in sorted order using mWithinMimeTypeDataItemComparator.
12406bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell         */
12416bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public Map<String, List<DataItem>> dataItemsMap;
12426bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public List<List<Entry>> aboutCardEntries;
12436bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public List<List<Entry>> contactCardEntries;
12446bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public String customAboutCardName;
12456bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    }
12466bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12476bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private static class MutableString {
12486bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public String value;
1249eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
1250edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1251eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    /**
1252eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * Converts a {@link DataItem} into an {@link ExpandingEntryCardView.Entry} for display.
1253eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * If the {@link ExpandingEntryCardView.Entry} has no visual elements, null is returned.
12546bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     *
12556bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * This runs on a background thread. This is set as static to avoid accidentally adding
12566bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * additional dependencies on unsafe things (like the Activity).
12576bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     *
1258eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @param dataItem The {@link DataItem} to convert.
12596a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * @param secondDataItem A second {@link DataItem} to help build a full entry for some
12606a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     *  mimetypes
1261eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @return The {@link ExpandingEntryCardView.Entry}, or null if no visual elements are present.
1262eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     */
12636a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static Entry dataItemToEntry(DataItem dataItem, DataItem secondDataItem,
12646bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            Context context, Contact contactData,
12656bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final MutableString aboutCardName) {
1266eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Drawable icon = null;
1267eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String header = null;
1268eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String subHeader = null;
1269eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Drawable subHeaderIcon = null;
1270eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String text = null;
1271eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Drawable textIcon = null;
127223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        StringBuilder primaryContentDescription = new StringBuilder();
1273eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Intent intent = null;
127448ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos        boolean shouldApplyColor = true;
1275dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        Drawable alternateIcon = null;
1276dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        Intent alternateIntent = null;
127723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        StringBuilder alternateContentDescription = new StringBuilder();
1278eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final boolean isEditable = false;
12792a4207fb39330e840436215c896cde911489e111Paul Soulos        EntryContextMenuInfo entryContextMenuInfo = null;
128048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        Drawable thirdIcon = null;
128148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        Intent thirdIntent = null;
128248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        String thirdContentDescription = null;
128348290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos        int iconResourceId = 0;
1284eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
12856bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        context = context.getApplicationContext();
128623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        final Resources res = context.getResources();
1287eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        DataKind kind = dataItem.getDataKind();
1288eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1289eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (dataItem instanceof ImDataItem) {
1290eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final ImDataItem im = (ImDataItem) dataItem;
12916bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            intent = ContactsUtils.buildImIntent(context, im).first;
1292eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final boolean isEmail = im.isCreatedFromEmail();
12937de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            final int protocol;
12947de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            if (!im.isProtocolValid()) {
12957de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                protocol = Im.PROTOCOL_CUSTOM;
12967de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            } else {
12977de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : im.getProtocol();
12987de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            }
12997de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            if (protocol == Im.PROTOCOL_CUSTOM) {
13007de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                // If the protocol is custom, display the "IM" entry header as well to distinguish
13017de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                // this entry from other ones
130223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                header = res.getString(R.string.header_im_entry);
130323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                subHeader = Im.getProtocolLabel(res, protocol,
13047de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                        im.getCustomProtocol()).toString();
13057de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                text = im.getData();
13067de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            } else {
130723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                header = Im.getProtocolLabel(res, protocol,
13087de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                        im.getCustomProtocol()).toString();
13097de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                subHeader = im.getData();
13107de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            }
131197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(im.getData(), header,
131297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1313eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof OrganizationDataItem) {
1314eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final OrganizationDataItem organization = (OrganizationDataItem) dataItem;
131523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_organization_entry);
1316eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = organization.getCompany();
131797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
131897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1319eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            text = organization.getTitle();
1320eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof NicknameDataItem) {
1321eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final NicknameDataItem nickname = (NicknameDataItem) dataItem;
1322eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Build nickname entries
1323eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final boolean isNameRawContact =
13246bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                (contactData.getNameRawContactId() == dataItem.getRawContactId());
1325eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1326eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final boolean duplicatesTitle =
1327eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                isNameRawContact
13286bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                && contactData.getDisplayNameSource() == DisplayNameSources.NICKNAME;
1329eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1330eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!duplicatesTitle) {
133123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                header = res.getString(R.string.header_nickname_entry);
1332eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                subHeader = nickname.getName();
133397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
133497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1335eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1336eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof NoteDataItem) {
1337eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final NoteDataItem note = (NoteDataItem) dataItem;
133823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_note_entry);
1339eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = note.getNote();
134097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
134197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1342eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof WebsiteDataItem) {
1343eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final WebsiteDataItem website = (WebsiteDataItem) dataItem;
134423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_website_entry);
1345eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = website.getUrl();
134697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
134797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1348eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            try {
13496bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                final WebAddress webAddress = new WebAddress(website.buildDataString(context,
13506bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        kind));
1351eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_VIEW, Uri.parse(webAddress.toString()));
1352eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } catch (final ParseException e) {
13536bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                Log.e(TAG, "Couldn't parse website: " + website.buildDataString(context, kind));
1354eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1355eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof EventDataItem) {
1356eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final EventDataItem event = (EventDataItem) dataItem;
13576bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final String dataString = event.buildDataString(context, kind);
1358eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final Calendar cal = DateUtils.parseDate(dataString, false);
1359eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (cal != null) {
1360eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final Date nextAnniversary =
1361eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        DateUtils.getNextAnnualDate(cal);
1362eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
1363eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                builder.appendPath("time");
1364eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                ContentUris.appendId(builder, nextAnniversary.getTime());
1365eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_VIEW).setData(builder.build());
1366eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
136723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_event_entry);
1368f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            if (event.hasKindTypeColumn(kind)) {
136923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                subHeader = Event.getTypeLabel(res, event.getKindTypeColumn(kind),
13707de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                        event.getLabel()).toString();
1371f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            }
13726bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            text = DateUtils.formatDate(context, dataString);
137397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(text, header,
137497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1375eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof RelationDataItem) {
1376eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final RelationDataItem relation = (RelationDataItem) dataItem;
13776bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final String dataString = relation.buildDataString(context, kind);
1378eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(dataString)) {
1379eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_SEARCH);
1380eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent.putExtra(SearchManager.QUERY, dataString);
1381eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent.setType(Contacts.CONTENT_TYPE);
1382eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
138323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_relation_entry);
1384eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = relation.getName();
138597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
138697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1387f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            if (relation.hasKindTypeColumn(kind)) {
138823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                text = Relation.getTypeLabel(res,
13896bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        relation.getKindTypeColumn(kind),
1390f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                        relation.getLabel()).toString();
1391f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            }
1392eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof PhoneDataItem) {
1393eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final PhoneDataItem phone = (PhoneDataItem) dataItem;
1394eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(phone.getNumber())) {
139523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(res.getString(R.string.call_other)).append(" ");
1396c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell                header = sBidiFormatter.unicodeWrap(phone.buildDataString(context, kind),
1397c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell                        TextDirectionHeuristics.LTR);
13982a4207fb39330e840436215c896cde911489e111Paul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(header,
139997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        res.getString(R.string.phoneLabelsGroup), dataItem.getMimeType(),
140097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getId(), dataItem.isSuperPrimary());
1401f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                if (phone.hasKindTypeColumn(kind)) {
140223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    text = Phone.getTypeLabel(res, phone.getKindTypeColumn(kind),
1403f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                            phone.getLabel()).toString();
140423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(text).append(" ");
1405f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                }
140623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(header);
140723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                icon = res.getDrawable(R.drawable.ic_phone_24dp);
140848290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId = R.drawable.ic_phone_24dp;
14096bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                if (PhoneCapabilityTester.isPhone(context)) {
1410eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    intent = CallUtil.getCallIntent(phone.getNumber());
141116339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos                }
1412dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                alternateIntent = new Intent(Intent.ACTION_SENDTO,
14131cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                        Uri.fromParts(ContactsUtils.SCHEME_SMSTO, phone.getNumber(), null));
141448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
141523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateIcon = res.getDrawable(R.drawable.ic_message_24dp);
141623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.append(res.getString(R.string.sms_custom, header));
141748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
141848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                // Add video call button if supported
1419f764730a34da560db87206f9a48390d4c8085365Paul Soulos                if (CallUtil.isVideoEnabled(context)) {
142023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    thirdIcon = res.getDrawable(R.drawable.ic_videocam);
142148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    thirdIntent = CallUtil.getVideoCallIntent(phone.getNumber(),
142248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                            CALL_ORIGIN_QUICK_CONTACTS_ACTIVITY);
142348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    thirdContentDescription =
142423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                            res.getString(R.string.description_video_call);
142548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                }
1426eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1427eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof EmailDataItem) {
1428eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final EmailDataItem email = (EmailDataItem) dataItem;
1429eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String address = email.getData();
1430eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(address)) {
143123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(res.getString(R.string.email_other)).append(" ");
14321cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                final Uri mailUri = Uri.fromParts(ContactsUtils.SCHEME_MAILTO, address, null);
1433eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_SENDTO, mailUri);
1434eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                header = email.getAddress();
14352a4207fb39330e840436215c896cde911489e111Paul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(header,
143697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        res.getString(R.string.emailLabelsGroup), dataItem.getMimeType(),
143797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getId(), dataItem.isSuperPrimary());
1438f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                if (email.hasKindTypeColumn(kind)) {
143923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    text = Email.getTypeLabel(res, email.getKindTypeColumn(kind),
1440f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                            email.getLabel()).toString();
144123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(text).append(" ");
1442f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                }
144323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(header);
144423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                icon = res.getDrawable(R.drawable.ic_email_24dp);
144548290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId = R.drawable.ic_email_24dp;
1446eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1447eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof StructuredPostalDataItem) {
1448eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            StructuredPostalDataItem postal = (StructuredPostalDataItem) dataItem;
1449eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String postalAddress = postal.getFormattedAddress();
1450eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(postalAddress)) {
145123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(res.getString(R.string.map_other)).append(" ");
1452eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = StructuredPostalUtils.getViewPostalAddressIntent(postalAddress);
1453eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                header = postal.getFormattedAddress();
14542a4207fb39330e840436215c896cde911489e111Paul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(header,
145597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        res.getString(R.string.postalLabelsGroup), dataItem.getMimeType(),
145697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getId(), dataItem.isSuperPrimary());
1457f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                if (postal.hasKindTypeColumn(kind)) {
145823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    text = StructuredPostal.getTypeLabel(res,
1459f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                            postal.getKindTypeColumn(kind), postal.getLabel()).toString();
146023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(text).append(" ");
1461f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                }
146223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(header);
14636a4d2736d772cc5cbb79d04e115f2d6117826860Paul Soulos                alternateIntent =
14646a4d2736d772cc5cbb79d04e115f2d6117826860Paul Soulos                        StructuredPostalUtils.getViewPostalAddressDirectionsIntent(postalAddress);
146523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateIcon = res.getDrawable(R.drawable.ic_directions_24dp);
146623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.append(res.getString(
146723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                        R.string.content_description_directions)).append(" ").append(header);
146823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                icon = res.getDrawable(R.drawable.ic_place_24dp);
146948290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId = R.drawable.ic_place_24dp;
1470eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1471eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof SipAddressDataItem) {
1472593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell            final SipAddressDataItem sip = (SipAddressDataItem) dataItem;
1473593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell            final String address = sip.getSipAddress();
1474593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell            if (!TextUtils.isEmpty(address)) {
1475593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                primaryContentDescription.append(res.getString(R.string.call_other)).append(
1476593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                        " ");
1477593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                if (PhoneCapabilityTester.isSipPhone(context)) {
14781cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                    final Uri callUri = Uri.fromParts(PhoneAccount.SCHEME_SIP, address, null);
1479eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    intent = CallUtil.getCallIntent(callUri);
148016339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos                }
1481593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                header = address;
1482593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                entryContextMenuInfo = new EntryContextMenuInfo(header,
1483593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                        res.getString(R.string.phoneLabelsGroup), dataItem.getMimeType(),
1484593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                        dataItem.getId(), dataItem.isSuperPrimary());
1485593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                if (sip.hasKindTypeColumn(kind)) {
1486593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                    text = SipAddress.getTypeLabel(res,
1487593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                            sip.getKindTypeColumn(kind), sip.getLabel()).toString();
1488593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                    primaryContentDescription.append(text).append(" ");
1489593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                }
1490593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                primaryContentDescription.append(header);
1491593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                icon = res.getDrawable(R.drawable.ic_dialer_sip_black_24dp);
1492593e5a7f2551b7946ada9913408f649e530202c8Brian Attwell                iconResourceId = R.drawable.ic_dialer_sip_black_24dp;
1493edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
1494eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof StructuredNameDataItem) {
1495eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String givenName = ((StructuredNameDataItem) dataItem).getGivenName();
1496eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(givenName)) {
149723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                aboutCardName.value = res.getString(R.string.about_card_title) +
14986bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        " " + givenName;
1499eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else {
150023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                aboutCardName.value = res.getString(R.string.about_card_title);
1501eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1502eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else {
1503eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Custom DataItem
15046bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            header = dataItem.buildDataStringForDisplay(context, kind);
1505eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            text = kind.typeColumn;
1506eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            intent = new Intent(Intent.ACTION_VIEW);
150760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            final Uri uri = ContentUris.withAppendedId(Data.CONTENT_URI, dataItem.getId());
150860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            intent.setDataAndType(uri, dataItem.getMimeType());
1509e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos
1510e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            if (intent != null) {
1511e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                final String mimetype = intent.getType();
1512e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos
15136a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                // Build advanced entry for known 3p types. Otherwise default to ResolveCache icon.
1514e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                switch (mimetype) {
1515e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                    case MIMETYPE_GPLUS_PROFILE:
15166a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // If a secondDataItem is available, use it to build an entry with
15176a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // alternate actions
15186a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        if (secondDataItem != null) {
151923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                            icon = res.getDrawable(R.drawable.ic_google_plus_24dp);
15206a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            alternateIcon = res.getDrawable(R.drawable.ic_add_to_circles_black_24);
15216a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            final GPlusOrHangoutsDataItemModel itemModel =
15226a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                    new GPlusOrHangoutsDataItemModel(intent, alternateIntent,
15236a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            dataItem, secondDataItem, alternateContentDescription,
15246a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            header, text, context);
15256a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
152697b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            populateGPlusOrHangoutsDataItemModel(itemModel);
152797b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            intent = itemModel.intent;
152897b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateIntent = itemModel.alternateIntent;
152997b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateContentDescription = itemModel.alternateContentDescription;
153097b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            header = itemModel.header;
153197b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            text = itemModel.text;
15326a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        } else {
15336a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            if (GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE.equals(
15346a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                    intent.getDataString())) {
15356a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_add_to_circles_black_24);
15366a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            } else {
15376a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_google_plus_24dp);
15386a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            }
1539e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        }
1540e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        break;
1541e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                    case MIMETYPE_HANGOUTS:
15426a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // If a secondDataItem is available, use it to build an entry with
15436a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // alternate actions
15446a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        if (secondDataItem != null) {
154523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                            icon = res.getDrawable(R.drawable.ic_hangout_24dp);
15466a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            alternateIcon = res.getDrawable(R.drawable.ic_hangout_video_24dp);
154797b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            final GPlusOrHangoutsDataItemModel itemModel =
15486a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                    new GPlusOrHangoutsDataItemModel(intent, alternateIntent,
15496a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            dataItem, secondDataItem, alternateContentDescription,
15506a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            header, text, context);
15516a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
155297b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            populateGPlusOrHangoutsDataItemModel(itemModel);
155397b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            intent = itemModel.intent;
155497b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateIntent = itemModel.alternateIntent;
155597b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateContentDescription = itemModel.alternateContentDescription;
155697b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            header = itemModel.header;
155797b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            text = itemModel.text;
15586a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        } else {
15596a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            if (HANGOUTS_DATA_5_VIDEO.equals(intent.getDataString())) {
15606a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_hangout_video_24dp);
15616a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            } else {
15626a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_hangout_24dp);
15636a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            }
1564e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        }
1565e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        break;
1566e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                    default:
156797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        entryContextMenuInfo = new EntryContextMenuInfo(header, mimetype,
156897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                                dataItem.getMimeType(), dataItem.getId(),
156997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                                dataItem.isSuperPrimary());
15706bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        icon = ResolveCache.getInstance(context).getIcon(
1571e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                                dataItem.getMimeType(), intent);
1572e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        // Call mutate to create a new Drawable.ConstantState for color filtering
1573e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        if (icon != null) {
1574e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                            icon.mutate();
1575e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        }
157648ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                        shouldApplyColor = false;
1577e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                }
1578e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            }
1579eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1580b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1581eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (intent != null) {
1582eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Do not set the intent is there are no resolves
15836bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            if (!PhoneCapabilityTester.isIntentRegistered(context, intent)) {
1584eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = null;
1585eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1586eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1587eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1588dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        if (alternateIntent != null) {
1589dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            // Do not set the alternate intent is there are no resolves
15906bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            if (!PhoneCapabilityTester.isIntentRegistered(context, alternateIntent)) {
1591dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                alternateIntent = null;
1592f0d04c11b649e953177e79722d05fa048e53273dJay Shrauner            } else if (TextUtils.isEmpty(alternateContentDescription)) {
1593f0d04c11b649e953177e79722d05fa048e53273dJay Shrauner                // Attempt to use package manager to find a suitable content description if needed
159423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.append(getIntentResolveLabel(alternateIntent, context));
1595dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            }
1596dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
1597dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1598eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        // If the Entry has no visual elements, return null
1599eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (icon == null && TextUtils.isEmpty(header) && TextUtils.isEmpty(subHeader) &&
1600eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                subHeaderIcon == null && TextUtils.isEmpty(text) && textIcon == null) {
1601eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            return null;
1602eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1603eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1604fa238949855fba3b28a57fad3d585b13e80362bbBrian Attwell        // Ignore dataIds from the Me profile.
1605ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos        final int dataId = dataItem.getId() > Integer.MAX_VALUE ?
1606ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                -1 : (int) dataItem.getId();
1607ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
160823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        return new Entry(dataId, icon, header, subHeader, subHeaderIcon, text, textIcon,
160923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.toString(), intent, alternateIcon, alternateIntent,
161023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.toString(), shouldApplyColor, isEditable,
161148290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                entryContextMenuInfo, thirdIcon, thirdIntent, thirdContentDescription,
161248290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId);
1613eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
1614eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
16156bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private List<Entry> dataItemsToEntries(List<DataItem> dataItems,
16166bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            MutableString aboutCardTitleOut) {
16176a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Hangouts and G+ use two data items to create one entry.
16186a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        if (dataItems.get(0).getMimeType().equals(MIMETYPE_GPLUS_PROFILE) ||
16196a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataItems.get(0).getMimeType().equals(MIMETYPE_HANGOUTS)) {
16206a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            return gPlusOrHangoutsDataItemsToEntries(dataItems);
16216a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        } else {
16226a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            final List<Entry> entries = new ArrayList<>();
16236a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            for (DataItem dataItem : dataItems) {
16246a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                final Entry entry = dataItemToEntry(dataItem, /* secondDataItem = */ null,
16256a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        this, mContactData, aboutCardTitleOut);
16266a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                if (entry != null) {
16276a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    entries.add(entry);
16286a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                }
16296a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            }
16306a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            return entries;
16316a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
16326a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    }
16336a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
16346a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    /**
16356a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * G+ and Hangout entries are unique in that a single ExpandingEntryCardView.Entry consists
16366a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * of two data items. This method attempts to build each entry using the two data items if
16376a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * they are available. If there are more or less than two data items, a fall back is used
16386a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * and each data item gets its own entry.
16396a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     */
16406a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private List<Entry> gPlusOrHangoutsDataItemsToEntries(List<DataItem> dataItems) {
1641eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<Entry> entries = new ArrayList<>();
16426a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        final Map<Long, List<DataItem>> buckets = new HashMap<>();
16436a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Put the data items into buckets based on the raw contact id
1644eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        for (DataItem dataItem : dataItems) {
16456a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            List<DataItem> bucket = buckets.get(dataItem.getRawContactId());
16466a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            if (bucket == null) {
16476a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                bucket = new ArrayList<>();
16486a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                buckets.put(dataItem.getRawContactId(), bucket);
16496a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            }
16506a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            bucket.add(dataItem);
16516a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
16526a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
16536a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Use the buckets to build entries. If a bucket contains two data items, build the special
16546a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // entry, otherwise fall back to the normal entry.
16556a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        for (List<DataItem> bucket : buckets.values()) {
16566a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            if (bucket.size() == 2) {
16576a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                // Use the pair to build an entry
16586a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                final Entry entry = dataItemToEntry(bucket.get(0),
16596a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        /* secondDataItem = */ bucket.get(1), this, mContactData,
16606a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        /* aboutCardName = */ null);
16616a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                if (entry != null) {
16626a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    entries.add(entry);
16636a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                }
16646a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            } else {
16656a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                for (DataItem dataItem : bucket) {
16666a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    final Entry entry = dataItemToEntry(dataItem, /* secondDataItem = */ null,
16676a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            this, mContactData, /* aboutCardName = */ null);
16686a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    if (entry != null) {
16696a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        entries.add(entry);
16706a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    }
16716a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                }
1672eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1673eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1674eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        return entries;
1675edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
1676edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
16776a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    /**
16786a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * Used for statically passing around G+ or Hangouts data items and entry fields to
16796a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * populateGPlusOrHangoutsDataItemModel.
16806a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     */
16816a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final class GPlusOrHangoutsDataItemModel {
16826a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public Intent intent;
16836a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public Intent alternateIntent;
16846a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public DataItem dataItem;
16856a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public DataItem secondDataItem;
16866a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public StringBuilder alternateContentDescription;
16876a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public String header;
16886a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public String text;
16896a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public Context context;
16906a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
16916a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public GPlusOrHangoutsDataItemModel(Intent intent, Intent alternateIntent, DataItem dataItem,
16926a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                DataItem secondDataItem, StringBuilder alternateContentDescription, String header,
16936a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                String text, Context context) {
16946a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.intent = intent;
16956a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.alternateIntent = alternateIntent;
16966a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.dataItem = dataItem;
16976a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.secondDataItem = secondDataItem;
16986a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.alternateContentDescription = alternateContentDescription;
16996a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.header = header;
17006a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.text = text;
17016a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.context = context;
17026a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
17036a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    }
17046a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
17056a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static void populateGPlusOrHangoutsDataItemModel(
17066a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            GPlusOrHangoutsDataItemModel dataModel) {
17076a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        final Intent secondIntent = new Intent(Intent.ACTION_VIEW);
17086a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        secondIntent.setDataAndType(ContentUris.withAppendedId(Data.CONTENT_URI,
17096a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataModel.secondDataItem.getId()), dataModel.secondDataItem.getMimeType());
17106a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // There is no guarantee the order the data items come in. Second
17116a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // data item does not necessarily mean it's the alternate.
17126a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Hangouts video and Add to circles should be alternate. Swap if needed
17136a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        if (HANGOUTS_DATA_5_VIDEO.equals(
17146a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataModel.dataItem.getContentValues().getAsString(Data.DATA5)) ||
17156a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE.equals(
17166a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
17176a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateIntent = dataModel.intent;
17186a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateContentDescription = new StringBuilder(dataModel.header);
17196a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
17206a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.intent = secondIntent;
17216a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.header = dataModel.secondDataItem.buildDataStringForDisplay(dataModel.context,
17226a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    dataModel.secondDataItem.getDataKind());
17236a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.text = dataModel.secondDataItem.getDataKind().typeColumn;
17246a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        } else if (HANGOUTS_DATA_5_MESSAGE.equals(
17256a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataModel.dataItem.getContentValues().getAsString(Data.DATA5)) ||
17266a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                GPLUS_PROFILE_DATA_5_VIEW_PROFILE.equals(
17276a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
17286a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateIntent = secondIntent;
17296a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateContentDescription = new StringBuilder(
17306a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    dataModel.secondDataItem.buildDataStringForDisplay(dataModel.context,
17316a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            dataModel.secondDataItem.getDataKind()));
17326a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
17336a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    }
17346a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
17356bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private static String getIntentResolveLabel(Intent intent, Context context) {
17366bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<ResolveInfo> matches = context.getPackageManager().queryIntentActivities(intent,
1737dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                PackageManager.MATCH_DEFAULT_ONLY);
1738dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1739dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        // Pick first match, otherwise best found
1740dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        ResolveInfo bestResolve = null;
1741dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final int size = matches.size();
1742dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        if (size == 1) {
1743dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            bestResolve = matches.get(0);
1744dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        } else if (size > 1) {
17456bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            bestResolve = ResolveCache.getInstance(context).getBestResolve(intent, matches);
1746dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
1747dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1748dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        if (bestResolve == null) {
1749dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            return null;
1750dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
1751dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
17526bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        return String.valueOf(bestResolve.loadLabel(context.getPackageManager()));
1753dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos    }
1754dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1755edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
175631b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     * Asynchronously extract the most vibrant color from the PhotoView. Once extracted,
175731b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     * apply this tint to {@link MultiShrinkScroller}. This operation takes about 20-30ms
175831b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     * on a Nexus 5.
175931b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     */
176031b2d42fb0889e61515d27314aa5a245147100daBrian Attwell    private void extractAndApplyTintFromPhotoViewAsynchronously() {
176131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        if (mScroller == null) {
176231b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            return;
176331b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        }
176431b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        final Drawable imageViewDrawable = mPhotoView.getDrawable();
1765faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        new AsyncTask<Void, Void, MaterialPalette>() {
176631b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            @Override
1767faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell            protected MaterialPalette doInBackground(Void... params) {
1768faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell
176995c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                if (imageViewDrawable instanceof BitmapDrawable
177095c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        && mContactData.getThumbnailPhotoBinaryData() != null
177195c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        && mContactData.getThumbnailPhotoBinaryData().length > 0) {
177295c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    // Perform the color analysis on the thumbnail instead of the full sized
177395c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    // image, so that our results will be as similar as possible to the Bugle
177495c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    // app.
177595c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    final Bitmap bitmap = BitmapFactory.decodeByteArray(
177695c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                            mContactData.getThumbnailPhotoBinaryData(), 0,
177795c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                            mContactData.getThumbnailPhotoBinaryData().length);
177895c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    try {
177995c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        final int primaryColor = colorFromBitmap(bitmap);
178095c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        if (primaryColor != 0) {
178195c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                            return mMaterialColorMapUtils.calculatePrimaryAndSecondaryColor(
178295c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                                    primaryColor);
178395c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        }
178495c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    } finally {
178595c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        bitmap.recycle();
1786faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                    }
17878a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                }
17888a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                if (imageViewDrawable instanceof LetterTileDrawable) {
1789faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                    final int primaryColor = ((LetterTileDrawable) imageViewDrawable).getColor();
1790a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                    return mMaterialColorMapUtils.calculatePrimaryAndSecondaryColor(primaryColor);
179131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell                }
1792a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                return MaterialColorMapUtils.getDefaultPrimaryAndSecondaryColors(getResources());
179331b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            }
179431b2d42fb0889e61515d27314aa5a245147100daBrian Attwell
179531b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            @Override
1796faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell            protected void onPostExecute(MaterialPalette palette) {
1797faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                super.onPostExecute(palette);
17988571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                if (mHasComputedThemeColor) {
17998571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // If we had previously computed a theme color from the contact photo,
18008571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // then do not update the theme color. Changing the theme color several
18018571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // seconds after QC has started, as a result of an updated/upgraded photo,
18028571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // is a jarring experience. On the other hand, changing the theme color after
18038571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // a rotation or onNewIntent() is perfectly fine.
18048571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    return;
18058571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                }
18068571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                // Check that the Photo has not changed. If it has changed, the new tint
18078571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                // color needs to be extracted
18088571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                if (imageViewDrawable == mPhotoView.getDrawable()) {
18098571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    mHasComputedThemeColor = true;
1810faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                    setThemeColor(palette);
181131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell                }
181231b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            }
181331b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        }.execute();
181431b2d42fb0889e61515d27314aa5a245147100daBrian Attwell    }
181531b2d42fb0889e61515d27314aa5a245147100daBrian Attwell
18164936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell    /**
18174936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell     * Examine how many white pixels are in the bitmap in order to determine whether or not
18184936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell     * we need gradient overlays on top of the image.
18194936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell     */
18204936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell    private void analyzeWhitenessOfPhotoAsynchronously() {
18214936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        final Drawable imageViewDrawable = mPhotoView.getDrawable();
18224936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        new AsyncTask<Void, Void, Boolean>() {
18234936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            @Override
18244936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            protected Boolean doInBackground(Void... params) {
18254936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                if (imageViewDrawable instanceof BitmapDrawable) {
18264936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                    final Bitmap bitmap = ((BitmapDrawable) imageViewDrawable).getBitmap();
18274936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                    return WhitenessUtils.isBitmapWhiteAtTopOrBottom(bitmap);
18284936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                }
18294936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                return !(imageViewDrawable instanceof LetterTileDrawable);
18304936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            }
18314936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell
18324936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            @Override
18334936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            protected void onPostExecute(Boolean isWhite) {
18344936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                super.onPostExecute(isWhite);
18354936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                mScroller.setUseGradient(isWhite);
18364936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            }
18374936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        }.execute();
18384936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell    }
18394936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell
1840faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell    private void setThemeColor(MaterialPalette palette) {
18419b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        // If the color is invalid, use the predefined default
1842faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        final int primaryColor = palette.mPrimaryColor;
1843faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mScroller.setHeaderTintColor(primaryColor);
1844faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mStatusBarColor = palette.mSecondaryColor;
18459b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        updateStatusBarColor();
18468571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell
18479b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        mColorFilter =
1848faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                new PorterDuffColorFilter(primaryColor, PorterDuff.Mode.SRC_ATOP);
1849faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mContactCard.setColorAndFilter(primaryColor, mColorFilter);
1850faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mRecentCard.setColorAndFilter(primaryColor, mColorFilter);
1851faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mAboutCard.setColorAndFilter(primaryColor, mColorFilter);
18529b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    }
18539b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
18548a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private void updateStatusBarColor() {
18558a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mScroller == null) {
18568a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            return;
18578a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
18588a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final int desiredStatusBarColor;
18598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // Only use a custom status bar color if QuickContacts touches the top of the viewport.
18608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mScroller.getScrollNeededToBeFullScreen() <= 0) {
18618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            desiredStatusBarColor = mStatusBarColor;
18628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        } else {
18638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            desiredStatusBarColor = Color.TRANSPARENT;
18648a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
18658a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // Animate to the new color.
1866847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        final ObjectAnimator animation = ObjectAnimator.ofInt(getWindow(), "statusBarColor",
1867847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell                getWindow().getStatusBarColor(), desiredStatusBarColor);
1868847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        animation.setDuration(ANIMATION_STATUS_BAR_COLOR_CHANGE_DURATION);
1869847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        animation.setEvaluator(new ArgbEvaluator());
1870847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        animation.start();
18718a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
18728a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
18738a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private int colorFromBitmap(Bitmap bitmap) {
18748a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // Author of Palette recommends using 24 colors when analyzing profile photos.
18758a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final int NUMBER_OF_PALETTE_COLORS = 24;
18768a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final Palette palette = Palette.generate(bitmap, NUMBER_OF_PALETTE_COLORS);
1877a0f20f77e1b4f6cde5934d8b3348d93b58fd6362Brian Attwell        if (palette != null && palette.getVibrantSwatch() != null) {
1878a0f20f77e1b4f6cde5934d8b3348d93b58fd6362Brian Attwell            return palette.getVibrantSwatch().getRgb();
18798a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
18808a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        return 0;
18818a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
18828a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1883b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private List<Entry> contactInteractionsToEntries(List<ContactInteraction> interactions) {
1884eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<Entry> entries = new ArrayList<>();
1885b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        for (ContactInteraction interaction : interactions) {
1886ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            entries.add(new Entry(/* id = */ -1,
1887ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                    interaction.getIcon(this),
1888b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getViewHeader(this),
1889b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getViewBody(this),
1890b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getBodyIcon(this),
1891b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getViewFooter(this),
1892b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getFooterIcon(this),
189323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    interaction.getContentDescription(this),
1894b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getIntent(),
1895dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    /* alternateIcon = */ null,
1896dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    /* alternateIntent = */ null,
1897dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    /* alternateContentDescription = */ null,
189848ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                    /* shouldApplyColor = */ true,
18992a4207fb39330e840436215c896cde911489e111Paul Soulos                    /* isEditable = */ false,
190048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* EntryContextMenuInfo = */ null,
190148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIcon = */ null,
190248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIntent = */ null,
190348290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    /* thirdContentDescription = */ null,
190448290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    interaction.getIconResourceId()));
1905b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
1906b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        return entries;
1907b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    }
1908b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1909eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final LoaderCallbacks<Contact> mLoaderContactCallbacks =
1910851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            new LoaderCallbacks<Contact>() {
1911cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
1912851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoaderReset(Loader<Contact> loader) {
1913405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos            mContactData = null;
1914cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
1915cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1916cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
1917851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoadFinished(Loader<Contact> loader, Contact data) {
19188a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            Trace.beginSection("onLoadFinished()");
1919930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell            try {
19208a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1921930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                if (isFinishing()) {
1922930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    return;
1923930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                }
1924930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                if (data.isError()) {
1925930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    // This shouldn't ever happen, so throw an exception. The {@link ContactLoader}
1926930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    // should log the actual exception.
1927930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    throw new IllegalStateException("Failed to load contact", data.getException());
1928930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                }
1929930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                if (data.isNotFound()) {
19308a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    Log.i(TAG, "No contact found: " + ((ContactLoader)loader).getLookupUri());
19318a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    Toast.makeText(QuickContactActivity.this, R.string.invalidContactMessage,
19328a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                            Toast.LENGTH_LONG).show();
1933930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    finish();
1934930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    return;
19358a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                }
1936cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1937930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                bindContactData(data);
1938cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1939930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell            } finally {
1940930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                Trace.endSection();
1941930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell            }
1942cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
1943cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1944cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
1945851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public Loader<Contact> onCreateLoader(int id, Bundle args) {
1946cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (mLookupUri == null) {
1947cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                Log.wtf(TAG, "Lookup uri wasn't initialized. Loader was started too early");
1948cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
1949d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Load all contact data. We need loadGroupMetaData=true to determine whether the
1950d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // contact is invisible. If it is, we need to display an "Add to Contacts" MenuItem.
1951b2b435a944947fbf1965c3bb7c202a97f0273259Yorke Lee            return new ContactLoader(getApplicationContext(), mLookupUri,
1952d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    true /*loadGroupMetaData*/, false /*loadInvitableAccountTypes*/,
19538571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    true /*postViewNotification*/, true /*computeFormattedPhoneNumber*/);
1954cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
1955cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann    };
1956b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1957b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    @Override
1958b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    public void onBackPressed() {
1959b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        if (mScroller != null) {
19608477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            if (!mIsExitAnimationInProgress) {
19618477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell                mScroller.scrollOffBottom();
19628477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            }
1963b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        } else {
1964b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell            super.onBackPressed();
1965b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        }
1966b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    }
1967b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
19688a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    @Override
19698a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    public void finish() {
19708a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.finish();
19718a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
19728a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // override transitions to skip the standard window animations
19738a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        overridePendingTransition(0, 0);
19748a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
19758a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1976eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final LoaderCallbacks<List<ContactInteraction>> mLoaderInteractionsCallbacks =
1977b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            new LoaderCallbacks<List<ContactInteraction>>() {
1978b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1979b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        @Override
1980b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        public Loader<List<ContactInteraction>> onCreateLoader(int id, Bundle args) {
1981b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            Loader<List<ContactInteraction>> loader = null;
1982b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            switch (id) {
1983b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                case LOADER_SMS_ID:
1984b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    loader = new SmsInteractionsLoader(
1985b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                            QuickContactActivity.this,
1986ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            args.getStringArray(KEY_LOADER_EXTRA_PHONES),
1987b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                            MAX_SMS_RETRIEVE);
1988b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    break;
1989899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                case LOADER_CALENDAR_ID:
1990ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    final String[] emailsArray = args.getStringArray(KEY_LOADER_EXTRA_EMAILS);
1991ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    List<String> emailsList = null;
1992ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    if (emailsArray != null) {
1993ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                        emailsList = Arrays.asList(args.getStringArray(KEY_LOADER_EXTRA_EMAILS));
1994ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    }
1995899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                    loader = new CalendarInteractionsLoader(
1996899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            QuickContactActivity.this,
1997ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                            emailsList,
1998899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            MAX_FUTURE_CALENDAR_RETRIEVE,
1999899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            MAX_PAST_CALENDAR_RETRIEVE,
2000899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            FUTURE_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR,
2001899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            PAST_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR);
2002899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                    break;
2003ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                case LOADER_CALL_LOG_ID:
2004ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                    loader = new CallLogInteractionsLoader(
2005ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            QuickContactActivity.this,
2006ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            args.getStringArray(KEY_LOADER_EXTRA_PHONES),
2007ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            MAX_CALL_LOG_RETRIEVE);
2008b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            }
2009b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            return loader;
2010b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
2011b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2012b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        @Override
2013b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        public void onLoadFinished(Loader<List<ContactInteraction>> loader,
2014b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                List<ContactInteraction> data) {
2015b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            mRecentLoaderResults.put(loader.getId(), data);
2016b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2017b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            if (isAllRecentDataLoaded()) {
2018b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                bindRecentData();
2019b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            }
2020b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
2021b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2022b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        @Override
2023b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        public void onLoaderReset(Loader<List<ContactInteraction>> loader) {
2024b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            mRecentLoaderResults.remove(loader.getId());
2025b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
2026b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    };
2027b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2028b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private boolean isAllRecentDataLoaded() {
2029b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        return mRecentLoaderResults.size() == mRecentLoaderIds.length;
2030b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    }
2031b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2032b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private void bindRecentData() {
2033eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<ContactInteraction> allInteractions = new ArrayList<>();
203430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        final List<List<Entry>> interactionsWrapper = new ArrayList<>();
2035b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
203630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        mRecentDataTask = new AsyncTask<Void, Void, Void>() {
2037b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            @Override
203830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            protected Void doInBackground(Void... params) {
203930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.beginSection("sort recent loader results");
204030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
204130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                for (List<ContactInteraction> loaderInteractions : mRecentLoaderResults.values()) {
204230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    allInteractions.addAll(loaderInteractions);
204330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
204430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
204530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // Sort the interactions by most recent
204630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Collections.sort(allInteractions, new Comparator<ContactInteraction>() {
204730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    @Override
204830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    public int compare(ContactInteraction a, ContactInteraction b) {
204930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                        return a.getInteractionDate() >= b.getInteractionDate() ? -1 : 1;
205030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    }
205130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                });
205230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
205330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.endSection();
205430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.beginSection("contactInteractionsToEntries");
205530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
205630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // Wrap each interaction in its own list so that an icon is displayed for each entry
205730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                for (Entry contactInteraction : contactInteractionsToEntries(allInteractions)) {
205830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    List<Entry> entryListWrapper = new ArrayList<>(1);
205930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    entryListWrapper.add(contactInteraction);
206030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    interactionsWrapper.add(entryListWrapper);
206130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
206230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
206330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.endSection();
206430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                return null;
2065b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            }
206630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
206730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            @Override
206830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            protected void onPostExecute(Void aVoid) {
206930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                super.onPostExecute(aVoid);
207030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.beginSection("initialize recents card");
207130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
207230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                if (allInteractions.size() > 0) {
207330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mRecentCard.initialize(interactionsWrapper,
2074b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    /* numInitialVisibleEntries = */ MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN,
2075c8e2a91807b581194566eb45019fa16e2268b462Paul Soulos                    /* isExpanded = */ mRecentCard.isExpanded(), /* isAlwaysExpanded = */ false,
207630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                            mExpandingEntryCardViewListener, mScroller);
207730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mRecentCard.setVisibility(View.VISIBLE);
207830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
2079eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
208030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.endSection();
208130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
208230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // About card is initialized along with the contact card, but since it appears after
208330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // the recent card in the UI, we hold off until making it visible until the recent
208430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // card is also ready to avoid stuttering.
208530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                if (mAboutCard.shouldShow()) {
208630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mAboutCard.setVisibility(View.VISIBLE);
208730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                } else {
208830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mAboutCard.setVisibility(View.GONE);
208930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
209030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                mRecentDataTask = null;
209130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            }
209230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        };
209330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        mRecentDataTask.execute();
2094b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    }
20958a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
20968a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    @Override
20978a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    protected void onStop() {
20988a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.onStop();
20998a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
21008a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mEntriesAndActionsTask != null) {
21018a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // Once the activity is stopped, we will no longer want to bind mEntriesAndActionsTask's
21028a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // results on the UI thread. In some circumstances Activities are killed without
21038a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // onStop() being called. This is not a problem, because in these circumstances
21048a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // the entire process will be killed.
21058a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            mEntriesAndActionsTask.cancel(/* mayInterruptIfRunning = */ false);
21068a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
210730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        if (mRecentDataTask != null) {
210830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            mRecentDataTask.cancel(/* mayInterruptIfRunning = */ false);
210930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        }
21108a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
211123889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos
211223889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos    /**
2113d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     * Returns true if it is possible to edit the current contact.
2114d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     */
2115d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private boolean isContactEditable() {
2116d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        return mContactData != null && !mContactData.isDirectoryEntry();
2117d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2118d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2119a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell    /**
2120a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell     * Returns true if it is possible to share the current contact.
2121a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell     */
2122a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell    private boolean isContactShareable() {
2123a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell        return mContactData != null && !mContactData.isDirectoryEntry();
2124a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell    }
2125a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
21266095369885edcca566a812b551886e29c7ff8039Brian Attwell    private Intent getEditContactIntent() {
212763176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        final Intent intent = new Intent(Intent.ACTION_EDIT, mContactData.getLookupUri());
2128d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
21296095369885edcca566a812b551886e29c7ff8039Brian Attwell        return intent;
21306095369885edcca566a812b551886e29c7ff8039Brian Attwell    }
21316095369885edcca566a812b551886e29c7ff8039Brian Attwell
21326095369885edcca566a812b551886e29c7ff8039Brian Attwell    private void editContact() {
2133a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        mHasIntentLaunched = true;
2134c00a0b5370f0714f6af1ea9b3e29b10f25e91af0Zheng Fu        mContactLoader.cacheResult();
21356095369885edcca566a812b551886e29c7ff8039Brian Attwell        startActivityForResult(getEditContactIntent(), REQUEST_CODE_CONTACT_EDITOR_ACTIVITY);
2136d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2137d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2138d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private void toggleStar(MenuItem starredMenuItem) {
2139d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        // Make sure there is a contact
214063176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        if (mContactData != null) {
2141d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Read the current starred value from the UI instead of using the last
2142d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // loaded state. This allows rapid tapping without writing the same
2143d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // value several times
2144d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final boolean isStarred = starredMenuItem.isChecked();
2145d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2146d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // To improve responsiveness, swap out the picture (and tag) in the UI already
2147333091ae754ddfc25714c14b9b89534be24379f9Paul Soulos            ContactDisplayUtils.configureStarredMenuItem(starredMenuItem,
2148d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    mContactData.isDirectoryEntry(), mContactData.isUserProfile(),
2149d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    !isStarred);
2150d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2151d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Now perform the real save
2152eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final Intent intent = ContactSaveService.createSetStarredIntent(
215363176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell                    QuickContactActivity.this, mContactData.getLookupUri(), !isStarred);
2154d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            startService(intent);
215535ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell
215635ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            final CharSequence accessibilityText = !isStarred
215735ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell                    ? getResources().getText(R.string.description_action_menu_add_star)
215835ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell                    : getResources().getText(R.string.description_action_menu_remove_star);
215935ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            // Accessibility actions need to have an associated view. We can't access the MenuItem's
216035ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            // underlying view, so put this accessibility action on the root view.
216135ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            mScroller.announceForAccessibility(accessibilityText);
2162d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
2163d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2164d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2165752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    /**
2166752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     * Calls into the contacts provider to get a pre-authorized version of the given URI.
2167752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     */
2168752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private Uri getPreAuthorizedUri(Uri uri) {
2169752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Bundle uriBundle = new Bundle();
2170752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        uriBundle.putParcelable(ContactsContract.Authorization.KEY_URI_TO_AUTHORIZE, uri);
2171752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Bundle authResponse = getContentResolver().call(
2172752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                ContactsContract.AUTHORITY_URI,
2173752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                ContactsContract.Authorization.AUTHORIZATION_METHOD,
2174752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                null,
2175752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                uriBundle);
2176752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        if (authResponse != null) {
2177752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            return (Uri) authResponse.getParcelable(
2178752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    ContactsContract.Authorization.KEY_AUTHORIZED_URI);
2179752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        } else {
2180752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            return uri;
2181752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        }
2182752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    }
21832d150da246632b1649999cfabed776133b097775Brian Attwell
2184752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private void shareContact() {
2185752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final String lookupKey = mContactData.getLookupKey();
2186752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        Uri shareUri = Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, lookupKey);
2187752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        if (mContactData.isUserProfile()) {
2188752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            // User is sharing the profile.  We don't want to force the receiver to have
2189752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            // the highly-privileged READ_PROFILE permission, so we need to request a
2190752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            // pre-authorized URI from the provider.
2191752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            shareUri = getPreAuthorizedUri(shareUri);
2192752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        }
2193752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2194752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Intent intent = new Intent(Intent.ACTION_SEND);
2195752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        intent.setType(Contacts.CONTENT_VCARD_TYPE);
2196752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        intent.putExtra(Intent.EXTRA_STREAM, shareUri);
2197752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2198752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        // Launch chooser to share contact via
2199752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final CharSequence chooseTitle = getText(R.string.share_via);
2200752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Intent chooseIntent = Intent.createChooser(intent, chooseTitle);
2201752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2202752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        try {
2203a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            mHasIntentLaunched = true;
2204752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            this.startActivity(chooseIntent);
2205eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } catch (final ActivityNotFoundException ex) {
2206752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            Toast.makeText(this, R.string.share_error, Toast.LENGTH_SHORT).show();
2207752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        }
2208752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    }
2209752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2210752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    /**
2211752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     * Creates a launcher shortcut with the current contact.
2212752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     */
2213752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private void createLauncherShortcutWithContact() {
2214752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final ShortcutIntentBuilder builder = new ShortcutIntentBuilder(this,
2215752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                new OnShortcutIntentCreatedListener() {
2216752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2217752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    @Override
2218752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    public void onShortcutIntentCreated(Uri uri, Intent shortcutIntent) {
2219752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // Broadcast the shortcutIntent to the launcher to create a
2220752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // shortcut to this contact
2221752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        shortcutIntent.setAction(ACTION_INSTALL_SHORTCUT);
2222752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        QuickContactActivity.this.sendBroadcast(shortcutIntent);
2223752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2224752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // Send a toast to give feedback to the user that a shortcut to this
2225752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // contact was added to the launcher.
2226752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        Toast.makeText(QuickContactActivity.this,
2227752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                                R.string.createContactShortcutSuccessful,
2228752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                                Toast.LENGTH_SHORT).show();
2229752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    }
2230752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2231752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                });
223263176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        builder.createContactShortcutIntent(mContactData.getLookupUri());
2233752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    }
2234752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
223566965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell    private boolean isShortcutCreatable() {
223666965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        final Intent createShortcutIntent = new Intent();
223766965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        createShortcutIntent.setAction(ACTION_INSTALL_SHORTCUT);
223866965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        final List<ResolveInfo> receivers = getPackageManager()
223966965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell                .queryBroadcastReceivers(createShortcutIntent, 0);
224066965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        return receivers != null && receivers.size() > 0;
224166965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell    }
224266965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell
2243d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    @Override
2244d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public boolean onCreateOptionsMenu(Menu menu) {
2245eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final MenuInflater inflater = getMenuInflater();
2246d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        inflater.inflate(R.menu.quickcontact, menu);
2247d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        return true;
2248d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2249d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2250d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    @Override
2251d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public boolean onPrepareOptionsMenu(Menu menu) {
2252d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (mContactData != null) {
2253d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final MenuItem starredMenuItem = menu.findItem(R.id.menu_star);
2254333091ae754ddfc25714c14b9b89534be24379f9Paul Soulos            ContactDisplayUtils.configureStarredMenuItem(starredMenuItem,
2255d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    mContactData.isDirectoryEntry(), mContactData.isUserProfile(),
2256d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    mContactData.getStarred());
2257a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
2258d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Configure edit MenuItem
2259d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final MenuItem editMenuItem = menu.findItem(R.id.menu_edit);
2260d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            editMenuItem.setVisible(true);
2261d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            if (DirectoryContactUtil.isDirectoryContact(mContactData) || InvisibleContactUtil
2262d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    .isInvisibleAndAddable(mContactData, this)) {
226330cfd121ad8c8adb83cf417ff1d40a8ba1e3761dBrian Attwell                editMenuItem.setIcon(R.drawable.ic_person_add_tinted_24dp);
22642e4214c79170cdb6c1b8b6ff0408925d3f512becBrian Attwell                editMenuItem.setTitle(R.string.menu_add_contact);
2265d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            } else if (isContactEditable()) {
2266d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                editMenuItem.setIcon(R.drawable.ic_create_24dp);
22672e4214c79170cdb6c1b8b6ff0408925d3f512becBrian Attwell                editMenuItem.setTitle(R.string.menu_editContact);
2268d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            } else {
2269d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                editMenuItem.setVisible(false);
2270d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            }
2271a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
2272a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell            final MenuItem shareMenuItem = menu.findItem(R.id.menu_share);
2273a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell            shareMenuItem.setVisible(isContactShareable());
2274a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
227566965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell            final MenuItem shortcutMenuItem = menu.findItem(R.id.menu_create_contact_shortcut);
227666965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell            shortcutMenuItem.setVisible(isShortcutCreatable());
227766965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell
22788a6d0022b07640d4a1fb8b264c8822bbab2981adPaul Soulos            return true;
2279d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
22808a6d0022b07640d4a1fb8b264c8822bbab2981adPaul Soulos        return false;
2281d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2282d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2283d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    @Override
2284d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public boolean onOptionsItemSelected(MenuItem item) {
2285d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        switch (item.getItemId()) {
2286d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            case R.id.menu_star:
2287d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                toggleStar(item);
2288d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                return true;
2289d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            case R.id.menu_edit:
2290d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                if (DirectoryContactUtil.isDirectoryContact(mContactData)) {
2291ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // This action is used to launch the contact selector, with the option of
2292ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // creating a new contact. Creating a new contact is an INSERT, while selecting
2293ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // an exisiting one is an edit. The fields in the edit screen will be
2294ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // prepopulated with data.
2295ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2296ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
2297ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    intent.setType(Contacts.CONTENT_ITEM_TYPE);
2298ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2299fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    ArrayList<ContentValues> values = mContactData.getContentValues();
2300fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell
2301fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    // Only pre-fill the name field if the provided display name is an nickname
2302fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    // or better (e.g. structured name, nickname)
2303fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    if (mContactData.getDisplayNameSource() >= DisplayNameSources.NICKNAME) {
2304ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        intent.putExtra(Intents.Insert.NAME, mContactData.getDisplayName());
2305fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    } else if (mContactData.getDisplayNameSource()
2306fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                            == DisplayNameSources.ORGANIZATION) {
2307fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        // This is probably an organization. Instead of copying the organization
2308fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        // name into a name entry, copy it into the organization entry. This
2309fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        // way we will still consider the contact an organization.
2310fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        final ContentValues organization = new ContentValues();
2311fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        organization.put(Organization.COMPANY, mContactData.getDisplayName());
2312fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        organization.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
2313fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        values.add(organization);
2314ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    }
2315fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell
2316ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // Last time used and times used are aggregated values from the usage stat
2317ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // table. They need to be removed from data values so the SQL table can insert
2318ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // properly
2319ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    for (ContentValues value : values) {
2320ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        value.remove(Data.LAST_TIME_USED);
2321ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        value.remove(Data.TIMES_USED);
2322ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    }
2323ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    intent.putExtra(Intents.Insert.DATA, values);
2324ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2325ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // If the contact can only export to the same account, add it to the intent.
2326ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // Otherwise the ContactEditorFragment will show a dialog for selecting an
2327ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // account.
2328ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    if (mContactData.getDirectoryExportSupport() ==
2329ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                            Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY) {
2330ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        intent.putExtra(Intents.Insert.ACCOUNT,
2331ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                                new Account(mContactData.getDirectoryAccountName(),
2332ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                                        mContactData.getDirectoryAccountType()));
2333ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        intent.putExtra(Intents.Insert.DATA_SET,
2334ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                                mContactData.getRawContacts().get(0).getDataSet());
2335ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    }
2336ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2337f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                    // Add this flag to disable the delete menu option on directory contact joins
2338f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                    // with local contacts. The delete option is ambiguous when joining contacts.
2339f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                    intent.putExtra(ContactEditorFragment.INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION,
2340f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                            true);
2341f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos
2342ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    startActivityForResult(intent, REQUEST_CODE_CONTACT_SELECTION_ACTIVITY);
2343d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                } else if (InvisibleContactUtil.isInvisibleAndAddable(mContactData, this)) {
2344d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    InvisibleContactUtil.addToDefaultGroup(mContactData, this);
2345d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                } else if (isContactEditable()) {
2346d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    editContact();
2347d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                }
2348d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                return true;
2349752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            case R.id.menu_share:
2350752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                shareContact();
2351752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                return true;
2352752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            case R.id.menu_create_contact_shortcut:
2353752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                createLauncherShortcutWithContact();
2354752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                return true;
2355d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            default:
2356d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                return super.onOptionsItemSelected(item);
2357d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
235823889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos    }
2359edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann}
2360