QuickContactActivity.java revision 417309a770568d7b278abc91c46a739020e48157
1edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann/*
2edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Copyright (C) 2009 The Android Open Source Project
3edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann *
4edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License");
5edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * you may not use this file except in compliance with the License.
6edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * You may obtain a copy of the License at
7edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann *
8edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann *      http://www.apache.org/licenses/LICENSE-2.0
9edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann *
10edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Unless required by applicable law or agreed to in writing, software
11edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS,
12edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * See the License for the specific language governing permissions and
14edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * limitations under the License.
15edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */
16edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
17edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannpackage com.android.contacts.quickcontact;
18edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
19ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulosimport android.accounts.Account;
208a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.animation.ArgbEvaluator;
21b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport android.animation.ObjectAnimator;
22edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.app.Activity;
23d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.app.Fragment;
24cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks;
25eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.app.SearchManager;
26752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport android.content.ActivityNotFoundException;
27edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.ContentUris;
28ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulosimport android.content.ContentValues;
296bb01347eab60f95deafdfe523b0c368707210f3Brian Attwellimport android.content.Context;
30edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.Intent;
31cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmannimport android.content.Loader;
32dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulosimport android.content.pm.PackageManager;
33dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulosimport android.content.pm.ResolveInfo;
3423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulosimport android.content.res.Resources;
3531b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.graphics.Bitmap;
3695c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwellimport android.graphics.BitmapFactory;
378a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.graphics.Color;
38eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.graphics.PorterDuff;
39eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.graphics.PorterDuffColorFilter;
4031b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.graphics.drawable.BitmapDrawable;
418a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.graphics.drawable.ColorDrawable;
4231b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.graphics.drawable.Drawable;
43eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.net.ParseException;
44edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.net.Uri;
45eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.net.WebAddress;
4631b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.os.AsyncTask;
47edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.os.Bundle;
488a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.os.Trace;
49eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.CalendarContract;
50752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport android.provider.ContactsContract;
51edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Email;
52eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Event;
53eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;
54eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Identity;
55eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Im;
56eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Nickname;
57eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Note;
58eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Organization;
59edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Phone;
60eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.CommonDataKinds.Relation;
61edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.SipAddress;
62edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
63edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Website;
64752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport android.provider.ContactsContract.Contacts;
6560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulosimport android.provider.ContactsContract.Data;
66ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulosimport android.provider.ContactsContract.Directory;
67eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.provider.ContactsContract.DisplayNameSources;
68ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulosimport android.provider.ContactsContract.DataUsageFeedback;
69ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulosimport android.provider.ContactsContract.Intents;
70edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.QuickContact;
71edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.RawContacts;
7231b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.support.v7.graphics.Palette;
730319222b43927d4d9ce7e2a9070f3543661b5782Tyler Gunnimport android.telecom.PhoneAccount;
740319222b43927d4d9ce7e2a9070f3543661b5782Tyler Gunnimport android.telecom.TelecomManager;
75c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwellimport android.text.BidiFormatter;
76c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwellimport android.text.TextDirectionHeuristics;
77edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.text.TextUtils;
78edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.util.Log;
792a4207fb39330e840436215c896cde911489e111Paul Soulosimport android.view.ContextMenu;
802a4207fb39330e840436215c896cde911489e111Paul Soulosimport android.view.ContextMenu.ContextMenuInfo;
81d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.view.Menu;
82d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.view.MenuInflater;
83eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport android.view.MenuItem;
84f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chenimport android.view.MotionEvent;
85edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.view.View;
86edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.view.View.OnClickListener;
872a4207fb39330e840436215c896cde911489e111Paul Soulosimport android.view.View.OnCreateContextMenuListener;
8810d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawaimport android.view.WindowManager;
89edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.widget.Toast;
90d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.widget.Toolbar;
91edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
9272b3ab1d8a62f228a540b05f4ed6373e494c7d72Christine Chenimport com.android.contacts.ContactSaveService;
93d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport com.android.contacts.ContactsActivity;
942d150da246632b1649999cfabed776133b097775Brian Attwellimport com.android.contacts.NfcHandler;
95e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
96eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.CallUtil;
972a4207fb39330e840436215c896cde911489e111Paul Soulosimport com.android.contacts.common.ClipboardUtils;
98eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.Collapser;
99eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.ContactsUtils;
100d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport com.android.contacts.common.editor.SelectAccountDialogFragment;
10170e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chenimport com.android.contacts.common.interactions.TouchPointManager;
10231b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport com.android.contacts.common.lettertiles.LetterTileDrawable;
103752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport com.android.contacts.common.list.ShortcutIntentBuilder;
104752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport com.android.contacts.common.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener;
1050d5588da244d0992c3ff8f25d0875fdf95a8c644Chiao Chengimport com.android.contacts.common.model.AccountTypeManager;
106cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.Contact;
107cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.ContactLoader;
108cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.RawContact;
109428f008513d1591cc08fcfe2cf0c9237fb313241Chiao Chengimport com.android.contacts.common.model.account.AccountType;
110d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport com.android.contacts.common.model.account.AccountWithDataSet;
111cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.dataitem.DataItem;
112428f008513d1591cc08fcfe2cf0c9237fb313241Chiao Chengimport com.android.contacts.common.model.dataitem.DataKind;
113cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.dataitem.EmailDataItem;
114eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.EventDataItem;
115cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.dataitem.ImDataItem;
116eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.NicknameDataItem;
117eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.NoteDataItem;
118eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.OrganizationDataItem;
119b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport com.android.contacts.common.model.dataitem.PhoneDataItem;
120eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.RelationDataItem;
121eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.SipAddressDataItem;
122eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.StructuredNameDataItem;
123eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.StructuredPostalDataItem;
124eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.model.dataitem.WebsiteDataItem;
125eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.common.util.DateUtils;
126faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwellimport com.android.contacts.common.util.MaterialColorMapUtils;
127faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwellimport com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
128d41ab8ace81a2e44f8b28aa8782679b9e9cca1b9Brian Attwellimport com.android.contacts.common.util.ViewUtil;
129333091ae754ddfc25714c14b9b89534be24379f9Paul Soulosimport com.android.contacts.detail.ContactDisplayUtils;
130f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulosimport com.android.contacts.editor.ContactEditorFragment;
131899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulosimport com.android.contacts.interactions.CalendarInteractionsLoader;
132ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulosimport com.android.contacts.interactions.CallLogInteractionsLoader;
1338a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport com.android.contacts.interactions.ContactDeletionInteraction;
134b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport com.android.contacts.interactions.ContactInteraction;
135b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport com.android.contacts.interactions.SmsInteractionsLoader;
1362d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport com.android.contacts.quickcontact.ExpandingEntryCardView.Entry;
1372a4207fb39330e840436215c896cde911489e111Paul Soulosimport com.android.contacts.quickcontact.ExpandingEntryCardView.EntryContextMenuInfo;
1382ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulosimport com.android.contacts.quickcontact.ExpandingEntryCardView.EntryTag;
139e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwellimport com.android.contacts.quickcontact.ExpandingEntryCardView.ExpandingEntryCardViewListener;
140e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.ImageViewDrawableSetter;
141eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.util.PhoneCapabilityTester;
142b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport com.android.contacts.util.SchedulingUtils;
143eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport com.android.contacts.util.StructuredPostalUtils;
144b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport com.android.contacts.widget.MultiShrinkScroller;
145b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport com.android.contacts.widget.MultiShrinkScroller.MultiShrinkScrollerListener;
14602eaf11669d25fd885606b3b0700358323532cddBrian Attwellimport com.android.contacts.widget.QuickContactImageView;
147e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.base.Preconditions;
148e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.collect.Lists;
149e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
1502d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport java.util.ArrayList;
151899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulosimport java.util.Arrays;
152eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport java.util.Calendar;
153b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport java.util.Collections;
154b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport java.util.Comparator;
155eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulosimport java.util.Date;
156edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.HashMap;
157edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.List;
158b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport java.util.Map;
159edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
160edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann/**
161edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Mostly translucent {@link Activity} that shows QuickContact dialog. It loads
162edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * data asynchronously, and then shows a popup with details centered around
163edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * {@link Intent#getSourceBounds()}.
164edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */
165d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellpublic class QuickContactActivity extends ContactsActivity {
1668a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1678a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    /**
1688a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell     * QuickContacts immediately takes up the full screen. All possible information is shown.
1698a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell     * This value for {@link android.provider.ContactsContract.QuickContact#EXTRA_MODE}
1708a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell     * should only be used by the Contacts app.
1718a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell     */
1728a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    public static final int MODE_FULLY_EXPANDED = 4;
1738a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
174edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final String TAG = "QuickContact";
175edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1769b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    private static final String KEY_THEME_COLOR = "theme_color";
1779b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
1789b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    private static final int ANIMATION_STATUS_BAR_COLOR_CHANGE_DURATION = 150;
1798a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private static final int REQUEST_CODE_CONTACT_EDITOR_ACTIVITY = 1;
1802e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos    private static final int DEFAULT_SCRIM_ALPHA = 0xC8;
1812e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos    private static final int SCRIM_COLOR = Color.argb(DEFAULT_SCRIM_ALPHA, 0, 0, 0);
182ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos    private static final int REQUEST_CODE_CONTACT_SELECTION_ACTIVITY = 2;
183ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos    private static final String MIMETYPE_SMS = "vnd.android-dir/mms-sms";
184dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
185752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    /** This is the Intent action to install a shortcut in the launcher. */
186752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private static final String ACTION_INSTALL_SHORTCUT =
187752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            "com.android.launcher.action.INSTALL_SHORTCUT";
188edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
189edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @SuppressWarnings("deprecation")
190edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final String LEGACY_AUTHORITY = android.provider.Contacts.AUTHORITY;
191edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
192e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos    private static final String MIMETYPE_GPLUS_PROFILE =
193e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            "vnd.android.cursor.item/vnd.googleplus.profile";
1946a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE = "addtocircle";
1956a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String GPLUS_PROFILE_DATA_5_VIEW_PROFILE = "view";
196e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos    private static final String MIMETYPE_HANGOUTS =
197e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            "vnd.android.cursor.item/vnd.googleplus.profile.comm";
1986a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String HANGOUTS_DATA_5_VIDEO = "hangout";
1996a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final String HANGOUTS_DATA_5_MESSAGE = "conversation";
20048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos    private static final String CALL_ORIGIN_QUICK_CONTACTS_ACTIVITY =
20148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            "com.android.contacts.quickcontact.QuickContactActivity";
202e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos
20363176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell    /**
20463176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell     * The URI used to load the the Contact. Once the contact is loaded, use Contact#getLookupUri()
20563176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell     * instead of referencing this URI.
20663176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell     */
207edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private Uri mLookupUri;
208edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private String[] mExcludeMimes;
2098a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private int mExtraMode;
2108a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private int mStatusBarColor;
2118a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private boolean mHasAlreadyBeenOpened;
21297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    private boolean mOnlyOnePhoneNumber;
21397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    private boolean mOnlyOneEmail;
214edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
21502eaf11669d25fd885606b3b0700358323532cddBrian Attwell    private QuickContactImageView mPhotoView;
216eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private ExpandingEntryCardView mContactCard;
2176095369885edcca566a812b551886e29c7ff8039Brian Attwell    private ExpandingEntryCardView mNoContactDetailsCard;
218b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private ExpandingEntryCardView mRecentCard;
219eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private ExpandingEntryCardView mAboutCard;
220b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    private MultiShrinkScroller mScroller;
221d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private SelectAccountDialogFragmentListener mSelectAccountFragmentListener;
2226bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private AsyncTask<Void, Void, Cp2DataCardModel> mEntriesAndActionsTask;
22330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell    private AsyncTask<Void, Void, Void> mRecentDataTask;
2246bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    /**
2256bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * The last copy of Cp2DataCardModel that was passed to {@link #populateContactAndAboutCard}.
2266bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     */
2276bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private Cp2DataCardModel mCachedCp2DataCardModel;
228f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell    /**
229f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  This scrim's opacity is controlled in two different ways. 1) Before the initial entrance
230f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  animation finishes, the opacity is animated by a value animator. This is designed to
231f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  distract the user from the length of the initial loading time. 2) After the initial
232f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     *  entrance animation, the opacity is directly related to scroll position.
233f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell     */
2349b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    private ColorDrawable mWindowScrim;
235f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell    private boolean mIsEntranceAnimationFinished;
236a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell    private MaterialColorMapUtils mMaterialColorMapUtils;
2378477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell    private boolean mIsExitAnimationInProgress;
2388571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell    private boolean mHasComputedThemeColor;
239edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
240a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    /**
241a42ef76251778161d27bc07db214b8c81720e476Paul Soulos     * Used to stop the ExpandingEntry cards from adjusting between an entry click and the intent
242a42ef76251778161d27bc07db214b8c81720e476Paul Soulos     * being launched.
243a42ef76251778161d27bc07db214b8c81720e476Paul Soulos     */
244a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    private boolean mHasIntentLaunched;
245a42ef76251778161d27bc07db214b8c81720e476Paul Soulos
2466cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee    private Contact mContactData;
2479815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann    private ContactLoader mContactLoader;
2489b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    private PorterDuffColorFilter mColorFilter;
2499815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann
2509758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus    private final ImageViewDrawableSetter mPhotoSetter = new ImageViewDrawableSetter();
2519758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus
252edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
253cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * {@link #LEADING_MIMETYPES} is used to sort MIME-types.
254edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     *
255edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * <p>The MIME-types in {@link #LEADING_MIMETYPES} appear in the front of the dialog,
256edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * in the order specified here.</p>
257edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
258edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final List<String> LEADING_MIMETYPES = Lists.newArrayList(
259cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos            Phone.CONTENT_ITEM_TYPE, SipAddress.CONTENT_ITEM_TYPE, Email.CONTENT_ITEM_TYPE,
260405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos            StructuredPostal.CONTENT_ITEM_TYPE);
261edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
262a153dba33c2152332c5706178a367f52b0550723Paul Soulos    private static final List<String> SORTED_ABOUT_CARD_MIMETYPES = Lists.newArrayList(
263a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Nickname.CONTENT_ITEM_TYPE,
264a153dba33c2152332c5706178a367f52b0550723Paul Soulos            // Phonetic name is inserted after nickname if it is available.
265a153dba33c2152332c5706178a367f52b0550723Paul Soulos            // No mimetype for phonetic name exists.
266a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Website.CONTENT_ITEM_TYPE,
267a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Organization.CONTENT_ITEM_TYPE,
268a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Event.CONTENT_ITEM_TYPE,
269a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Relation.CONTENT_ITEM_TYPE,
270a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Im.CONTENT_ITEM_TYPE,
271a153dba33c2152332c5706178a367f52b0550723Paul Soulos            GroupMembership.CONTENT_ITEM_TYPE,
272a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Identity.CONTENT_ITEM_TYPE,
273a153dba33c2152332c5706178a367f52b0550723Paul Soulos            Note.CONTENT_ITEM_TYPE);
274eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
275c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell    private static final BidiFormatter sBidiFormatter = BidiFormatter.getInstance();
276c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell
277b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    /** Id for the background contact loader */
278b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private static final int LOADER_CONTACT_ID = 0;
279b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
280ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final String KEY_LOADER_EXTRA_PHONES =
281ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos            QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_PHONES";
282ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
283b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    /** Id for the background Sms Loader */
284b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private static final int LOADER_SMS_ID = 1;
285b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private static final int MAX_SMS_RETRIEVE = 3;
286ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
287ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    /** Id for the back Calendar Loader */
288899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final int LOADER_CALENDAR_ID = 2;
289ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final String KEY_LOADER_EXTRA_EMAILS =
290ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos            QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_EMAILS";
291899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final int MAX_PAST_CALENDAR_RETRIEVE = 3;
292899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final int MAX_FUTURE_CALENDAR_RETRIEVE = 3;
293899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final long PAST_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR =
29440d7a65c6e68967f3f486715b194c144d93c296fPaul Soulos            1L * 24L * 60L * 60L * 1000L /* 1 day */;
295899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos    private static final long FUTURE_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR =
29640d7a65c6e68967f3f486715b194c144d93c296fPaul Soulos            7L * 24L * 60L * 60L * 1000L /* 7 days */;
297899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos
298ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    /** Id for the background Call Log Loader */
299ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final int LOADER_CALL_LOG_ID = 3;
300ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final int MAX_CALL_LOG_RETRIEVE = 3;
3016095369885edcca566a812b551886e29c7ff8039Brian Attwell    private static final int MIN_NUM_CONTACT_ENTRIES_SHOWN = 3;
3026095369885edcca566a812b551886e29c7ff8039Brian Attwell    private static final int MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN = 3;
3036095369885edcca566a812b551886e29c7ff8039Brian Attwell    private static final int CARD_ENTRY_ID_EDIT_CONTACT = -2;
304ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
305ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
306ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos    private static final int[] mRecentLoaderIds = new int[]{
307ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        LOADER_SMS_ID,
308ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        LOADER_CALENDAR_ID,
309ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        LOADER_CALL_LOG_ID};
310a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos    private Map<Integer, List<ContactInteraction>> mRecentLoaderResults = new HashMap<>();
311b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
312d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private static final String FRAGMENT_TAG_SELECT_ACCOUNT = "select_account_fragment";
3136cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee
3142d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    final OnClickListener mEntryClickHandler = new OnClickListener() {
3152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        @Override
3162d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        public void onClick(View v) {
3172ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final Object entryTagObject = v.getTag();
3182ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            if (entryTagObject == null || !(entryTagObject instanceof EntryTag)) {
3192ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos                Log.w(TAG, "EntryTag was not used correctly");
3206095369885edcca566a812b551886e29c7ff8039Brian Attwell                return;
3216095369885edcca566a812b551886e29c7ff8039Brian Attwell            }
3222ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final EntryTag entryTag = (EntryTag) entryTagObject;
3232ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final Intent intent = entryTag.getIntent();
3242ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            final int dataId = entryTag.getId();
3252ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos
3262ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            if (dataId == CARD_ENTRY_ID_EDIT_CONTACT) {
3272ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos                editContact();
3282d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                return;
3292d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            }
330ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
331ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            // Default to USAGE_TYPE_CALL. Usage is summed among all types for sorting each data id
332ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            // so the exact usage type is not necessary in all cases
333ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            String usageType = DataUsageFeedback.USAGE_TYPE_CALL;
334ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
33520bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos            final Uri intentUri = intent.getData();
33620bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos            if ((intentUri != null && intentUri.getScheme() != null &&
3371cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                    intentUri.getScheme().equals(ContactsUtils.SCHEME_SMSTO)) ||
338ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                    (intent.getType() != null && intent.getType().equals(MIMETYPE_SMS))) {
339ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                usageType = DataUsageFeedback.USAGE_TYPE_SHORT_TEXT;
340ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            }
341ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
342ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            // Data IDs start at 1 so anything less is invalid
343ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            if (dataId > 0) {
34420bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos                final Uri dataUsageUri = DataUsageFeedback.FEEDBACK_URI.buildUpon()
345ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                        .appendPath(String.valueOf(dataId))
346ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                        .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, usageType)
347ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                        .build();
348ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                final boolean successful = getContentResolver().update(
34920bdf9d2d21e1c82513f798ef4205b9d1713996dPaul Soulos                        dataUsageUri, new ContentValues(), null, null) > 0;
350ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                if (!successful) {
351ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                    Log.w(TAG, "DataUsageFeedback increment failed");
352ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                }
353ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            } else {
354ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                Log.w(TAG, "Invalid Data ID");
355ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            }
356ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
35770e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen            // Pass the touch point through the intent for use in the InCallUI
35870e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen            if (Intent.ACTION_CALL.equals(intent.getAction())) {
3591f8a3fda87bf61e579d61e3fdd246548943d070aNancy Chen                if (TouchPointManager.getInstance().hasValidPoint()) {
36070e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen                    Bundle extras = new Bundle();
3611f8a3fda87bf61e579d61e3fdd246548943d070aNancy Chen                    extras.putParcelable(TouchPointManager.TOUCH_POINT,
3621f8a3fda87bf61e579d61e3fdd246548943d070aNancy Chen                            TouchPointManager.getInstance().getPoint());
3630319222b43927d4d9ce7e2a9070f3543661b5782Tyler Gunn                    intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);
36470e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen                }
36570e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen            }
36670e3f4f45c040a2d09bfb46462242b450cf20b29Nancy Chen
367793e73c859ed839c28cc37d80d62bde0a361c78aPaul Soulos            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
368793e73c859ed839c28cc37d80d62bde0a361c78aPaul Soulos
3692e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            // Force the window dim amount to the scrim value for app transition animations
3702e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            // The scrim may be removed before the window transitions to the new activity, which
3712e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            // can cause a flicker in the status and navigation bar. Set dim alone does not work
3722e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            // well because the request is passed through IPC which makes it slow to animate.
3732e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
3742e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos                    WindowManager.LayoutParams.FLAG_DIM_BEHIND);
3752e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos            getWindow().setDimAmount(mWindowScrim.getAlpha() / DEFAULT_SCRIM_ALPHA);
3762e6387f0bef606bb4be3facaedeafd080156d6c6Paul Soulos
377a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            mHasIntentLaunched = true;
378417309a770568d7b278abc91c46a739020e48157Jay Shrauner            try {
379417309a770568d7b278abc91c46a739020e48157Jay Shrauner                startActivity(intent);
380417309a770568d7b278abc91c46a739020e48157Jay Shrauner            } catch (ActivityNotFoundException ex) {
381417309a770568d7b278abc91c46a739020e48157Jay Shrauner                Toast.makeText(QuickContactActivity.this, R.string.missing_app,
382417309a770568d7b278abc91c46a739020e48157Jay Shrauner                        Toast.LENGTH_SHORT).show();
383417309a770568d7b278abc91c46a739020e48157Jay Shrauner            }
3842d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
3852d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    };
3862d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
387e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    final ExpandingEntryCardViewListener mExpandingEntryCardViewListener
388e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell            = new ExpandingEntryCardViewListener() {
389e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        @Override
390e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        public void onCollapse(int heightDelta) {
391e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell            mScroller.prepareForShrinkingScrollChild(heightDelta);
392e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        }
3930cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
3940cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        @Override
3950cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        public void onExpand(int heightDelta) {
3960cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            mScroller.prepareForExpandingScrollChild();
3970cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        }
398e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    };
399e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell
40097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    private interface ContextMenuIds {
40197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        static final int COPY_TEXT = 0;
40297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        static final int CLEAR_DEFAULT = 1;
40397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        static final int SET_DEFAULT = 2;
40497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos    }
40597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
4062a4207fb39330e840436215c896cde911489e111Paul Soulos    private final OnCreateContextMenuListener mEntryContextMenuListener =
4072a4207fb39330e840436215c896cde911489e111Paul Soulos            new OnCreateContextMenuListener() {
4082a4207fb39330e840436215c896cde911489e111Paul Soulos        @Override
4092a4207fb39330e840436215c896cde911489e111Paul Soulos        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
4102a4207fb39330e840436215c896cde911489e111Paul Soulos            if (menuInfo == null) {
4112a4207fb39330e840436215c896cde911489e111Paul Soulos                return;
4122a4207fb39330e840436215c896cde911489e111Paul Soulos            }
41397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            final EntryContextMenuInfo info = (EntryContextMenuInfo) menuInfo;
4142a4207fb39330e840436215c896cde911489e111Paul Soulos            menu.setHeaderTitle(info.getCopyText());
41597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            menu.add(ContextMenu.NONE, ContextMenuIds.COPY_TEXT,
41697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    ContextMenu.NONE, getString(R.string.copy_text));
41797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
41897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Don't allow setting or clearing of defaults for non-editable contacts
41997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            if (!isContactEditable()) {
42097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return;
42197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            }
42297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
42397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            final String selectedMimeType = info.getMimeType();
42497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
42597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Defaults to true will only enable the detail to be copied to the clipboard.
42697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            boolean onlyOneOfMimeType = true;
42797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
42897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Only allow primary support for Phone and Email content types
42997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            if (Phone.CONTENT_ITEM_TYPE.equals(selectedMimeType)) {
43097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                onlyOneOfMimeType = mOnlyOnePhoneNumber;
43197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            } else if (Email.CONTENT_ITEM_TYPE.equals(selectedMimeType)) {
43297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                onlyOneOfMimeType = mOnlyOneEmail;
43397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            }
43497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
43597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            // Checking for previously set default
43697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            if (info.isSuperPrimary()) {
43797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                menu.add(ContextMenu.NONE, ContextMenuIds.CLEAR_DEFAULT,
43897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        ContextMenu.NONE, getString(R.string.clear_default));
43997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            } else if (!onlyOneOfMimeType) {
44097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                menu.add(ContextMenu.NONE, ContextMenuIds.SET_DEFAULT,
44197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        ContextMenu.NONE, getString(R.string.set_default));
44297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            }
4432a4207fb39330e840436215c896cde911489e111Paul Soulos        }
4442a4207fb39330e840436215c896cde911489e111Paul Soulos    };
4452a4207fb39330e840436215c896cde911489e111Paul Soulos
4462a4207fb39330e840436215c896cde911489e111Paul Soulos    @Override
4472a4207fb39330e840436215c896cde911489e111Paul Soulos    public boolean onContextItemSelected(MenuItem item) {
4482a4207fb39330e840436215c896cde911489e111Paul Soulos        EntryContextMenuInfo menuInfo;
4492a4207fb39330e840436215c896cde911489e111Paul Soulos        try {
4502a4207fb39330e840436215c896cde911489e111Paul Soulos            menuInfo = (EntryContextMenuInfo) item.getMenuInfo();
4512a4207fb39330e840436215c896cde911489e111Paul Soulos        } catch (ClassCastException e) {
4522a4207fb39330e840436215c896cde911489e111Paul Soulos            Log.e(TAG, "bad menuInfo", e);
4532a4207fb39330e840436215c896cde911489e111Paul Soulos            return false;
4542a4207fb39330e840436215c896cde911489e111Paul Soulos        }
4552a4207fb39330e840436215c896cde911489e111Paul Soulos
45697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        switch (item.getItemId()) {
45797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            case ContextMenuIds.COPY_TEXT:
45897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                ClipboardUtils.copyText(this, menuInfo.getCopyLabel(), menuInfo.getCopyText(),
45997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        true);
46097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return true;
46197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            case ContextMenuIds.SET_DEFAULT:
46297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                final Intent setIntent = ContactSaveService.createSetSuperPrimaryIntent(this,
46397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        menuInfo.getId());
46497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                this.startService(setIntent);
46597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return true;
46697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            case ContextMenuIds.CLEAR_DEFAULT:
46797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                final Intent clearIntent = ContactSaveService.createClearPrimaryIntent(this,
46897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        menuInfo.getId());
46997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                this.startService(clearIntent);
47097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                return true;
47197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            default:
47297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                throw new IllegalArgumentException("Unknown menu option " + item.getItemId());
47397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
4742a4207fb39330e840436215c896cde911489e111Paul Soulos    }
4752a4207fb39330e840436215c896cde911489e111Paul Soulos
476d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    /**
477d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     * Headless fragment used to handle account selection callbacks invoked from
478d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     * {@link DirectoryContactUtil}.
479d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     */
480d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public static class SelectAccountDialogFragmentListener extends Fragment
481d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            implements SelectAccountDialogFragment.Listener {
482d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
483d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        private QuickContactActivity mQuickContactActivity;
484d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
485d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public SelectAccountDialogFragmentListener() {}
486d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
487d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        @Override
488d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
489d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            DirectoryContactUtil.createCopy(mQuickContactActivity.mContactData.getContentValues(),
490d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    account, mQuickContactActivity);
491d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
492d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
493d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        @Override
494d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public void onAccountSelectorCancelled() {}
495d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
496d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        /**
497d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         * Set the parent activity. Since rotation can cause this fragment to be used across
498d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         * more than one activity instance, we need to explicitly set this value instead
499d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         * of making this class non-static.
500d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell         */
501d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        public void setQuickContactActivity(QuickContactActivity quickContactActivity) {
502d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mQuickContactActivity = quickContactActivity;
503d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
504d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
505d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
506b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    final MultiShrinkScrollerListener mMultiShrinkScrollerListener
507b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell            = new MultiShrinkScrollerListener() {
508b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        @Override
509b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        public void onScrolledOffBottom() {
510f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell            finish();
511b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        }
5128a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
5138a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        @Override
5148a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        public void onEnterFullscreen() {
5158a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            updateStatusBarColor();
5168a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
5178a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
5188a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        @Override
5198a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        public void onExitFullscreen() {
5208a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            updateStatusBarColor();
5218a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
5228477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell
5238477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        @Override
5248477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        public void onStartScrollOffBottom() {
5258477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            mIsExitAnimationInProgress = true;
5268477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        }
5278477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell
5288477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        @Override
529f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        public void onEntranceAnimationDone() {
530f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell            mIsEntranceAnimationFinished = true;
531f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        }
532f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell
533f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        @Override
534f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        public void onTransparentViewHeightChange(float ratio) {
535f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell            if (mIsEntranceAnimationFinished) {
536f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                mWindowScrim.setAlpha((int) (0xFF * ratio));
5378477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            }
5388477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell        }
539b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    };
540b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell
541eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
542eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    /**
543eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * Data items are compared to the same mimetype based off of three qualities:
544eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * 1. Super primary
545eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * 2. Primary
546eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * 3. Times used
547eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     */
548eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final Comparator<DataItem> mWithinMimeTypeDataItemComparator =
549eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            new Comparator<DataItem>() {
550eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        @Override
551eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        public int compare(DataItem lhs, DataItem rhs) {
552eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!lhs.getMimeType().equals(rhs.getMimeType())) {
553eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                Log.wtf(TAG, "Comparing DataItems with different mimetypes lhs.getMimeType(): " +
554eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        lhs.getMimeType() + " rhs.getMimeType(): " + rhs.getMimeType());
555eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 0;
556eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
557eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
558eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (lhs.isSuperPrimary()) {
559eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return -1;
560eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (rhs.isSuperPrimary()) {
561eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 1;
562eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (lhs.isPrimary() && !rhs.isPrimary()) {
563eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return -1;
564eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (!lhs.isPrimary() && rhs.isPrimary()) {
565eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 1;
566eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else {
567eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final int lhsTimesUsed =
568eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        lhs.getTimesUsed() == null ? 0 : lhs.getTimesUsed();
569eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final int rhsTimesUsed =
570eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        rhs.getTimesUsed() == null ? 0 : rhs.getTimesUsed();
571eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
572eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return rhsTimesUsed - lhsTimesUsed;
573eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
574eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
575eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    };
576eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
577cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos    /**
578cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * Sorts among different mimetypes based off:
579cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * 1. Times used
580cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * 2. Last time used
581cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     * 3. Statically defined
582cb4fcc7ef75c33411d2b900db7933c5bc4336527Paul Soulos     */
583eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final Comparator<List<DataItem>> mAmongstMimeTypeDataItemComparator =
584eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            new Comparator<List<DataItem>> () {
585eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        @Override
586eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        public int compare(List<DataItem> lhsList, List<DataItem> rhsList) {
587eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            DataItem lhs = lhsList.get(0);
588eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            DataItem rhs = rhsList.get(0);
589eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final int lhsTimesUsed = lhs.getTimesUsed() == null ? 0 : lhs.getTimesUsed();
590eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final int rhsTimesUsed = rhs.getTimesUsed() == null ? 0 : rhs.getTimesUsed();
591eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final int timesUsedDifference = rhsTimesUsed - lhsTimesUsed;
592eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (timesUsedDifference != 0) {
593eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return timesUsedDifference;
594eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
595eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
596eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final long lhsLastTimeUsed =
597eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    lhs.getLastTimeUsed() == null ? 0 : lhs.getLastTimeUsed();
598eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final long rhsLastTimeUsed =
599eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    rhs.getLastTimeUsed() == null ? 0 : rhs.getLastTimeUsed();
600eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final long lastTimeUsedDifference = rhsLastTimeUsed - lhsLastTimeUsed;
601eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (lastTimeUsedDifference > 0) {
602eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return 1;
603eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else if (lastTimeUsedDifference < 0) {
604eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return -1;
605eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
606eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
607eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Times used and last time used are the same. Resort to statically defined.
608eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String lhsMimeType = lhs.getMimeType();
609eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String rhsMimeType = rhs.getMimeType();
610eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            for (String mimeType : LEADING_MIMETYPES) {
611eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (lhsMimeType.equals(mimeType)) {
612eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    return -1;
613eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                } else if (rhsMimeType.equals(mimeType)) {
614eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    return 1;
615eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                }
616eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
617eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            return 0;
618eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
619eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    };
620eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
621edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @Override
622f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen    public boolean dispatchTouchEvent(MotionEvent ev) {
623f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
624f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen            TouchPointManager.getInstance().setPoint((int) ev.getRawX(), (int) ev.getRawY());
625f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen        }
626f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen        return super.dispatchTouchEvent(ev);
627f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen    }
628f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen
629f619e432bcebb7f91c9ed88fc384abab16a9cd6aNancy Chen    @Override
6308a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    protected void onCreate(Bundle savedInstanceState) {
6318a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.beginSection("onCreate()");
6328a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.onCreate(savedInstanceState);
633edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
6348a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        getWindow().setStatusBarColor(Color.TRANSPARENT);
6352426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann
636d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        processIntent(getIntent());
637dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
63810d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa        // Show QuickContact in front of soft input
63910d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
64010d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
64110d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa
642edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        setContentView(R.layout.quickcontact_activity);
643edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
644a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell        mMaterialColorMapUtils = new MaterialColorMapUtils(getResources());
645a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell
6460cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        mScroller = (MultiShrinkScroller) findViewById(R.id.multiscroller);
6470cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
648eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mContactCard = (ExpandingEntryCardView) findViewById(R.id.communication_card);
6496095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard = (ExpandingEntryCardView) findViewById(R.id.no_contact_data_card);
650b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        mRecentCard = (ExpandingEntryCardView) findViewById(R.id.recent_card);
651eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mAboutCard = (ExpandingEntryCardView) findViewById(R.id.about_card);
652edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
6536095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setOnClickListener(mEntryClickHandler);
654eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mContactCard.setOnClickListener(mEntryClickHandler);
655eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mContactCard.setExpandButtonText(
65623889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos        getResources().getString(R.string.expanding_entry_card_view_see_all));
6572a4207fb39330e840436215c896cde911489e111Paul Soulos        mContactCard.setOnCreateContextMenuListener(mEntryContextMenuListener);
658b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
659b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        mRecentCard.setOnClickListener(mEntryClickHandler);
660b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        mRecentCard.setTitle(getResources().getString(R.string.recent_card_title));
661edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
662eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        mAboutCard.setOnClickListener(mEntryClickHandler);
6632a4207fb39330e840436215c896cde911489e111Paul Soulos        mAboutCard.setOnCreateContextMenuListener(mEntryContextMenuListener);
664eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
66502eaf11669d25fd885606b3b0700358323532cddBrian Attwell        mPhotoView = (QuickContactImageView) findViewById(R.id.photo);
66663176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        final View transparentView = findViewById(R.id.transparent_view);
6670d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell        if (mScroller != null) {
66863176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell            transparentView.setOnClickListener(new OnClickListener() {
6690d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                @Override
6700d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                public void onClick(View v) {
6710d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                    mScroller.scrollOffBottom();
6720d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell                }
6730d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell            });
6740d90afea92dc37245d5c2cad4d6b8040f2faed5cBrian Attwell        }
675edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
676d41ab8ace81a2e44f8b28aa8782679b9e9cca1b9Brian Attwell        // Allow a shadow to be shown under the toolbar.
677d41ab8ace81a2e44f8b28aa8782679b9e9cca1b9Brian Attwell        ViewUtil.addRectangularOutlineProvider(findViewById(R.id.toolbar_parent), getResources());
678d41ab8ace81a2e44f8b28aa8782679b9e9cca1b9Brian Attwell
679d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
680d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        setActionBar(toolbar);
6819b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        getActionBar().setTitle(null);
6829b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        // Put a TextView with a known resource id into the ActionBar. This allows us to easily
6839b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        // find the correct TextView location & size later.
6849b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        toolbar.addView(getLayoutInflater().inflate(R.layout.quickcontact_title_placeholder, null));
6856219668d0612f7522bd15a9d34c6232cb15b9a6cYorke Lee
6868a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mHasAlreadyBeenOpened = savedInstanceState != null;
687f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        mIsEntranceAnimationFinished = mHasAlreadyBeenOpened;
6889b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        mWindowScrim = new ColorDrawable(SCRIM_COLOR);
689f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        mWindowScrim.setAlpha(0);
6909b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        getWindow().setBackgroundDrawable(mWindowScrim);
691edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
692c33ae17c9816b770041ee1f9ccde10e7c7eee491Brian Attwell        mScroller.initialize(mMultiShrinkScrollerListener, mExtraMode == MODE_FULLY_EXPANDED);
693ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell        // mScroller needs to perform asynchronous measurements after initalize(), therefore
694ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell        // we can't mark this as GONE.
695ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell        mScroller.setVisibility(View.INVISIBLE);
6968a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
6979b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        setHeaderNameText(R.string.missing_name);
6989b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
699d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mSelectAccountFragmentListener= (SelectAccountDialogFragmentListener) getFragmentManager()
700d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                .findFragmentByTag(FRAGMENT_TAG_SELECT_ACCOUNT);
701d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (mSelectAccountFragmentListener == null) {
702d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mSelectAccountFragmentListener = new SelectAccountDialogFragmentListener();
703d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            getFragmentManager().beginTransaction().add(0, mSelectAccountFragmentListener,
704d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    FRAGMENT_TAG_SELECT_ACCOUNT).commit();
705d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mSelectAccountFragmentListener.setRetainInstance(true);
706d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
707d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mSelectAccountFragmentListener.setQuickContactActivity(this);
70823889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos
709f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        SchedulingUtils.doOnPreDraw(mScroller, /* drawNextFrame = */ true,
710f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                new Runnable() {
711f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                    @Override
712f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                    public void run() {
713f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                        if (!mHasAlreadyBeenOpened) {
714f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            // The initial scrim opacity must match the scrim opacity that would be
715f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            // achieved by scrolling to the starting position.
716f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            final float alphaRatio = mExtraMode == MODE_FULLY_EXPANDED ?
717f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                                    1 : mScroller.getStartingTransparentHeightRatio();
718f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            final int duration = getResources().getInteger(
719f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                                    android.R.integer.config_shortAnimTime);
720f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            final int desiredAlpha = (int) (0xFF * alphaRatio);
721f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            ObjectAnimator o = ObjectAnimator.ofInt(mWindowScrim, "alpha", 0,
722f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                                    desiredAlpha).setDuration(duration);
723f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell
724f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                            o.start();
725f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                        }
726f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                    }
727f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell                });
728f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell
7299b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        if (savedInstanceState != null) {
7309b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            final int color = savedInstanceState.getInt(KEY_THEME_COLOR, 0);
731ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell            SchedulingUtils.doOnPreDraw(mScroller, /* drawNextFrame = */ false,
732ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                    new Runnable() {
733ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                        @Override
734ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                        public void run() {
735ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // Need to wait for the pre draw before setting the initial scroll
736ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // value. Prior to pre draw all scroll values are invalid.
737ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            if (mHasAlreadyBeenOpened) {
738ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                                mScroller.setVisibility(View.VISIBLE);
739ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                                mScroller.setScroll(mScroller.getScrollNeededToBeFullScreen());
740ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            }
741ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // Need to wait for pre draw for setting the theme color. Setting the
742ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // header tint before the MultiShrinkScroller has been measured will
743ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            // cause incorrect tinting calculations.
744ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                            if (color != 0) {
745a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                                setThemeColor(mMaterialColorMapUtils
746a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                                        .calculatePrimaryAndSecondaryColor(color));
7479b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell                            }
748ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                        }
749ac3ed8e48cc474448aa5a7cfed5d6b95073b84f9Brian Attwell                    });
7509b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        }
7519b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
7528a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
7538a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
7548a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
755405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos    @Override
756405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
7578a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (requestCode == REQUEST_CODE_CONTACT_EDITOR_ACTIVITY &&
7588a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                resultCode == ContactDeletionInteraction.RESULT_CODE_DELETED) {
7598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // The contact that we were showing has been deleted.
7608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            finish();
761ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos        } else if (requestCode == REQUEST_CODE_CONTACT_SELECTION_ACTIVITY &&
762ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                resultCode != RESULT_CANCELED) {
763ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos            processIntent(data);
764b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        }
7658a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
766dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
7678a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    @Override
7688a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    protected void onNewIntent(Intent intent) {
7698a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.onNewIntent(intent);
7708a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mHasAlreadyBeenOpened = true;
771f1076dc20feb3ee0c687c818d70ffc1d25bef909Brian Attwell        mIsEntranceAnimationFinished = true;
7728571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell        mHasComputedThemeColor = false;
773d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        processIntent(intent);
774d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
775d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
7769b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    @Override
7779b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    public void onSaveInstanceState(Bundle savedInstanceState) {
7789b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        super.onSaveInstanceState(savedInstanceState);
7799b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        if (mColorFilter != null) {
7809b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            savedInstanceState.putInt(KEY_THEME_COLOR, mColorFilter.getColor());
7819b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        }
7829b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    }
7839b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
784d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private void processIntent(Intent intent) {
785f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos        if (intent == null) {
786f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos            finish();
787f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos            return;
788f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos        }
789d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        Uri lookupUri = intent.getData();
790d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
791d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        // Check to see whether it comes from the old version.
792d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (lookupUri != null && LEGACY_AUTHORITY.equals(lookupUri.getAuthority())) {
793d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final long rawContactId = ContentUris.parseId(lookupUri);
794d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            lookupUri = RawContacts.getContactLookupUri(getContentResolver(),
795d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
796d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
797d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mExtraMode = getIntent().getIntExtra(QuickContact.EXTRA_MODE,
798d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                QuickContact.MODE_LARGE);
799d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        final Uri oldLookupUri = mLookupUri;
800d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
801d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mLookupUri = Preconditions.checkNotNull(lookupUri, "missing lookupUri");
802d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        mExcludeMimes = intent.getStringArrayExtra(QuickContact.EXTRA_EXCLUDE_MIMES);
803d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (oldLookupUri == null) {
804d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            mContactLoader = (ContactLoader) getLoaderManager().initLoader(
805d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    LOADER_CONTACT_ID, null, mLoaderContactCallbacks);
806d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        } else if (oldLookupUri != mLookupUri) {
807d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // After copying a directory contact, the contact URI changes. Therefore,
808d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // we need to restart the loader and reload the new contact.
80959a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell            destroyInteractionLoaders();
810405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos            mContactLoader = (ContactLoader) getLoaderManager().restartLoader(
811405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos                    LOADER_CONTACT_ID, null, mLoaderContactCallbacks);
81259a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell            mCachedCp2DataCardModel = null;
813d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
8142d150da246632b1649999cfabed776133b097775Brian Attwell
8152d150da246632b1649999cfabed776133b097775Brian Attwell        NfcHandler.register(this, mLookupUri);
8162426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann    }
817edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
81859a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell    private void destroyInteractionLoaders() {
81959a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        for (int interactionLoaderId : mRecentLoaderIds) {
82059a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell            getLoaderManager().destroyLoader(interactionLoaderId);
82159a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        }
82259a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell    }
82359a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell
824b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    private void runEntranceAnimation() {
8258a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mHasAlreadyBeenOpened) {
8268a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            return;
8278a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
8288a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mHasAlreadyBeenOpened = true;
829c33ae17c9816b770041ee1f9ccde10e7c7eee491Brian Attwell        mScroller.scrollUpForEntranceAnimation(mExtraMode != MODE_FULLY_EXPANDED);
830b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    }
831b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell
83281281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /** Assign this string to the view if it is not empty. */
833d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private void setHeaderNameText(int resId) {
8349b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        if (mScroller != null) {
835f43f573340fd9de5d30b43d7c96cac1ec9021e58Brian Attwell            mScroller.setTitle(getText(resId) == null ? null : getText(resId).toString());
8369b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        }
83781281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    }
83881281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan
83981281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /** Assign this string to the view if it is not empty. */
840f43f573340fd9de5d30b43d7c96cac1ec9021e58Brian Attwell    private void setHeaderNameText(String value) {
841d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (!TextUtils.isEmpty(value)) {
8429b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            if (mScroller != null) {
843f43f573340fd9de5d30b43d7c96cac1ec9021e58Brian Attwell                mScroller.setTitle(value);
8449b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell            }
84581281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        }
84681281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    }
84781281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan
84881281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /**
849edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Check if the given MIME-type appears in the list of excluded MIME-types
850edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * that the most-recent caller requested.
851edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
852edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private boolean isMimeExcluded(String mimeType) {
853edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        if (mExcludeMimes == null) return false;
854edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String excludedMime : mExcludeMimes) {
855edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (TextUtils.equals(excludedMime, mimeType)) {
856edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                return true;
857edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
858edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
859edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        return false;
860edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
861edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
862edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
863cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann     * Handle the result from the ContactLoader
864edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
8658a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private void bindContactData(final Contact data) {
8668a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.beginSection("bindContactData");
8676cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee        mContactData = data;
868d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        invalidateOptionsMenu();
869edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
8708a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
8718a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.beginSection("Set display photo & name");
872dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
87302eaf11669d25fd885606b3b0700358323532cddBrian Attwell        mPhotoView.setIsBusiness(mContactData.isDisplayNameFromOrganization());
8746219668d0612f7522bd15a9d34c6232cb15b9a6cYorke Lee        mPhotoSetter.setupContactPhoto(data, mPhotoView);
87531b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        extractAndApplyTintFromPhotoViewAsynchronously();
8764936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        analyzeWhitenessOfPhotoAsynchronously();
877333091ae754ddfc25714c14b9b89534be24379f9Paul Soulos        setHeaderNameText(ContactDisplayUtils.getDisplayName(this, data).toString());
878edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
8798a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
880dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
8816bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        mEntriesAndActionsTask = new AsyncTask<Void, Void, Cp2DataCardModel>() {
8828a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
8838a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            @Override
8846bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            protected Cp2DataCardModel doInBackground(
885eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    Void... params) {
886eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                return generateDataModelFromContact(data);
8878a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            }
8888a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
8898a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            @Override
8906bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            protected void onPostExecute(Cp2DataCardModel cardDataModel) {
8916bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                super.onPostExecute(cardDataModel);
8928a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                // Check that original AsyncTask parameters are still valid and the activity
8938a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                // is still running before binding to UI. A new intent could invalidate
8948a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                // the results, for example.
8958a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                if (data == mContactData && !isCancelled()) {
8966bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                    bindDataToCards(cardDataModel);
8978a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    showActivity();
8988a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                }
8998a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            }
9008a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        };
9018a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        mEntriesAndActionsTask.execute();
9028a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
9038a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
9046bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private void bindDataToCards(Cp2DataCardModel cp2DataCardModel) {
9056bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        startInteractionLoaders(cp2DataCardModel);
9066bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        populateContactAndAboutCard(cp2DataCardModel);
907eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
908eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
9096bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private void startInteractionLoaders(Cp2DataCardModel cp2DataCardModel) {
9106bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final Map<String, List<DataItem>> dataItemsMap = cp2DataCardModel.dataItemsMap;
9116bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<DataItem> phoneDataItems = dataItemsMap.get(Phone.CONTENT_ITEM_TYPE);
91297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        if (phoneDataItems != null && phoneDataItems.size() == 1) {
91397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            mOnlyOnePhoneNumber = true;
91497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
915eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String[] phoneNumbers = null;
916eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (phoneDataItems != null) {
917eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            phoneNumbers = new String[phoneDataItems.size()];
918eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            for (int i = 0; i < phoneDataItems.size(); ++i) {
919eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                phoneNumbers[i] = ((PhoneDataItem) phoneDataItems.get(i)).getNumber();
920eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
921eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
922ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        final Bundle phonesExtraBundle = new Bundle();
923eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        phonesExtraBundle.putStringArray(KEY_LOADER_EXTRA_PHONES, phoneNumbers);
924eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
925eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("start sms loader");
9268a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        getLoaderManager().initLoader(
9278a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                LOADER_SMS_ID,
928ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                phonesExtraBundle,
929ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                mLoaderInteractionsCallbacks);
930ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        Trace.endSection();
931ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos
932ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        Trace.beginSection("start call log loader");
933ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        getLoaderManager().initLoader(
934ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                LOADER_CALL_LOG_ID,
935ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                phonesExtraBundle,
9368a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                mLoaderInteractionsCallbacks);
937899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos        Trace.endSection();
9388a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
939eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
940899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos        Trace.beginSection("start calendar loader");
9416bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<DataItem> emailDataItems = dataItemsMap.get(Email.CONTENT_ITEM_TYPE);
94297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        if (emailDataItems != null && emailDataItems.size() == 1) {
94397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            mOnlyOneEmail = true;
94497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
945eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String[] emailAddresses = null;
946eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (emailDataItems != null) {
947eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            emailAddresses = new String[emailDataItems.size()];
948eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            for (int i = 0; i < emailDataItems.size(); ++i) {
949eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                emailAddresses[i] = ((EmailDataItem) emailDataItems.get(i)).getAddress();
950eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
951eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
952ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos        final Bundle emailsExtraBundle = new Bundle();
953eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        emailsExtraBundle.putStringArray(KEY_LOADER_EXTRA_EMAILS, emailAddresses);
954899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos        getLoaderManager().initLoader(
955899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                LOADER_CALENDAR_ID,
956ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                emailsExtraBundle,
957899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                mLoaderInteractionsCallbacks);
9588a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
9598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
9608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
9618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private void showActivity() {
9628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mScroller != null) {
9638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            mScroller.setVisibility(View.VISIBLE);
9648a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            SchedulingUtils.doOnPreDraw(mScroller, /* drawNextFrame = */ false,
9658a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    new Runnable() {
9668a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                        @Override
9678a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                        public void run() {
9688a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                            runEntranceAnimation();
9698a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                        }
9708a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    });
9718a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
9728a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
9738a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
9746bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private List<List<Entry>> buildAboutCardEntries(Map<String, List<DataItem>> dataItemsMap) {
975a153dba33c2152332c5706178a367f52b0550723Paul Soulos        final List<List<Entry>> aboutCardEntries = new ArrayList<>();
976a153dba33c2152332c5706178a367f52b0550723Paul Soulos        for (String mimetype : SORTED_ABOUT_CARD_MIMETYPES) {
9776bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final List<DataItem> mimeTypeItems = dataItemsMap.get(mimetype);
978a153dba33c2152332c5706178a367f52b0550723Paul Soulos            if (mimeTypeItems == null) {
979a153dba33c2152332c5706178a367f52b0550723Paul Soulos                continue;
980a153dba33c2152332c5706178a367f52b0550723Paul Soulos            }
9816bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            // Set aboutCardTitleOut = null, since SORTED_ABOUT_CARD_MIMETYPES doesn't contain
9826bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            // the name mimetype.
9836bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final List<Entry> aboutEntries = dataItemsToEntries(mimeTypeItems,
9846bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                    /* aboutCardTitleOut = */ null);
985a153dba33c2152332c5706178a367f52b0550723Paul Soulos            if (aboutEntries.size() > 0) {
986a153dba33c2152332c5706178a367f52b0550723Paul Soulos                aboutCardEntries.add(aboutEntries);
987a153dba33c2152332c5706178a367f52b0550723Paul Soulos            }
988a153dba33c2152332c5706178a367f52b0550723Paul Soulos        }
989a153dba33c2152332c5706178a367f52b0550723Paul Soulos        return aboutCardEntries;
990a153dba33c2152332c5706178a367f52b0550723Paul Soulos    }
991a153dba33c2152332c5706178a367f52b0550723Paul Soulos
992a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    @Override
993a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    protected void onResume() {
994a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        super.onResume();
995a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        // If returning from a launched activity, repopulate the contact and about card
996a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        if (mHasIntentLaunched) {
997a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            mHasIntentLaunched = false;
9986bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            populateContactAndAboutCard(mCachedCp2DataCardModel);
999a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        }
100059a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell
100159a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        // When exiting the activity and resuming, we want to force a full reload of all the
100259a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        // interaction data in case something changed in the background. On screen rotation,
100359a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        // we don't need to do this. And, mCachedCp2DataCardModel will be null, so we won't.
100459a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        if (mCachedCp2DataCardModel != null) {
100559a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell            destroyInteractionLoaders();
100659a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell            startInteractionLoaders(mCachedCp2DataCardModel);
100759a585b78d061c84367ec24c71e137fae55d10ceBrian Attwell        }
1008a42ef76251778161d27bc07db214b8c81720e476Paul Soulos    }
1009a42ef76251778161d27bc07db214b8c81720e476Paul Soulos
10106bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private void populateContactAndAboutCard(Cp2DataCardModel cp2DataCardModel) {
10116bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        mCachedCp2DataCardModel = cp2DataCardModel;
10126bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        if (mHasIntentLaunched || cp2DataCardModel == null) {
1013a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            return;
1014a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        }
1015eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("bind contact card");
1016eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
10176bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> contactCardEntries = cp2DataCardModel.contactCardEntries;
10186bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> aboutCardEntries = cp2DataCardModel.aboutCardEntries;
10196bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final String customAboutCardName = cp2DataCardModel.customAboutCardName;
1020eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1021eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (contactCardEntries.size() > 0) {
1022eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            mContactCard.initialize(contactCardEntries,
1023eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    /* numInitialVisibleEntries = */ MIN_NUM_CONTACT_ENTRIES_SHOWN,
1024c8e2a91807b581194566eb45019fa16e2268b462Paul Soulos                    /* isExpanded = */ mContactCard.isExpanded(),
102589966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos                    /* isAlwaysExpanded = */ false,
10260cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                    mExpandingEntryCardViewListener,
10270cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                    mScroller);
1028eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            mContactCard.setVisibility(View.VISIBLE);
1029eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else {
1030eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            mContactCard.setVisibility(View.GONE);
1031eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1032eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
10338a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1034eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("bind about card");
1035c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        // Phonetic name is not a data item, so the entry needs to be created separately
1036c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        final String phoneticName = mContactData.getPhoneticName();
1037c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        if (!TextUtils.isEmpty(phoneticName)) {
1038c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos            Entry phoneticEntry = new Entry(/* viewId = */ -1,
1039c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* icon = */ null,
1040c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    getResources().getString(R.string.name_phonetic),
1041c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    phoneticName,
1042c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* text = */ null,
104323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    /* primaryContentDescription = */ null,
1044c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* intent = */ null,
1045c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* alternateIcon = */ null,
1046c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* alternateIntent = */ null,
1047c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* alternateContentDescription = */ null,
1048c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos                    /* shouldApplyColor = */ false,
10492a4207fb39330e840436215c896cde911489e111Paul Soulos                    /* isEditable = */ false,
10502a4207fb39330e840436215c896cde911489e111Paul Soulos                    /* EntryContextMenuInfo = */ new EntryContextMenuInfo(phoneticName,
105197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                            getResources().getString(R.string.name_phonetic),
105297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                            /* mimeType = */ null, /* id = */ -1, /* isPrimary = */ false),
105348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIcon = */ null,
105448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIntent = */ null,
105548290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    /* thirdContentDescription = */ null,
105648290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    /* iconResourceId = */ 0);
1057c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos            List<Entry> phoneticList = new ArrayList<>();
1058c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos            phoneticList.add(phoneticEntry);
1059a153dba33c2152332c5706178a367f52b0550723Paul Soulos            // Phonetic name comes after nickname. Check to see if the first entry type is nickname
1060a0fa4c18dc111ceea9ff47f35ee01fecc1003578Paul Soulos            if (aboutCardEntries.size() > 0 && aboutCardEntries.get(0).get(0).getHeader().equals(
1061a153dba33c2152332c5706178a367f52b0550723Paul Soulos                    getResources().getString(R.string.header_nickname_entry))) {
1062a153dba33c2152332c5706178a367f52b0550723Paul Soulos                aboutCardEntries.add(1, phoneticList);
1063a153dba33c2152332c5706178a367f52b0550723Paul Soulos            } else {
1064a153dba33c2152332c5706178a367f52b0550723Paul Soulos                aboutCardEntries.add(0, phoneticList);
1065a153dba33c2152332c5706178a367f52b0550723Paul Soulos            }
1066c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos        }
1067c6e110946e2c51be6276591b85ac8abe169534a0Paul Soulos
10686bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        if (!TextUtils.isEmpty(customAboutCardName)) {
10696bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            mAboutCard.setTitle(customAboutCardName);
10706bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        }
10716bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
1072cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos        if (aboutCardEntries.size() > 0) {
1073cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos            mAboutCard.initialize(aboutCardEntries,
1074cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    /* numInitialVisibleEntries = */ 1,
1075cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    /* isExpanded = */ true,
1076cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    /* isAlwaysExpanded = */ true,
1077cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    mExpandingEntryCardViewListener,
1078cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    mScroller);
1079cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos        }
10806095369885edcca566a812b551886e29c7ff8039Brian Attwell
10816095369885edcca566a812b551886e29c7ff8039Brian Attwell        if (contactCardEntries.size() == 0 && aboutCardEntries.size() == 0) {
10826095369885edcca566a812b551886e29c7ff8039Brian Attwell            initializeNoContactDetailCard();
10836095369885edcca566a812b551886e29c7ff8039Brian Attwell        } else {
10846095369885edcca566a812b551886e29c7ff8039Brian Attwell            mNoContactDetailsCard.setVisibility(View.GONE);
10856095369885edcca566a812b551886e29c7ff8039Brian Attwell        }
10866095369885edcca566a812b551886e29c7ff8039Brian Attwell
1087a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        // If the Recent card is already initialized (all recent data is loaded), show the About
1088a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        // card if it has entries. Otherwise About card visibility will be set in bindRecentData()
1089a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        if (isAllRecentDataLoaded() && aboutCardEntries.size() > 0) {
1090a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos            mAboutCard.setVisibility(View.VISIBLE);
1091a8fce966f48d84af82f5ad767aa7986740ca7b26Paul Soulos        }
1092eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
1093eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
1094eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1095eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    /**
10966095369885edcca566a812b551886e29c7ff8039Brian Attwell     * Create a card that shows "Add email" and "Add phone number" entries in grey.
10976095369885edcca566a812b551886e29c7ff8039Brian Attwell     */
10986095369885edcca566a812b551886e29c7ff8039Brian Attwell    private void initializeNoContactDetailCard() {
10996095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Drawable phoneIcon = getResources().getDrawable(
11006095369885edcca566a812b551886e29c7ff8039Brian Attwell                R.drawable.ic_phone_24dp).mutate();
11016095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Entry phonePromptEntry = new Entry(CARD_ENTRY_ID_EDIT_CONTACT,
11026095369885edcca566a812b551886e29c7ff8039Brian Attwell                phoneIcon, getString(R.string.quickcontact_add_phone_number),
110323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                /* subHeader = */ null, /* text = */ null, /* primaryContentDescription = */ null,
110423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                getEditContactIntent(),
1105dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                /* alternateIcon = */ null, /* alternateIntent = */ null,
1106714455bba22b99d168a2e864dfbc74a6e30dfdb6Paul Soulos                /* alternateContentDescription = */ null, /* shouldApplyColor = */ true,
110748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                /* isEditable = */ false, /* EntryContextMenuInfo = */ null,
110848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                /* thirdIcon = */ null, /* thirdIntent = */ null,
110948290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                /* thirdContentDescription = */ null, R.drawable.ic_phone_24dp);
11106095369885edcca566a812b551886e29c7ff8039Brian Attwell
11116095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Drawable emailIcon = getResources().getDrawable(
11126095369885edcca566a812b551886e29c7ff8039Brian Attwell                R.drawable.ic_email_24dp).mutate();
11136095369885edcca566a812b551886e29c7ff8039Brian Attwell        final Entry emailPromptEntry = new Entry(CARD_ENTRY_ID_EDIT_CONTACT,
11146095369885edcca566a812b551886e29c7ff8039Brian Attwell                emailIcon, getString(R.string.quickcontact_add_email), /* subHeader = */ null,
111523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                /* text = */ null, /* primaryContentDescription = */ null,
111623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                getEditContactIntent(), /* alternateIcon = */ null,
1117dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                /* alternateIntent = */ null, /* alternateContentDescription = */ null,
11182a4207fb39330e840436215c896cde911489e111Paul Soulos                /* shouldApplyColor = */ true, /* isEditable = */ false,
111948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                /* EntryContextMenuInfo = */ null, /* thirdIcon = */ null,
112048290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                /* thirdIntent = */ null, /* thirdContentDescription = */ null,
112148290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                R.drawable.ic_email_24dp);
11226095369885edcca566a812b551886e29c7ff8039Brian Attwell
11236095369885edcca566a812b551886e29c7ff8039Brian Attwell        final List<List<Entry>> promptEntries = new ArrayList<>();
11246095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.add(new ArrayList<Entry>(1));
11256095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.add(new ArrayList<Entry>(1));
11266095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.get(0).add(phonePromptEntry);
11276095369885edcca566a812b551886e29c7ff8039Brian Attwell        promptEntries.get(1).add(emailPromptEntry);
11286095369885edcca566a812b551886e29c7ff8039Brian Attwell
11296095369885edcca566a812b551886e29c7ff8039Brian Attwell        final int subHeaderTextColor = getResources().getColor(
11306095369885edcca566a812b551886e29c7ff8039Brian Attwell                R.color.quickcontact_entry_sub_header_text_color);
11316095369885edcca566a812b551886e29c7ff8039Brian Attwell        final PorterDuffColorFilter greyColorFilter =
11326095369885edcca566a812b551886e29c7ff8039Brian Attwell                new PorterDuffColorFilter(subHeaderTextColor, PorterDuff.Mode.SRC_ATOP);
1133c8e2a91807b581194566eb45019fa16e2268b462Paul Soulos        mNoContactDetailsCard.initialize(promptEntries, 2, /* isExpanded = */ true,
11340cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                /* isAlwaysExpanded = */ true, mExpandingEntryCardViewListener, mScroller);
11356095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setVisibility(View.VISIBLE);
11366095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setEntryHeaderColor(subHeaderTextColor);
11376095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNoContactDetailsCard.setColorAndFilter(subHeaderTextColor, greyColorFilter);
11386095369885edcca566a812b551886e29c7ff8039Brian Attwell    }
11396095369885edcca566a812b551886e29c7ff8039Brian Attwell
11406095369885edcca566a812b551886e29c7ff8039Brian Attwell    /**
1141eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * Builds the {@link DataItem}s Map out of the Contact.
1142eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @param data The contact to build the data from.
1143eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @return A pair containing a list of data items sorted within mimetype and sorted
1144eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     *  amongst mimetype. The map goes from mimetype string to the sorted list of data items within
1145eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     *  mimetype
1146eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     */
11476bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private Cp2DataCardModel generateDataModelFromContact(
1148eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            Contact data) {
1149eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("Build data items map");
1150eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1151eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final Map<String, List<DataItem>> dataItemsMap = new HashMap<>();
11528bf96e78497ea9c8c893bcb357fc1e3175fb2e9bBrian Attwell
11538a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final ResolveCache cache = ResolveCache.getInstance(this);
1154851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        for (RawContact rawContact : data.getRawContacts()) {
1155851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            for (DataItem dataItem : rawContact.getDataItems()) {
1156eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                dataItem.setRawContactId(rawContact.getId());
1157eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1158851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final String mimeType = dataItem.getMimeType();
1159eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (mimeType == null) continue;
1160eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
116147b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                final AccountType accountType = rawContact.getAccountType(this);
116247b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                final DataKind dataKind = AccountTypeManager.getInstance(this)
116347b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                        .getKindOrFallback(accountType, mimeType);
1164eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (dataKind == null) continue;
1165cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1166eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                dataItem.setDataKind(dataKind);
1167b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1168eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final boolean hasData = !TextUtils.isEmpty(dataItem.buildDataString(this,
1169eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        dataKind));
1170899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos
1171eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (isMimeExcluded(mimeType) || !hasData) continue;
1172edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1173eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                List<DataItem> dataItemListByType = dataItemsMap.get(mimeType);
1174eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (dataItemListByType == null) {
1175eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    dataItemListByType = new ArrayList<>();
1176eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    dataItemsMap.put(mimeType, dataItemListByType);
1177edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                }
1178eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                dataItemListByType.add(dataItem);
1179edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
1180edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
11818a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        Trace.endSection();
1182edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1183eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("sort within mimetypes");
118416339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos        /*
118516339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos         * Sorting is a multi part step. The end result is to a have a sorted list of the most
1186eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos         * used data items, one per mimetype. Then, within each mimetype, the list of data items
1187eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos         * for that type is also sorted, based off of {super primary, primary, times used} in that
1188eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos         * order.
118916339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos         */
1190eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<List<DataItem>> dataItemsList = new ArrayList<>();
1191eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        for (List<DataItem> mimeTypeDataItems : dataItemsMap.values()) {
1192eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Remove duplicate data items
1193eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            Collapser.collapseList(mimeTypeDataItems, this);
1194eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Sort within mimetype
1195eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            Collections.sort(mimeTypeDataItems, mWithinMimeTypeDataItemComparator);
1196eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Add to the list of data item lists
1197eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            dataItemsList.add(mimeTypeDataItems);
1198edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
1199eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
1200edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1201eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.beginSection("sort amongst mimetypes");
1202eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        // Sort amongst mimetypes to bubble up the top data items for the contact card
1203eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Collections.sort(dataItemsList, mAmongstMimeTypeDataItemComparator);
1204eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Trace.endSection();
120516339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos
12066bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        Trace.beginSection("cp2 data items to entries");
12076bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12086bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> contactCardEntries = new ArrayList<>();
12096bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<List<Entry>> aboutCardEntries = buildAboutCardEntries(dataItemsMap);
12106bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final MutableString aboutCardName = new MutableString();
12116bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12126bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        for (int i = 0; i < dataItemsList.size(); ++i) {
12136bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final List<DataItem> dataItemsByMimeType = dataItemsList.get(i);
12146bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final DataItem topDataItem = dataItemsByMimeType.get(0);
12156bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            if (SORTED_ABOUT_CARD_MIMETYPES.contains(topDataItem.getMimeType())) {
12166bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                // About card mimetypes are built in buildAboutCardEntries, skip here
12176bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                continue;
12186bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            } else {
12196bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                List<Entry> contactEntries = dataItemsToEntries(dataItemsList.get(i),
12206bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        aboutCardName);
12216bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                if (contactEntries.size() > 0) {
12226bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                    contactCardEntries.add(contactEntries);
12236bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                }
12246bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            }
12256bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        }
12266bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12276bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        Trace.endSection();
12286bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12296bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final Cp2DataCardModel dataModel = new Cp2DataCardModel();
12306bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.customAboutCardName = aboutCardName.value;
12316bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.aboutCardEntries = aboutCardEntries;
12326bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.contactCardEntries = contactCardEntries;
12336bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        dataModel.dataItemsMap = dataItemsMap;
12346bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        return dataModel;
12356bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    }
12366bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12376bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    /**
12386bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * Class used to hold the About card and Contact cards' data model that gets generated
12396bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * on a background thread. All data is from CP2.
12406bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     */
12416bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private static class Cp2DataCardModel {
12426bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        /**
12436bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell         * A map between a mimetype string and the corresponding list of data items. The data items
12446bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell         * are in sorted order using mWithinMimeTypeDataItemComparator.
12456bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell         */
12466bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public Map<String, List<DataItem>> dataItemsMap;
12476bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public List<List<Entry>> aboutCardEntries;
12486bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public List<List<Entry>> contactCardEntries;
12496bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public String customAboutCardName;
12506bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    }
12516bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell
12526bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private static class MutableString {
12536bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        public String value;
1254eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
1255edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1256eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    /**
1257eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * Converts a {@link DataItem} into an {@link ExpandingEntryCardView.Entry} for display.
1258eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * If the {@link ExpandingEntryCardView.Entry} has no visual elements, null is returned.
12596bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     *
12606bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * This runs on a background thread. This is set as static to avoid accidentally adding
12616bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     * additional dependencies on unsafe things (like the Activity).
12626bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell     *
1263eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @param dataItem The {@link DataItem} to convert.
12646a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * @param secondDataItem A second {@link DataItem} to help build a full entry for some
12656a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     *  mimetypes
1266eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     * @return The {@link ExpandingEntryCardView.Entry}, or null if no visual elements are present.
1267eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos     */
12686a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static Entry dataItemToEntry(DataItem dataItem, DataItem secondDataItem,
12696bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            Context context, Contact contactData,
12706bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final MutableString aboutCardName) {
1271eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Drawable icon = null;
1272eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String header = null;
1273eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String subHeader = null;
1274eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Drawable subHeaderIcon = null;
1275eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        String text = null;
1276eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Drawable textIcon = null;
127723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        StringBuilder primaryContentDescription = new StringBuilder();
1278eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        Intent intent = null;
127948ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos        boolean shouldApplyColor = true;
1280dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        Drawable alternateIcon = null;
1281dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        Intent alternateIntent = null;
128223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        StringBuilder alternateContentDescription = new StringBuilder();
1283eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final boolean isEditable = false;
12842a4207fb39330e840436215c896cde911489e111Paul Soulos        EntryContextMenuInfo entryContextMenuInfo = null;
128548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        Drawable thirdIcon = null;
128648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        Intent thirdIntent = null;
128748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        String thirdContentDescription = null;
128848290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos        int iconResourceId = 0;
1289eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
12906bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        context = context.getApplicationContext();
129123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        final Resources res = context.getResources();
1292eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        DataKind kind = dataItem.getDataKind();
1293eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1294eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (dataItem instanceof ImDataItem) {
1295eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final ImDataItem im = (ImDataItem) dataItem;
12966bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            intent = ContactsUtils.buildImIntent(context, im).first;
1297eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final boolean isEmail = im.isCreatedFromEmail();
12987de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            final int protocol;
12997de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            if (!im.isProtocolValid()) {
13007de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                protocol = Im.PROTOCOL_CUSTOM;
13017de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            } else {
13027de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : im.getProtocol();
13037de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            }
13047de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            if (protocol == Im.PROTOCOL_CUSTOM) {
13057de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                // If the protocol is custom, display the "IM" entry header as well to distinguish
13067de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                // this entry from other ones
130723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                header = res.getString(R.string.header_im_entry);
130823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                subHeader = Im.getProtocolLabel(res, protocol,
13097de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                        im.getCustomProtocol()).toString();
13107de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                text = im.getData();
13117de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            } else {
131223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                header = Im.getProtocolLabel(res, protocol,
13137de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                        im.getCustomProtocol()).toString();
13147de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                subHeader = im.getData();
13157de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos            }
131697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(im.getData(), header,
131797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1318eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof OrganizationDataItem) {
1319eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final OrganizationDataItem organization = (OrganizationDataItem) dataItem;
132023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_organization_entry);
1321eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = organization.getCompany();
132297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
132397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1324eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            text = organization.getTitle();
1325eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof NicknameDataItem) {
1326eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final NicknameDataItem nickname = (NicknameDataItem) dataItem;
1327eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Build nickname entries
1328eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final boolean isNameRawContact =
13296bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                (contactData.getNameRawContactId() == dataItem.getRawContactId());
1330eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1331eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final boolean duplicatesTitle =
1332eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                isNameRawContact
13336bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                && contactData.getDisplayNameSource() == DisplayNameSources.NICKNAME;
1334eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1335eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!duplicatesTitle) {
133623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                header = res.getString(R.string.header_nickname_entry);
1337eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                subHeader = nickname.getName();
133897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
133997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1340eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1341eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof NoteDataItem) {
1342eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final NoteDataItem note = (NoteDataItem) dataItem;
134323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_note_entry);
1344eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = note.getNote();
134597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
134697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1347eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof WebsiteDataItem) {
1348eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final WebsiteDataItem website = (WebsiteDataItem) dataItem;
134923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_website_entry);
1350eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = website.getUrl();
135197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
135297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1353eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            try {
13546bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                final WebAddress webAddress = new WebAddress(website.buildDataString(context,
13556bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        kind));
1356eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_VIEW, Uri.parse(webAddress.toString()));
1357eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } catch (final ParseException e) {
13586bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                Log.e(TAG, "Couldn't parse website: " + website.buildDataString(context, kind));
1359eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1360eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof EventDataItem) {
1361eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final EventDataItem event = (EventDataItem) dataItem;
13626bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final String dataString = event.buildDataString(context, kind);
1363eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final Calendar cal = DateUtils.parseDate(dataString, false);
1364eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (cal != null) {
1365eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final Date nextAnniversary =
1366eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                        DateUtils.getNextAnnualDate(cal);
1367eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
1368eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                builder.appendPath("time");
1369eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                ContentUris.appendId(builder, nextAnniversary.getTime());
1370eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_VIEW).setData(builder.build());
1371eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
137223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_event_entry);
1373f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            if (event.hasKindTypeColumn(kind)) {
137423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                subHeader = Event.getTypeLabel(res, event.getKindTypeColumn(kind),
13757de6f85b0ee66deda13505f545c6b7125b2ac462Paul Soulos                        event.getLabel()).toString();
1376f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            }
13776bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            text = DateUtils.formatDate(context, dataString);
137897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(text, header,
137997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1380eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof RelationDataItem) {
1381eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final RelationDataItem relation = (RelationDataItem) dataItem;
13826bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            final String dataString = relation.buildDataString(context, kind);
1383eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(dataString)) {
1384eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_SEARCH);
1385eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent.putExtra(SearchManager.QUERY, dataString);
1386eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent.setType(Contacts.CONTENT_TYPE);
1387eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
138823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            header = res.getString(R.string.header_relation_entry);
1389eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            subHeader = relation.getName();
139097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            entryContextMenuInfo = new EntryContextMenuInfo(subHeader, header,
139197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                    dataItem.getMimeType(), dataItem.getId(), dataItem.isSuperPrimary());
1392f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            if (relation.hasKindTypeColumn(kind)) {
139323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                text = Relation.getTypeLabel(res,
13946bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        relation.getKindTypeColumn(kind),
1395f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                        relation.getLabel()).toString();
1396f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos            }
1397eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof PhoneDataItem) {
1398eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final PhoneDataItem phone = (PhoneDataItem) dataItem;
1399eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(phone.getNumber())) {
140023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(res.getString(R.string.call_other)).append(" ");
1401c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell                header = sBidiFormatter.unicodeWrap(phone.buildDataString(context, kind),
1402c62cc7931593b4137f8a507689b653e1e15e1260Brian Attwell                        TextDirectionHeuristics.LTR);
14032a4207fb39330e840436215c896cde911489e111Paul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(header,
140497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        res.getString(R.string.phoneLabelsGroup), dataItem.getMimeType(),
140597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getId(), dataItem.isSuperPrimary());
1406f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                if (phone.hasKindTypeColumn(kind)) {
140723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    text = Phone.getTypeLabel(res, phone.getKindTypeColumn(kind),
1408f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                            phone.getLabel()).toString();
140923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(text).append(" ");
1410f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                }
141123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(header);
141223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                icon = res.getDrawable(R.drawable.ic_phone_24dp);
141348290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId = R.drawable.ic_phone_24dp;
14146bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                if (PhoneCapabilityTester.isPhone(context)) {
1415eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    intent = CallUtil.getCallIntent(phone.getNumber());
141616339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos                }
1417dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                alternateIntent = new Intent(Intent.ACTION_SENDTO,
14181cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                        Uri.fromParts(ContactsUtils.SCHEME_SMSTO, phone.getNumber(), null));
141948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
142023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateIcon = res.getDrawable(R.drawable.ic_message_24dp);
142123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.append(res.getString(R.string.sms_custom, header));
142248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
142348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                // Add video call button if supported
1424f764730a34da560db87206f9a48390d4c8085365Paul Soulos                if (CallUtil.isVideoEnabled(context)) {
142523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    thirdIcon = res.getDrawable(R.drawable.ic_videocam);
142648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    thirdIntent = CallUtil.getVideoCallIntent(phone.getNumber(),
142748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                            CALL_ORIGIN_QUICK_CONTACTS_ACTIVITY);
142848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    thirdContentDescription =
142923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                            res.getString(R.string.description_video_call);
143048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                }
1431eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1432eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof EmailDataItem) {
1433eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final EmailDataItem email = (EmailDataItem) dataItem;
1434eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String address = email.getData();
1435eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(address)) {
143623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(res.getString(R.string.email_other)).append(" ");
14371cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                final Uri mailUri = Uri.fromParts(ContactsUtils.SCHEME_MAILTO, address, null);
1438eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = new Intent(Intent.ACTION_SENDTO, mailUri);
1439eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                header = email.getAddress();
14402a4207fb39330e840436215c896cde911489e111Paul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(header,
144197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        res.getString(R.string.emailLabelsGroup), dataItem.getMimeType(),
144297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getId(), dataItem.isSuperPrimary());
1443f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                if (email.hasKindTypeColumn(kind)) {
144423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    text = Email.getTypeLabel(res, email.getKindTypeColumn(kind),
1445f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                            email.getLabel()).toString();
144623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(text).append(" ");
1447f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                }
144823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(header);
144923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                icon = res.getDrawable(R.drawable.ic_email_24dp);
145048290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId = R.drawable.ic_email_24dp;
1451eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1452eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof StructuredPostalDataItem) {
1453eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            StructuredPostalDataItem postal = (StructuredPostalDataItem) dataItem;
1454eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String postalAddress = postal.getFormattedAddress();
1455eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(postalAddress)) {
145623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(res.getString(R.string.map_other)).append(" ");
1457eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = StructuredPostalUtils.getViewPostalAddressIntent(postalAddress);
1458eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                header = postal.getFormattedAddress();
14592a4207fb39330e840436215c896cde911489e111Paul Soulos                entryContextMenuInfo = new EntryContextMenuInfo(header,
146097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        res.getString(R.string.postalLabelsGroup), dataItem.getMimeType(),
146197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        dataItem.getId(), dataItem.isSuperPrimary());
1462f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                if (postal.hasKindTypeColumn(kind)) {
146323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    text = StructuredPostal.getTypeLabel(res,
1464f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                            postal.getKindTypeColumn(kind), postal.getLabel()).toString();
146523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(text).append(" ");
1466f9d5c0e24d1b11527475227549f9530127e9dc07Paul Soulos                }
146723e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.append(header);
14686a4d2736d772cc5cbb79d04e115f2d6117826860Paul Soulos                alternateIntent =
14696a4d2736d772cc5cbb79d04e115f2d6117826860Paul Soulos                        StructuredPostalUtils.getViewPostalAddressDirectionsIntent(postalAddress);
147023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateIcon = res.getDrawable(R.drawable.ic_directions_24dp);
147123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.append(res.getString(
147223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                        R.string.content_description_directions)).append(" ").append(header);
147323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                icon = res.getDrawable(R.drawable.ic_place_24dp);
147448290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId = R.drawable.ic_place_24dp;
1475eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1476eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof SipAddressDataItem) {
14776bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            if (PhoneCapabilityTester.isSipPhone(context)) {
1478eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final SipAddressDataItem sip = (SipAddressDataItem) dataItem;
1479eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                final String address = sip.getSipAddress();
1480eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                if (!TextUtils.isEmpty(address)) {
148123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(res.getString(R.string.call_other)).append(
148223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                            " ");
14831cd88e3ecfa72f43c3fe25c912d9f67848f11e60Jay Shrauner                    final Uri callUri = Uri.fromParts(PhoneAccount.SCHEME_SIP, address, null);
1484eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    intent = CallUtil.getCallIntent(callUri);
14851cda01b35a37f79b22e907cc970314b8c0a9e00cPaul Soulos                    header = address;
14862a4207fb39330e840436215c896cde911489e111Paul Soulos                    entryContextMenuInfo = new EntryContextMenuInfo(header,
148797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                            res.getString(R.string.phoneLabelsGroup), dataItem.getMimeType(),
148897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                            dataItem.getId(), dataItem.isSuperPrimary());
14891cda01b35a37f79b22e907cc970314b8c0a9e00cPaul Soulos                    if (sip.hasKindTypeColumn(kind)) {
149023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                        text = SipAddress.getTypeLabel(res,
14916bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                                sip.getKindTypeColumn(kind), sip.getLabel()).toString();
149223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                        primaryContentDescription.append(text).append(" ");
14931cda01b35a37f79b22e907cc970314b8c0a9e00cPaul Soulos                    }
149423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    primaryContentDescription.append(header);
149523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    icon = res.getDrawable(R.drawable.ic_dialer_sip_black_24dp);
149648290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    iconResourceId = R.drawable.ic_dialer_sip_black_24dp;
149716339336653fa028a2e02e1eee92851fe5084d1cPaul Soulos                }
1498edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
1499eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else if (dataItem instanceof StructuredNameDataItem) {
1500eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final String givenName = ((StructuredNameDataItem) dataItem).getGivenName();
1501eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            if (!TextUtils.isEmpty(givenName)) {
150223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                aboutCardName.value = res.getString(R.string.about_card_title) +
15036bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        " " + givenName;
1504eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            } else {
150523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                aboutCardName.value = res.getString(R.string.about_card_title);
1506eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1507eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } else {
1508eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Custom DataItem
15096bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            header = dataItem.buildDataStringForDisplay(context, kind);
1510eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            text = kind.typeColumn;
1511eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            intent = new Intent(Intent.ACTION_VIEW);
151260e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            final Uri uri = ContentUris.withAppendedId(Data.CONTENT_URI, dataItem.getId());
151360e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            intent.setDataAndType(uri, dataItem.getMimeType());
1514e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos
1515e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            if (intent != null) {
1516e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                final String mimetype = intent.getType();
1517e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos
15186a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                // Build advanced entry for known 3p types. Otherwise default to ResolveCache icon.
1519e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                switch (mimetype) {
1520e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                    case MIMETYPE_GPLUS_PROFILE:
15216a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // If a secondDataItem is available, use it to build an entry with
15226a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // alternate actions
15236a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        if (secondDataItem != null) {
152423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                            icon = res.getDrawable(R.drawable.ic_google_plus_24dp);
15256a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            alternateIcon = res.getDrawable(R.drawable.ic_add_to_circles_black_24);
15266a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            final GPlusOrHangoutsDataItemModel itemModel =
15276a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                    new GPlusOrHangoutsDataItemModel(intent, alternateIntent,
15286a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            dataItem, secondDataItem, alternateContentDescription,
15296a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            header, text, context);
15306a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
153197b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            populateGPlusOrHangoutsDataItemModel(itemModel);
153297b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            intent = itemModel.intent;
153397b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateIntent = itemModel.alternateIntent;
153497b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateContentDescription = itemModel.alternateContentDescription;
153597b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            header = itemModel.header;
153697b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            text = itemModel.text;
15376a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        } else {
15386a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            if (GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE.equals(
15396a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                    intent.getDataString())) {
15406a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_add_to_circles_black_24);
15416a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            } else {
15426a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_google_plus_24dp);
15436a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            }
1544e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        }
1545e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        break;
1546e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                    case MIMETYPE_HANGOUTS:
15476a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // If a secondDataItem is available, use it to build an entry with
15486a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        // alternate actions
15496a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        if (secondDataItem != null) {
155023e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                            icon = res.getDrawable(R.drawable.ic_hangout_24dp);
15516a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            alternateIcon = res.getDrawable(R.drawable.ic_hangout_video_24dp);
155297b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            final GPlusOrHangoutsDataItemModel itemModel =
15536a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                    new GPlusOrHangoutsDataItemModel(intent, alternateIntent,
15546a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            dataItem, secondDataItem, alternateContentDescription,
15556a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                            header, text, context);
15566a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
155797b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            populateGPlusOrHangoutsDataItemModel(itemModel);
155897b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            intent = itemModel.intent;
155997b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateIntent = itemModel.alternateIntent;
156097b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            alternateContentDescription = itemModel.alternateContentDescription;
156197b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            header = itemModel.header;
156297b1e2d6206ad8f64af6bc935451654204706661Paul Soulos                            text = itemModel.text;
15636a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        } else {
15646a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            if (HANGOUTS_DATA_5_VIDEO.equals(intent.getDataString())) {
15656a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_hangout_video_24dp);
15666a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            } else {
15676a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                                icon = res.getDrawable(R.drawable.ic_hangout_24dp);
15686a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            }
1569e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        }
1570e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        break;
1571e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                    default:
157297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                        entryContextMenuInfo = new EntryContextMenuInfo(header, mimetype,
157397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                                dataItem.getMimeType(), dataItem.getId(),
157497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                                dataItem.isSuperPrimary());
15756bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell                        icon = ResolveCache.getInstance(context).getIcon(
1576e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                                dataItem.getMimeType(), intent);
1577e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        // Call mutate to create a new Drawable.ConstantState for color filtering
1578e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        if (icon != null) {
1579e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                            icon.mutate();
1580e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                        }
158148ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                        shouldApplyColor = false;
1582e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos                }
1583e005566a1616d6797fb7e204d0d41bd341b37543Paul Soulos            }
1584eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1585b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1586eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (intent != null) {
1587eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            // Do not set the intent is there are no resolves
15886bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            if (!PhoneCapabilityTester.isIntentRegistered(context, intent)) {
1589eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                intent = null;
1590eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1591eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1592eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1593dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        if (alternateIntent != null) {
1594dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            // Do not set the alternate intent is there are no resolves
15956bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            if (!PhoneCapabilityTester.isIntentRegistered(context, alternateIntent)) {
1596dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                alternateIntent = null;
1597f0d04c11b649e953177e79722d05fa048e53273dJay Shrauner            } else if (TextUtils.isEmpty(alternateContentDescription)) {
1598f0d04c11b649e953177e79722d05fa048e53273dJay Shrauner                // Attempt to use package manager to find a suitable content description if needed
159923e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.append(getIntentResolveLabel(alternateIntent, context));
1600dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            }
1601dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
1602dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1603eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        // If the Entry has no visual elements, return null
1604eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (icon == null && TextUtils.isEmpty(header) && TextUtils.isEmpty(subHeader) &&
1605eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                subHeaderIcon == null && TextUtils.isEmpty(text) && textIcon == null) {
1606eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            return null;
1607eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1608eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
1609fa238949855fba3b28a57fad3d585b13e80362bbBrian Attwell        // Ignore dataIds from the Me profile.
1610ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos        final int dataId = dataItem.getId() > Integer.MAX_VALUE ?
1611ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                -1 : (int) dataItem.getId();
1612ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
161323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        return new Entry(dataId, icon, header, subHeader, subHeaderIcon, text, textIcon,
161423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                primaryContentDescription.toString(), intent, alternateIcon, alternateIntent,
161523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                alternateContentDescription.toString(), shouldApplyColor, isEditable,
161648290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                entryContextMenuInfo, thirdIcon, thirdIntent, thirdContentDescription,
161748290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                iconResourceId);
1618eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
1619eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
16206bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private List<Entry> dataItemsToEntries(List<DataItem> dataItems,
16216bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            MutableString aboutCardTitleOut) {
16226a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Hangouts and G+ use two data items to create one entry.
16236a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        if (dataItems.get(0).getMimeType().equals(MIMETYPE_GPLUS_PROFILE) ||
16246a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataItems.get(0).getMimeType().equals(MIMETYPE_HANGOUTS)) {
16256a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            return gPlusOrHangoutsDataItemsToEntries(dataItems);
16266a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        } else {
16276a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            final List<Entry> entries = new ArrayList<>();
16286a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            for (DataItem dataItem : dataItems) {
16296a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                final Entry entry = dataItemToEntry(dataItem, /* secondDataItem = */ null,
16306a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        this, mContactData, aboutCardTitleOut);
16316a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                if (entry != null) {
16326a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    entries.add(entry);
16336a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                }
16346a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            }
16356a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            return entries;
16366a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
16376a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    }
16386a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
16396a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    /**
16406a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * G+ and Hangout entries are unique in that a single ExpandingEntryCardView.Entry consists
16416a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * of two data items. This method attempts to build each entry using the two data items if
16426a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * they are available. If there are more or less than two data items, a fall back is used
16436a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * and each data item gets its own entry.
16446a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     */
16456a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private List<Entry> gPlusOrHangoutsDataItemsToEntries(List<DataItem> dataItems) {
1646eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<Entry> entries = new ArrayList<>();
16476a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        final Map<Long, List<DataItem>> buckets = new HashMap<>();
16486a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Put the data items into buckets based on the raw contact id
1649eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        for (DataItem dataItem : dataItems) {
16506a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            List<DataItem> bucket = buckets.get(dataItem.getRawContactId());
16516a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            if (bucket == null) {
16526a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                bucket = new ArrayList<>();
16536a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                buckets.put(dataItem.getRawContactId(), bucket);
16546a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            }
16556a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            bucket.add(dataItem);
16566a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
16576a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
16586a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Use the buckets to build entries. If a bucket contains two data items, build the special
16596a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // entry, otherwise fall back to the normal entry.
16606a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        for (List<DataItem> bucket : buckets.values()) {
16616a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            if (bucket.size() == 2) {
16626a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                // Use the pair to build an entry
16636a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                final Entry entry = dataItemToEntry(bucket.get(0),
16646a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        /* secondDataItem = */ bucket.get(1), this, mContactData,
16656a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        /* aboutCardName = */ null);
16666a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                if (entry != null) {
16676a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    entries.add(entry);
16686a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                }
16696a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            } else {
16706a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                for (DataItem dataItem : bucket) {
16716a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    final Entry entry = dataItemToEntry(dataItem, /* secondDataItem = */ null,
16726a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            this, mContactData, /* aboutCardName = */ null);
16736a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    if (entry != null) {
16746a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        entries.add(entry);
16756a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    }
16766a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                }
1677eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            }
1678eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
1679eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        return entries;
1680edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
1681edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
16826a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    /**
16836a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * Used for statically passing around G+ or Hangouts data items and entry fields to
16846a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     * populateGPlusOrHangoutsDataItemModel.
16856a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos     */
16866a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static final class GPlusOrHangoutsDataItemModel {
16876a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public Intent intent;
16886a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public Intent alternateIntent;
16896a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public DataItem dataItem;
16906a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public DataItem secondDataItem;
16916a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public StringBuilder alternateContentDescription;
16926a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public String header;
16936a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public String text;
16946a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public Context context;
16956a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
16966a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        public GPlusOrHangoutsDataItemModel(Intent intent, Intent alternateIntent, DataItem dataItem,
16976a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                DataItem secondDataItem, StringBuilder alternateContentDescription, String header,
16986a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                String text, Context context) {
16996a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.intent = intent;
17006a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.alternateIntent = alternateIntent;
17016a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.dataItem = dataItem;
17026a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.secondDataItem = secondDataItem;
17036a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.alternateContentDescription = alternateContentDescription;
17046a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.header = header;
17056a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.text = text;
17066a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            this.context = context;
17076a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
17086a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    }
17096a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
17106a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    private static void populateGPlusOrHangoutsDataItemModel(
17116a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            GPlusOrHangoutsDataItemModel dataModel) {
17126a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        final Intent secondIntent = new Intent(Intent.ACTION_VIEW);
17136a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        secondIntent.setDataAndType(ContentUris.withAppendedId(Data.CONTENT_URI,
17146a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataModel.secondDataItem.getId()), dataModel.secondDataItem.getMimeType());
17156a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // There is no guarantee the order the data items come in. Second
17166a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // data item does not necessarily mean it's the alternate.
17176a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        // Hangouts video and Add to circles should be alternate. Swap if needed
17186a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        if (HANGOUTS_DATA_5_VIDEO.equals(
17196a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataModel.dataItem.getContentValues().getAsString(Data.DATA5)) ||
17206a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE.equals(
17216a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
17226a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateIntent = dataModel.intent;
17236a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateContentDescription = new StringBuilder(dataModel.header);
17246a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
17256a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.intent = secondIntent;
17266a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.header = dataModel.secondDataItem.buildDataStringForDisplay(dataModel.context,
17276a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    dataModel.secondDataItem.getDataKind());
17286a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.text = dataModel.secondDataItem.getDataKind().typeColumn;
17296a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        } else if (HANGOUTS_DATA_5_MESSAGE.equals(
17306a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                dataModel.dataItem.getContentValues().getAsString(Data.DATA5)) ||
17316a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                GPLUS_PROFILE_DATA_5_VIEW_PROFILE.equals(
17326a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                        dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
17336a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateIntent = secondIntent;
17346a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos            dataModel.alternateContentDescription = new StringBuilder(
17356a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                    dataModel.secondDataItem.buildDataStringForDisplay(dataModel.context,
17366a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos                            dataModel.secondDataItem.getDataKind()));
17376a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos        }
17386a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos    }
17396a2a1a7d87cd3c59d0e09abce0739ab4175a670ePaul Soulos
17406bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell    private static String getIntentResolveLabel(Intent intent, Context context) {
17416bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        final List<ResolveInfo> matches = context.getPackageManager().queryIntentActivities(intent,
1742dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                PackageManager.MATCH_DEFAULT_ONLY);
1743dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1744dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        // Pick first match, otherwise best found
1745dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        ResolveInfo bestResolve = null;
1746dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final int size = matches.size();
1747dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        if (size == 1) {
1748dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            bestResolve = matches.get(0);
1749dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        } else if (size > 1) {
17506bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell            bestResolve = ResolveCache.getInstance(context).getBestResolve(intent, matches);
1751dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
1752dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1753dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        if (bestResolve == null) {
1754dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            return null;
1755dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
1756dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
17576bb01347eab60f95deafdfe523b0c368707210f3Brian Attwell        return String.valueOf(bestResolve.loadLabel(context.getPackageManager()));
1758dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos    }
1759dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
1760edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
176131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     * Asynchronously extract the most vibrant color from the PhotoView. Once extracted,
176231b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     * apply this tint to {@link MultiShrinkScroller}. This operation takes about 20-30ms
176331b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     * on a Nexus 5.
176431b2d42fb0889e61515d27314aa5a245147100daBrian Attwell     */
176531b2d42fb0889e61515d27314aa5a245147100daBrian Attwell    private void extractAndApplyTintFromPhotoViewAsynchronously() {
176631b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        if (mScroller == null) {
176731b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            return;
176831b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        }
176931b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        final Drawable imageViewDrawable = mPhotoView.getDrawable();
1770faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        new AsyncTask<Void, Void, MaterialPalette>() {
177131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            @Override
1772faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell            protected MaterialPalette doInBackground(Void... params) {
1773faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell
177495c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                if (imageViewDrawable instanceof BitmapDrawable
177595c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        && mContactData.getThumbnailPhotoBinaryData() != null
177695c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        && mContactData.getThumbnailPhotoBinaryData().length > 0) {
177795c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    // Perform the color analysis on the thumbnail instead of the full sized
177895c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    // image, so that our results will be as similar as possible to the Bugle
177995c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    // app.
178095c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    final Bitmap bitmap = BitmapFactory.decodeByteArray(
178195c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                            mContactData.getThumbnailPhotoBinaryData(), 0,
178295c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                            mContactData.getThumbnailPhotoBinaryData().length);
178395c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    try {
178495c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        final int primaryColor = colorFromBitmap(bitmap);
178595c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        if (primaryColor != 0) {
178695c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                            return mMaterialColorMapUtils.calculatePrimaryAndSecondaryColor(
178795c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                                    primaryColor);
178895c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        }
178995c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                    } finally {
179095c268e8dae6ed6b3bf6a205b02eadd995dec2c0Brian Attwell                        bitmap.recycle();
1791faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                    }
17928a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                }
17938a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                if (imageViewDrawable instanceof LetterTileDrawable) {
1794faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                    final int primaryColor = ((LetterTileDrawable) imageViewDrawable).getColor();
1795a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                    return mMaterialColorMapUtils.calculatePrimaryAndSecondaryColor(primaryColor);
179631b2d42fb0889e61515d27314aa5a245147100daBrian Attwell                }
1797a3859ed9ff9f315d492e199620a08ae35ab8569fBrian Attwell                return MaterialColorMapUtils.getDefaultPrimaryAndSecondaryColors(getResources());
179831b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            }
179931b2d42fb0889e61515d27314aa5a245147100daBrian Attwell
180031b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            @Override
1801faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell            protected void onPostExecute(MaterialPalette palette) {
1802faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                super.onPostExecute(palette);
18038571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                if (mHasComputedThemeColor) {
18048571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // If we had previously computed a theme color from the contact photo,
18058571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // then do not update the theme color. Changing the theme color several
18068571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // seconds after QC has started, as a result of an updated/upgraded photo,
18078571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // is a jarring experience. On the other hand, changing the theme color after
18088571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    // a rotation or onNewIntent() is perfectly fine.
18098571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    return;
18108571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                }
18118571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                // Check that the Photo has not changed. If it has changed, the new tint
18128571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                // color needs to be extracted
18138571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                if (imageViewDrawable == mPhotoView.getDrawable()) {
18148571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    mHasComputedThemeColor = true;
1815faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                    setThemeColor(palette);
181631b2d42fb0889e61515d27314aa5a245147100daBrian Attwell                }
181731b2d42fb0889e61515d27314aa5a245147100daBrian Attwell            }
181831b2d42fb0889e61515d27314aa5a245147100daBrian Attwell        }.execute();
181931b2d42fb0889e61515d27314aa5a245147100daBrian Attwell    }
182031b2d42fb0889e61515d27314aa5a245147100daBrian Attwell
18214936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell    /**
18224936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell     * Examine how many white pixels are in the bitmap in order to determine whether or not
18234936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell     * we need gradient overlays on top of the image.
18244936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell     */
18254936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell    private void analyzeWhitenessOfPhotoAsynchronously() {
18264936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        final Drawable imageViewDrawable = mPhotoView.getDrawable();
18274936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        new AsyncTask<Void, Void, Boolean>() {
18284936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            @Override
18294936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            protected Boolean doInBackground(Void... params) {
18304936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                if (imageViewDrawable instanceof BitmapDrawable) {
18314936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                    final Bitmap bitmap = ((BitmapDrawable) imageViewDrawable).getBitmap();
18324936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                    return WhitenessUtils.isBitmapWhiteAtTopOrBottom(bitmap);
18334936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                }
18344936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                return !(imageViewDrawable instanceof LetterTileDrawable);
18354936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            }
18364936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell
18374936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            @Override
18384936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            protected void onPostExecute(Boolean isWhite) {
18394936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                super.onPostExecute(isWhite);
18404936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell                mScroller.setUseGradient(isWhite);
18414936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell            }
18424936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell        }.execute();
18434936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell    }
18444936a92aeef739ae6b57dad00f385307d1b1c5b8Brian Attwell
1845faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell    private void setThemeColor(MaterialPalette palette) {
18469b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        // If the color is invalid, use the predefined default
1847faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        final int primaryColor = palette.mPrimaryColor;
1848faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mScroller.setHeaderTintColor(primaryColor);
1849faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mStatusBarColor = palette.mSecondaryColor;
18509b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        updateStatusBarColor();
18518571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell
18529b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell        mColorFilter =
1853faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell                new PorterDuffColorFilter(primaryColor, PorterDuff.Mode.SRC_ATOP);
1854faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mContactCard.setColorAndFilter(primaryColor, mColorFilter);
1855faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mRecentCard.setColorAndFilter(primaryColor, mColorFilter);
1856faf973989af7ac3b735c2aee1bec22ef6608b123Brian Attwell        mAboutCard.setColorAndFilter(primaryColor, mColorFilter);
18579b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell    }
18589b889e6ef4534db6925e3f915bed281733ea8bc3Brian Attwell
18598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private void updateStatusBarColor() {
18608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mScroller == null) {
18618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            return;
18628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
18638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final int desiredStatusBarColor;
18648a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // Only use a custom status bar color if QuickContacts touches the top of the viewport.
18658a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mScroller.getScrollNeededToBeFullScreen() <= 0) {
18668a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            desiredStatusBarColor = mStatusBarColor;
18678a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        } else {
18688a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            desiredStatusBarColor = Color.TRANSPARENT;
18698a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
18708a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // Animate to the new color.
1871847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        final ObjectAnimator animation = ObjectAnimator.ofInt(getWindow(), "statusBarColor",
1872847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell                getWindow().getStatusBarColor(), desiredStatusBarColor);
1873847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        animation.setDuration(ANIMATION_STATUS_BAR_COLOR_CHANGE_DURATION);
1874847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        animation.setEvaluator(new ArgbEvaluator());
1875847bf2cd3946b1801c83c745d7183aed5143b44cBrian Attwell        animation.start();
18768a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
18778a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
18788a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    private int colorFromBitmap(Bitmap bitmap) {
18798a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // Author of Palette recommends using 24 colors when analyzing profile photos.
18808a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final int NUMBER_OF_PALETTE_COLORS = 24;
18818a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        final Palette palette = Palette.generate(bitmap, NUMBER_OF_PALETTE_COLORS);
1882a0f20f77e1b4f6cde5934d8b3348d93b58fd6362Brian Attwell        if (palette != null && palette.getVibrantSwatch() != null) {
1883a0f20f77e1b4f6cde5934d8b3348d93b58fd6362Brian Attwell            return palette.getVibrantSwatch().getRgb();
18848a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
18858a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        return 0;
18868a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
18878a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1888b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private List<Entry> contactInteractionsToEntries(List<ContactInteraction> interactions) {
1889eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<Entry> entries = new ArrayList<>();
1890b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        for (ContactInteraction interaction : interactions) {
1891ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            entries.add(new Entry(/* id = */ -1,
1892ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos                    interaction.getIcon(this),
1893b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getViewHeader(this),
1894b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getViewBody(this),
1895b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getBodyIcon(this),
1896b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getViewFooter(this),
1897b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getFooterIcon(this),
189823e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                    interaction.getContentDescription(this),
1899b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    interaction.getIntent(),
1900dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    /* alternateIcon = */ null,
1901dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    /* alternateIntent = */ null,
1902dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    /* alternateContentDescription = */ null,
190348ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                    /* shouldApplyColor = */ true,
19042a4207fb39330e840436215c896cde911489e111Paul Soulos                    /* isEditable = */ false,
190548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* EntryContextMenuInfo = */ null,
190648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIcon = */ null,
190748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    /* thirdIntent = */ null,
190848290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    /* thirdContentDescription = */ null,
190948290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    interaction.getIconResourceId()));
1910b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
1911b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        return entries;
1912b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    }
1913b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1914eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final LoaderCallbacks<Contact> mLoaderContactCallbacks =
1915851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            new LoaderCallbacks<Contact>() {
1916cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
1917851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoaderReset(Loader<Contact> loader) {
1918405ae406379ad9c47770783afc76a660f6c55fcaPaul Soulos            mContactData = null;
1919cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
1920cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1921cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
1922851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoadFinished(Loader<Contact> loader, Contact data) {
19238a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            Trace.beginSection("onLoadFinished()");
1924930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell            try {
19258a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1926930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                if (isFinishing()) {
1927930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    return;
1928930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                }
1929930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                if (data.isError()) {
1930930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    // This shouldn't ever happen, so throw an exception. The {@link ContactLoader}
1931930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    // should log the actual exception.
1932930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    throw new IllegalStateException("Failed to load contact", data.getException());
1933930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                }
1934930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                if (data.isNotFound()) {
19358a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    Log.i(TAG, "No contact found: " + ((ContactLoader)loader).getLookupUri());
19368a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                    Toast.makeText(QuickContactActivity.this, R.string.invalidContactMessage,
19378a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                            Toast.LENGTH_LONG).show();
1938930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    finish();
1939930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                    return;
19408a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell                }
1941cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1942930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                bindContactData(data);
1943cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1944930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell            } finally {
1945930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell                Trace.endSection();
1946930da3ae6e392777986ed0722c5480caf1bd9e7eBrian Attwell            }
1947cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
1948cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
1949cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
1950851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public Loader<Contact> onCreateLoader(int id, Bundle args) {
1951cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (mLookupUri == null) {
1952cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                Log.wtf(TAG, "Lookup uri wasn't initialized. Loader was started too early");
1953cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
1954d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Load all contact data. We need loadGroupMetaData=true to determine whether the
1955d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // contact is invisible. If it is, we need to display an "Add to Contacts" MenuItem.
1956b2b435a944947fbf1965c3bb7c202a97f0273259Yorke Lee            return new ContactLoader(getApplicationContext(), mLookupUri,
1957d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    true /*loadGroupMetaData*/, false /*loadInvitableAccountTypes*/,
19588571dd3953ddf2cf8442335657a1945487d665a1Brian Attwell                    true /*postViewNotification*/, true /*computeFormattedPhoneNumber*/);
1959cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
1960cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann    };
1961b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1962b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    @Override
1963b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    public void onBackPressed() {
1964b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        if (mScroller != null) {
19658477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            if (!mIsExitAnimationInProgress) {
19668477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell                mScroller.scrollOffBottom();
19678477eafe57bca7b6b72da6e2e419ebeaf4de9674Brian Attwell            }
1968b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        } else {
1969b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell            super.onBackPressed();
1970b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell        }
1971b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell    }
1972b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
19738a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    @Override
19748a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    public void finish() {
19758a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.finish();
19768a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
19778a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        // override transitions to skip the standard window animations
19788a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        overridePendingTransition(0, 0);
19798a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
19808a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
1981eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    private final LoaderCallbacks<List<ContactInteraction>> mLoaderInteractionsCallbacks =
1982b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            new LoaderCallbacks<List<ContactInteraction>>() {
1983b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
1984b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        @Override
1985b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        public Loader<List<ContactInteraction>> onCreateLoader(int id, Bundle args) {
1986b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            Loader<List<ContactInteraction>> loader = null;
1987b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            switch (id) {
1988b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                case LOADER_SMS_ID:
1989b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    loader = new SmsInteractionsLoader(
1990b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                            QuickContactActivity.this,
1991ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            args.getStringArray(KEY_LOADER_EXTRA_PHONES),
1992b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                            MAX_SMS_RETRIEVE);
1993b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    break;
1994899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                case LOADER_CALENDAR_ID:
1995ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    final String[] emailsArray = args.getStringArray(KEY_LOADER_EXTRA_EMAILS);
1996ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    List<String> emailsList = null;
1997ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    if (emailsArray != null) {
1998ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                        emailsList = Arrays.asList(args.getStringArray(KEY_LOADER_EXTRA_EMAILS));
1999ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                    }
2000899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                    loader = new CalendarInteractionsLoader(
2001899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            QuickContactActivity.this,
2002ae4cafed699b7cd6c5d4dad855bc0d4948452983Paul Soulos                            emailsList,
2003899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            MAX_FUTURE_CALENDAR_RETRIEVE,
2004899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            MAX_PAST_CALENDAR_RETRIEVE,
2005899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            FUTURE_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR,
2006899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                            PAST_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR);
2007899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos                    break;
2008ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                case LOADER_CALL_LOG_ID:
2009ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                    loader = new CallLogInteractionsLoader(
2010ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            QuickContactActivity.this,
2011ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            args.getStringArray(KEY_LOADER_EXTRA_PHONES),
2012ab840448dd00ce3f02ec7317df69b24613ade8a9Paul Soulos                            MAX_CALL_LOG_RETRIEVE);
2013b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            }
2014b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            return loader;
2015b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
2016b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2017b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        @Override
2018b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        public void onLoadFinished(Loader<List<ContactInteraction>> loader,
2019b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                List<ContactInteraction> data) {
2020b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            mRecentLoaderResults.put(loader.getId(), data);
2021b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2022b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            if (isAllRecentDataLoaded()) {
2023b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                bindRecentData();
2024b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            }
2025b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
2026b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2027b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        @Override
2028b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        public void onLoaderReset(Loader<List<ContactInteraction>> loader) {
2029b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            mRecentLoaderResults.remove(loader.getId());
2030b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        }
2031b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    };
2032b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2033b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private boolean isAllRecentDataLoaded() {
2034b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos        return mRecentLoaderResults.size() == mRecentLoaderIds.length;
2035b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    }
2036b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
2037b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    private void bindRecentData() {
2038eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final List<ContactInteraction> allInteractions = new ArrayList<>();
203930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        final List<List<Entry>> interactionsWrapper = new ArrayList<>();
2040b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos
204130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        mRecentDataTask = new AsyncTask<Void, Void, Void>() {
2042b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            @Override
204330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            protected Void doInBackground(Void... params) {
204430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.beginSection("sort recent loader results");
204530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
204630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                for (List<ContactInteraction> loaderInteractions : mRecentLoaderResults.values()) {
204730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    allInteractions.addAll(loaderInteractions);
204830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
204930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
205030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // Sort the interactions by most recent
205130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Collections.sort(allInteractions, new Comparator<ContactInteraction>() {
205230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    @Override
205330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    public int compare(ContactInteraction a, ContactInteraction b) {
205430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                        return a.getInteractionDate() >= b.getInteractionDate() ? -1 : 1;
205530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    }
205630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                });
205730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
205830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.endSection();
205930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.beginSection("contactInteractionsToEntries");
206030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
206130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // Wrap each interaction in its own list so that an icon is displayed for each entry
206230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                for (Entry contactInteraction : contactInteractionsToEntries(allInteractions)) {
206330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    List<Entry> entryListWrapper = new ArrayList<>(1);
206430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    entryListWrapper.add(contactInteraction);
206530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    interactionsWrapper.add(entryListWrapper);
206630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
206730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
206830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.endSection();
206930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                return null;
2070b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos            }
207130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
207230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            @Override
207330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            protected void onPostExecute(Void aVoid) {
207430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                super.onPostExecute(aVoid);
207530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.beginSection("initialize recents card");
207630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
207730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                if (allInteractions.size() > 0) {
207830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mRecentCard.initialize(interactionsWrapper,
2079b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos                    /* numInitialVisibleEntries = */ MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN,
2080c8e2a91807b581194566eb45019fa16e2268b462Paul Soulos                    /* isExpanded = */ mRecentCard.isExpanded(), /* isAlwaysExpanded = */ false,
208130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                            mExpandingEntryCardViewListener, mScroller);
208230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mRecentCard.setVisibility(View.VISIBLE);
208330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
2084eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
208530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                Trace.endSection();
208630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell
208730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // About card is initialized along with the contact card, but since it appears after
208830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // the recent card in the UI, we hold off until making it visible until the recent
208930e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                // card is also ready to avoid stuttering.
209030e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                if (mAboutCard.shouldShow()) {
209130e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mAboutCard.setVisibility(View.VISIBLE);
209230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                } else {
209330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                    mAboutCard.setVisibility(View.GONE);
209430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                }
209530e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell                mRecentDataTask = null;
209630e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            }
209730e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        };
209830e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        mRecentDataTask.execute();
2099b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos    }
21008a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
21018a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    @Override
21028a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    protected void onStop() {
21038a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        super.onStop();
21048a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell
21058a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        if (mEntriesAndActionsTask != null) {
21068a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // Once the activity is stopped, we will no longer want to bind mEntriesAndActionsTask's
21078a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // results on the UI thread. In some circumstances Activities are killed without
21088a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // onStop() being called. This is not a problem, because in these circumstances
21098a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            // the entire process will be killed.
21108a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell            mEntriesAndActionsTask.cancel(/* mayInterruptIfRunning = */ false);
21118a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell        }
211230e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        if (mRecentDataTask != null) {
211330e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell            mRecentDataTask.cancel(/* mayInterruptIfRunning = */ false);
211430e1ef1927a1a21370b6b5dedd73540152062475Brian Attwell        }
21158a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell    }
211623889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos
211723889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos    /**
2118d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     * Returns true if it is possible to edit the current contact.
2119d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell     */
2120d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private boolean isContactEditable() {
2121d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        return mContactData != null && !mContactData.isDirectoryEntry();
2122d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2123d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2124a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell    /**
2125a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell     * Returns true if it is possible to share the current contact.
2126a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell     */
2127a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell    private boolean isContactShareable() {
2128a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell        return mContactData != null && !mContactData.isDirectoryEntry();
2129a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell    }
2130a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
21316095369885edcca566a812b551886e29c7ff8039Brian Attwell    private Intent getEditContactIntent() {
213263176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        final Intent intent = new Intent(Intent.ACTION_EDIT, mContactData.getLookupUri());
2133d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
21346095369885edcca566a812b551886e29c7ff8039Brian Attwell        return intent;
21356095369885edcca566a812b551886e29c7ff8039Brian Attwell    }
21366095369885edcca566a812b551886e29c7ff8039Brian Attwell
21376095369885edcca566a812b551886e29c7ff8039Brian Attwell    private void editContact() {
2138a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        mHasIntentLaunched = true;
2139c00a0b5370f0714f6af1ea9b3e29b10f25e91af0Zheng Fu        mContactLoader.cacheResult();
21406095369885edcca566a812b551886e29c7ff8039Brian Attwell        startActivityForResult(getEditContactIntent(), REQUEST_CODE_CONTACT_EDITOR_ACTIVITY);
2141d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2142d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2143d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    private void toggleStar(MenuItem starredMenuItem) {
2144d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        // Make sure there is a contact
214563176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        if (mContactData != null) {
2146d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Read the current starred value from the UI instead of using the last
2147d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // loaded state. This allows rapid tapping without writing the same
2148d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // value several times
2149d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final boolean isStarred = starredMenuItem.isChecked();
2150d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2151d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // To improve responsiveness, swap out the picture (and tag) in the UI already
2152333091ae754ddfc25714c14b9b89534be24379f9Paul Soulos            ContactDisplayUtils.configureStarredMenuItem(starredMenuItem,
2153d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    mContactData.isDirectoryEntry(), mContactData.isUserProfile(),
2154d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    !isStarred);
2155d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2156d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Now perform the real save
2157eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            final Intent intent = ContactSaveService.createSetStarredIntent(
215863176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell                    QuickContactActivity.this, mContactData.getLookupUri(), !isStarred);
2159d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            startService(intent);
216035ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell
216135ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            final CharSequence accessibilityText = !isStarred
216235ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell                    ? getResources().getText(R.string.description_action_menu_add_star)
216335ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell                    : getResources().getText(R.string.description_action_menu_remove_star);
216435ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            // Accessibility actions need to have an associated view. We can't access the MenuItem's
216535ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            // underlying view, so put this accessibility action on the root view.
216635ccdba7b8b2270204f7f96d824d258e408fe6efBrian Attwell            mScroller.announceForAccessibility(accessibilityText);
2167d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
2168d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2169d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2170752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    /**
2171752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     * Calls into the contacts provider to get a pre-authorized version of the given URI.
2172752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     */
2173752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private Uri getPreAuthorizedUri(Uri uri) {
2174752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Bundle uriBundle = new Bundle();
2175752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        uriBundle.putParcelable(ContactsContract.Authorization.KEY_URI_TO_AUTHORIZE, uri);
2176752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Bundle authResponse = getContentResolver().call(
2177752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                ContactsContract.AUTHORITY_URI,
2178752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                ContactsContract.Authorization.AUTHORIZATION_METHOD,
2179752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                null,
2180752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                uriBundle);
2181752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        if (authResponse != null) {
2182752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            return (Uri) authResponse.getParcelable(
2183752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    ContactsContract.Authorization.KEY_AUTHORIZED_URI);
2184752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        } else {
2185752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            return uri;
2186752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        }
2187752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    }
21882d150da246632b1649999cfabed776133b097775Brian Attwell
2189752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private void shareContact() {
2190752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final String lookupKey = mContactData.getLookupKey();
2191752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        Uri shareUri = Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, lookupKey);
2192752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        if (mContactData.isUserProfile()) {
2193752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            // User is sharing the profile.  We don't want to force the receiver to have
2194752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            // the highly-privileged READ_PROFILE permission, so we need to request a
2195752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            // pre-authorized URI from the provider.
2196752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            shareUri = getPreAuthorizedUri(shareUri);
2197752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        }
2198752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2199752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Intent intent = new Intent(Intent.ACTION_SEND);
2200752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        intent.setType(Contacts.CONTENT_VCARD_TYPE);
2201752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        intent.putExtra(Intent.EXTRA_STREAM, shareUri);
2202752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2203752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        // Launch chooser to share contact via
2204752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final CharSequence chooseTitle = getText(R.string.share_via);
2205752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final Intent chooseIntent = Intent.createChooser(intent, chooseTitle);
2206752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2207752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        try {
2208a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            mHasIntentLaunched = true;
2209752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            this.startActivity(chooseIntent);
2210eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        } catch (final ActivityNotFoundException ex) {
2211752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            Toast.makeText(this, R.string.share_error, Toast.LENGTH_SHORT).show();
2212752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        }
2213752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    }
2214752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2215752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    /**
2216752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     * Creates a launcher shortcut with the current contact.
2217752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell     */
2218752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    private void createLauncherShortcutWithContact() {
2219752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell        final ShortcutIntentBuilder builder = new ShortcutIntentBuilder(this,
2220752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                new OnShortcutIntentCreatedListener() {
2221752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2222752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    @Override
2223752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    public void onShortcutIntentCreated(Uri uri, Intent shortcutIntent) {
2224752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // Broadcast the shortcutIntent to the launcher to create a
2225752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // shortcut to this contact
2226752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        shortcutIntent.setAction(ACTION_INSTALL_SHORTCUT);
2227752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        QuickContactActivity.this.sendBroadcast(shortcutIntent);
2228752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2229752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // Send a toast to give feedback to the user that a shortcut to this
2230752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        // contact was added to the launcher.
2231752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                        Toast.makeText(QuickContactActivity.this,
2232752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                                R.string.createContactShortcutSuccessful,
2233752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                                Toast.LENGTH_SHORT).show();
2234752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                    }
2235752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
2236752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                });
223763176c96f33b5a0bcb25816c80889bb11e5c7152Brian Attwell        builder.createContactShortcutIntent(mContactData.getLookupUri());
2238752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell    }
2239752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell
224066965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell    private boolean isShortcutCreatable() {
224166965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        final Intent createShortcutIntent = new Intent();
224266965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        createShortcutIntent.setAction(ACTION_INSTALL_SHORTCUT);
224366965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        final List<ResolveInfo> receivers = getPackageManager()
224466965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell                .queryBroadcastReceivers(createShortcutIntent, 0);
224566965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell        return receivers != null && receivers.size() > 0;
224666965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell    }
224766965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell
2248d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    @Override
2249d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public boolean onCreateOptionsMenu(Menu menu) {
2250eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        final MenuInflater inflater = getMenuInflater();
2251d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        inflater.inflate(R.menu.quickcontact, menu);
2252d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        return true;
2253d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2254d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2255d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    @Override
2256d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public boolean onPrepareOptionsMenu(Menu menu) {
2257d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        if (mContactData != null) {
2258d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final MenuItem starredMenuItem = menu.findItem(R.id.menu_star);
2259333091ae754ddfc25714c14b9b89534be24379f9Paul Soulos            ContactDisplayUtils.configureStarredMenuItem(starredMenuItem,
2260d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    mContactData.isDirectoryEntry(), mContactData.isUserProfile(),
2261d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    mContactData.getStarred());
2262a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
2263d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            // Configure edit MenuItem
2264d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            final MenuItem editMenuItem = menu.findItem(R.id.menu_edit);
2265d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            editMenuItem.setVisible(true);
2266d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            if (DirectoryContactUtil.isDirectoryContact(mContactData) || InvisibleContactUtil
2267d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    .isInvisibleAndAddable(mContactData, this)) {
226830cfd121ad8c8adb83cf417ff1d40a8ba1e3761dBrian Attwell                editMenuItem.setIcon(R.drawable.ic_person_add_tinted_24dp);
22692e4214c79170cdb6c1b8b6ff0408925d3f512becBrian Attwell                editMenuItem.setTitle(R.string.menu_add_contact);
2270d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            } else if (isContactEditable()) {
2271d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                editMenuItem.setIcon(R.drawable.ic_create_24dp);
22722e4214c79170cdb6c1b8b6ff0408925d3f512becBrian Attwell                editMenuItem.setTitle(R.string.menu_editContact);
2273d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            } else {
2274d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                editMenuItem.setVisible(false);
2275d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            }
2276a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
2277a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell            final MenuItem shareMenuItem = menu.findItem(R.id.menu_share);
2278a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell            shareMenuItem.setVisible(isContactShareable());
2279a41d6d1c9d87fe81630426f537bdb864c1ee6db4Brian Attwell
228066965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell            final MenuItem shortcutMenuItem = menu.findItem(R.id.menu_create_contact_shortcut);
228166965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell            shortcutMenuItem.setVisible(isShortcutCreatable());
228266965e14e741be40f3f5ad6aa21a75795f9a1eb1Brian Attwell
22838a6d0022b07640d4a1fb8b264c8822bbab2981adPaul Soulos            return true;
2284d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
22858a6d0022b07640d4a1fb8b264c8822bbab2981adPaul Soulos        return false;
2286d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    }
2287d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell
2288d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    @Override
2289d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell    public boolean onOptionsItemSelected(MenuItem item) {
2290d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        switch (item.getItemId()) {
2291d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            case R.id.menu_star:
2292d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                toggleStar(item);
2293d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                return true;
2294d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            case R.id.menu_edit:
2295d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                if (DirectoryContactUtil.isDirectoryContact(mContactData)) {
2296ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // This action is used to launch the contact selector, with the option of
2297ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // creating a new contact. Creating a new contact is an INSERT, while selecting
2298ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // an exisiting one is an edit. The fields in the edit screen will be
2299ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // prepopulated with data.
2300ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2301ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
2302ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    intent.setType(Contacts.CONTENT_ITEM_TYPE);
2303ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2304fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    ArrayList<ContentValues> values = mContactData.getContentValues();
2305fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell
2306fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    // Only pre-fill the name field if the provided display name is an nickname
2307fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    // or better (e.g. structured name, nickname)
2308fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    if (mContactData.getDisplayNameSource() >= DisplayNameSources.NICKNAME) {
2309ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        intent.putExtra(Intents.Insert.NAME, mContactData.getDisplayName());
2310fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                    } else if (mContactData.getDisplayNameSource()
2311fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                            == DisplayNameSources.ORGANIZATION) {
2312fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        // This is probably an organization. Instead of copying the organization
2313fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        // name into a name entry, copy it into the organization entry. This
2314fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        // way we will still consider the contact an organization.
2315fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        final ContentValues organization = new ContentValues();
2316fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        organization.put(Organization.COMPANY, mContactData.getDisplayName());
2317fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        organization.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
2318fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell                        values.add(organization);
2319ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    }
2320fc423b4040a0ec1728ee32ff40ef430f3e16e9dcBrian Attwell
2321ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // Last time used and times used are aggregated values from the usage stat
2322ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // table. They need to be removed from data values so the SQL table can insert
2323ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // properly
2324ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    for (ContentValues value : values) {
2325ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        value.remove(Data.LAST_TIME_USED);
2326ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        value.remove(Data.TIMES_USED);
2327ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    }
2328ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    intent.putExtra(Intents.Insert.DATA, values);
2329ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2330ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // If the contact can only export to the same account, add it to the intent.
2331ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // Otherwise the ContactEditorFragment will show a dialog for selecting an
2332ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    // account.
2333ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    if (mContactData.getDirectoryExportSupport() ==
2334ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                            Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY) {
2335ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        intent.putExtra(Intents.Insert.ACCOUNT,
2336ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                                new Account(mContactData.getDirectoryAccountName(),
2337ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                                        mContactData.getDirectoryAccountType()));
2338ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                        intent.putExtra(Intents.Insert.DATA_SET,
2339ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                                mContactData.getRawContacts().get(0).getDataSet());
2340ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    }
2341ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos
2342f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                    // Add this flag to disable the delete menu option on directory contact joins
2343f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                    // with local contacts. The delete option is ambiguous when joining contacts.
2344f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                    intent.putExtra(ContactEditorFragment.INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION,
2345f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                            true);
2346f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos
2347ab54ea15274dd3975c82a6aac29ba268aaed0799Paul Soulos                    startActivityForResult(intent, REQUEST_CODE_CONTACT_SELECTION_ACTIVITY);
2348d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                } else if (InvisibleContactUtil.isInvisibleAndAddable(mContactData, this)) {
2349d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    InvisibleContactUtil.addToDefaultGroup(mContactData, this);
2350d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                } else if (isContactEditable()) {
2351d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                    editContact();
2352d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                }
2353d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                return true;
2354752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            case R.id.menu_share:
2355752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                shareContact();
2356752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                return true;
2357752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell            case R.id.menu_create_contact_shortcut:
2358752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                createLauncherShortcutWithContact();
2359752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell                return true;
2360d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell            default:
2361d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell                return super.onOptionsItemSelected(item);
2362d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell        }
236323889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos    }
2364edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann}
2365