QuickContactActivity.java revision 899aa21e911ee7170beab228d44d7fed68c414e4
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 198a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.animation.ArgbEvaluator; 20b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport android.animation.ObjectAnimator; 21edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.app.Activity; 22d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.app.Fragment; 23cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks; 24752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport android.content.ActivityNotFoundException; 25edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.ContentUris; 26edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.Intent; 27cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmannimport android.content.Loader; 28edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.pm.PackageManager; 2931b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.graphics.Bitmap; 308a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.graphics.Color; 3131b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.graphics.drawable.BitmapDrawable; 328a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.graphics.drawable.ColorDrawable; 3331b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.graphics.drawable.Drawable; 3423889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulosimport android.graphics.PorterDuff; 3523889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulosimport android.graphics.PorterDuffColorFilter; 36edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.net.Uri; 3731b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.os.AsyncTask; 38edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.os.Bundle; 398a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport android.os.Trace; 40752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport android.provider.ContactsContract; 41edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Email; 42edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Phone; 43edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.SipAddress; 44edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 45edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Website; 46752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport android.provider.ContactsContract.Contacts; 47edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.QuickContact; 48edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.RawContacts; 4931b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport android.support.v7.graphics.Palette; 50edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.text.TextUtils; 51edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.util.Log; 52d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.view.Menu; 53d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.view.MenuItem; 54d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.view.MenuInflater; 55edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.view.View; 56edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.view.View.OnClickListener; 5710d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawaimport android.view.WindowManager; 58edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.widget.ImageView; 59edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.widget.Toast; 60d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport android.widget.Toolbar; 61edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 6272b3ab1d8a62f228a540b05f4ed6373e494c7d72Christine Chenimport com.android.contacts.ContactSaveService; 63d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport com.android.contacts.ContactsActivity; 64d7ca03e23948c3b2d5f97ec5598d8b50e3fc0b25Chiao Chengimport com.android.contacts.common.Collapser; 65e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R; 66d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport com.android.contacts.common.editor.SelectAccountDialogFragment; 6731b2d42fb0889e61515d27314aa5a245147100daBrian Attwellimport com.android.contacts.common.lettertiles.LetterTileDrawable; 68752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport com.android.contacts.common.list.ShortcutIntentBuilder; 69752cccf954bd6070c5fb623875314951c8e9849dBrian Attwellimport com.android.contacts.common.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener; 700d5588da244d0992c3ff8f25d0875fdf95a8c644Chiao Chengimport com.android.contacts.common.model.AccountTypeManager; 71cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.Contact; 72cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.ContactLoader; 73cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.RawContact; 74428f008513d1591cc08fcfe2cf0c9237fb313241Chiao Chengimport com.android.contacts.common.model.account.AccountType; 75d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport com.android.contacts.common.model.account.AccountWithDataSet; 76cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.dataitem.DataItem; 77428f008513d1591cc08fcfe2cf0c9237fb313241Chiao Chengimport com.android.contacts.common.model.dataitem.DataKind; 78cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.dataitem.EmailDataItem; 79cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.dataitem.ImDataItem; 80b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport com.android.contacts.common.model.dataitem.PhoneDataItem; 81cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.util.DataStatus; 82d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellimport com.android.contacts.detail.ContactDetailDisplayUtils; 83899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulosimport com.android.contacts.common.util.UriUtils; 84899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulosimport com.android.contacts.interactions.CalendarInteractionsLoader; 858a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwellimport com.android.contacts.interactions.ContactDeletionInteraction; 86b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport com.android.contacts.interactions.ContactInteraction; 87b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport com.android.contacts.interactions.SmsInteractionsLoader; 882d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport com.android.contacts.quickcontact.ExpandingEntryCardView.Entry; 89e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.ImageViewDrawableSetter; 90b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport com.android.contacts.util.SchedulingUtils; 91b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport com.android.contacts.widget.MultiShrinkScroller; 92b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwellimport com.android.contacts.widget.MultiShrinkScroller.MultiShrinkScrollerListener; 932d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos 94e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.base.Preconditions; 95e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.collect.Lists; 96e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng 972d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport java.util.ArrayList; 98899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulosimport java.util.Arrays; 99899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulosimport java.util.Collection; 100b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport java.util.Collections; 101b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport java.util.Comparator; 102edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.HashMap; 103edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.HashSet; 104edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.List; 105b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulosimport java.util.Map; 106edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.Set; 107edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 108edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann/** 109edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Mostly translucent {@link Activity} that shows QuickContact dialog. It loads 110edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * data asynchronously, and then shows a popup with details centered around 111edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * {@link Intent#getSourceBounds()}. 112edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */ 113d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwellpublic class QuickContactActivity extends ContactsActivity { 1148a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 1158a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell /** 1168a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell * QuickContacts immediately takes up the full screen. All possible information is shown. 1178a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell * This value for {@link android.provider.ContactsContract.QuickContact#EXTRA_MODE} 1188a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell * should only be used by the Contacts app. 1198a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell */ 1208a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell public static final int MODE_FULLY_EXPANDED = 4; 1218a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 122edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann private static final String TAG = "QuickContact"; 123edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 1248a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private static final int ANIMATION_SLIDE_OPEN_DURATION = 250; 1258a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private static final int ANIMATION_STATUS_BAR_COLOR_CHANGE_DURATION = 75; 1268a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private static final int REQUEST_CODE_CONTACT_EDITOR_ACTIVITY = 1; 1278a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private static final float SYSTEM_BAR_BRIGHTNESS_FACTOR = 0.7f; 1288a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private static final int SHIM_COLOR = Color.argb(0x7F, 0, 0, 0); 129dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki 130752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell /** This is the Intent action to install a shortcut in the launcher. */ 131752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell private static final String ACTION_INSTALL_SHORTCUT = 132752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell "com.android.launcher.action.INSTALL_SHORTCUT"; 133edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 134edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann @SuppressWarnings("deprecation") 135edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann private static final String LEGACY_AUTHORITY = android.provider.Contacts.AUTHORITY; 136edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 137edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann private Uri mLookupUri; 138edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann private String[] mExcludeMimes; 1398a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private int mExtraMode; 1408a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private int mStatusBarColor; 1418a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private boolean mHasAlreadyBeenOpened; 142edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 1436219668d0612f7522bd15a9d34c6232cb15b9a6cYorke Lee private ImageView mPhotoView; 1442d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos private ExpandingEntryCardView mCommunicationCard; 145b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private ExpandingEntryCardView mRecentCard; 146b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell private MultiShrinkScroller mScroller; 147d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell private SelectAccountDialogFragmentListener mSelectAccountFragmentListener; 1488a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private AsyncTask<Void, Void, Void> mEntriesAndActionsTask; 149edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 150b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private static final int MIN_NUM_COMMUNICATION_ENTRIES_SHOWN = 3; 151b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private static final int MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN = 3; 152b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 1536cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee private Contact mContactData; 1549815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann private ContactLoader mContactLoader; 1559815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann 15623889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos private PorterDuffColorFilter mColorFilter; 15723889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos List<Drawable> mDrawablesToTint; 15823889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos 1599758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus private final ImageViewDrawableSetter mPhotoSetter = new ImageViewDrawableSetter(); 1609758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus 161edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann /** 162edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Keeps the default action per mimetype. Empty if no default actions are set 163edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */ 164edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann private HashMap<String, Action> mDefaultsMap = new HashMap<String, Action>(); 165edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 166edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann /** 167edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Set of {@link Action} that are associated with the aggregate currently 168edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * displayed by this dialog, represented as a map from {@link String} 169edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * MIME-type to a list of {@link Action}. 170edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */ 171edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann private ActionMultiMap mActions = new ActionMultiMap(); 172edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 173edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann /** 174edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * {@link #LEADING_MIMETYPES} and {@link #TRAILING_MIMETYPES} are used to sort MIME-types. 175edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * 176edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * <p>The MIME-types in {@link #LEADING_MIMETYPES} appear in the front of the dialog, 177edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * in the order specified here.</p> 178edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * 179edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * <p>The ones in {@link #TRAILING_MIMETYPES} appear in the end of the dialog, in the order 180edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * specified here.</p> 181edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * 182edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * <p>The rest go between them, in the order in the array.</p> 183edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */ 184edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann private static final List<String> LEADING_MIMETYPES = Lists.newArrayList( 185edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann Phone.CONTENT_ITEM_TYPE, SipAddress.CONTENT_ITEM_TYPE, Email.CONTENT_ITEM_TYPE); 186edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 187edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann /** See {@link #LEADING_MIMETYPES}. */ 188edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann private static final List<String> TRAILING_MIMETYPES = Lists.newArrayList( 189edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann StructuredPostal.CONTENT_ITEM_TYPE, Website.CONTENT_ITEM_TYPE); 190edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 191b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos /** Id for the background contact loader */ 192b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private static final int LOADER_CONTACT_ID = 0; 193b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 194b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos /** Id for the background Sms Loader */ 195b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private static final int LOADER_SMS_ID = 1; 196b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private static final String KEY_LOADER_EXTRA_SMS_PHONES = 197b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_SMS_PHONES"; 198b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private static final int MAX_SMS_RETRIEVE = 3; 199899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos private static final int LOADER_CALENDAR_ID = 2; 200899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos private static final String KEY_LOADER_EXTRA_CALENDAR_EMAILS = 201899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_CALENDAR_EMAILS"; 202899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos private static final int MAX_PAST_CALENDAR_RETRIEVE = 3; 203899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos private static final int MAX_FUTURE_CALENDAR_RETRIEVE = 3; 204899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos private static final long PAST_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR = 205899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos 180L * 24L * 60L * 60L * 1000L /* 180 days */; 206899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos private static final long FUTURE_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR = 207899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos 36L * 60L * 60L * 1000L /* 36 hours */; 208899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos 209899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos private static final int[] mRecentLoaderIds = new int[]{LOADER_SMS_ID, LOADER_CALENDAR_ID}; 210b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private Map<Integer, List<ContactInteraction>> mRecentLoaderResults; 211b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 212d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell private static final String FRAGMENT_TAG_SELECT_ACCOUNT = "select_account_fragment"; 2136cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee 2142d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos final OnClickListener mEntryClickHandler = new OnClickListener() { 2152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos @Override 2162d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos public void onClick(View v) { 2172d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos Log.i(TAG, "mEntryClickHandler onClick"); 2182d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos Object intent = v.getTag(); 2192d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos if (intent == null || !(intent instanceof Intent)) { 2202d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos return; 2212d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos } 2222d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos startActivity((Intent) intent); 2232d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos } 2242d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos }; 2252d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos 226d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell /** 227d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell * Headless fragment used to handle account selection callbacks invoked from 228d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell * {@link DirectoryContactUtil}. 229d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell */ 230d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell public static class SelectAccountDialogFragmentListener extends Fragment 231d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell implements SelectAccountDialogFragment.Listener { 232d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 233d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell private QuickContactActivity mQuickContactActivity; 234d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 235d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell public SelectAccountDialogFragmentListener() {} 236d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 237d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell @Override 238d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) { 239d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell DirectoryContactUtil.createCopy(mQuickContactActivity.mContactData.getContentValues(), 240d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell account, mQuickContactActivity); 241d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 242d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 243d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell @Override 244d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell public void onAccountSelectorCancelled() {} 245d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 246d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell /** 247d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell * Set the parent activity. Since rotation can cause this fragment to be used across 248d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell * more than one activity instance, we need to explicitly set this value instead 249d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell * of making this class non-static. 250d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell */ 251d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell public void setQuickContactActivity(QuickContactActivity quickContactActivity) { 252d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mQuickContactActivity = quickContactActivity; 253d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 254d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 255d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 256b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell final MultiShrinkScrollerListener mMultiShrinkScrollerListener 257b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell = new MultiShrinkScrollerListener() { 258b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell @Override 259b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell public void onScrolledOffBottom() { 260b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell onBackPressed(); 261b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell } 2628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 2638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell @Override 2648a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell public void onEnterFullscreen() { 2658a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell updateStatusBarColor(); 2668a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 2678a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 2688a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell @Override 2698a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell public void onExitFullscreen() { 2708a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell updateStatusBarColor(); 2718a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 272b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell }; 273b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell 274edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann @Override 2758a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell protected void onCreate(Bundle savedInstanceState) { 2768a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.beginSection("onCreate()"); 2778a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell super.onCreate(savedInstanceState); 278edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 2798a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell getWindow().setStatusBarColor(Color.TRANSPARENT); 2808a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // Since we can't disable Window animations from the Launcher, we can minimize the 2818a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // silliness of the animation by setting the navigation bar transparent. 2828a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell getWindow().setNavigationBarColor(Color.TRANSPARENT); 2832426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann 284d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell processIntent(getIntent()); 285dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki 28610d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa // Show QuickContact in front of soft input 28710d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, 28810d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); 28910d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa 290edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann setContentView(R.layout.quickcontact_activity); 291edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 2922d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos mCommunicationCard = (ExpandingEntryCardView) findViewById(R.id.communication_card); 293b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos mRecentCard = (ExpandingEntryCardView) findViewById(R.id.recent_card); 294b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell mScroller = (MultiShrinkScroller) findViewById(R.id.multiscroller); 295edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 2962d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos mCommunicationCard.setOnClickListener(mEntryClickHandler); 297b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos mCommunicationCard.setTitle(getResources().getString(R.string.communication_card_title)); 29823889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos mCommunicationCard.setExpandButtonText( 29923889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos getResources().getString(R.string.expanding_entry_card_view_see_all)); 300b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 301b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos mRecentCard.setOnClickListener(mEntryClickHandler); 302b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos mRecentCard.setTitle(getResources().getString(R.string.recent_card_title)); 303edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 304d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mPhotoView = (ImageView) findViewById(R.id.photo); 305edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 306d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 307d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell setActionBar(toolbar); 308d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell setHeaderNameText(R.string.missing_name); 3096219668d0612f7522bd15a9d34c6232cb15b9a6cYorke Lee 3108a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mHasAlreadyBeenOpened = savedInstanceState != null; 3118a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 3128a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final ColorDrawable windowShim = new ColorDrawable(SHIM_COLOR); 3138a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell getWindow().setBackgroundDrawable(windowShim); 3148a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (!mHasAlreadyBeenOpened) { 3158a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final int duration = getResources().getInteger(android.R.integer.config_shortAnimTime); 3168a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell ObjectAnimator.ofInt(windowShim, "alpha", 0, 0xFF).setDuration(duration).start(); 3178a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 318edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 319b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell if (mScroller != null) { 3208a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mScroller.initialize(mMultiShrinkScrollerListener); 3218a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (mHasAlreadyBeenOpened) { 3228a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mScroller.setVisibility(View.VISIBLE); 3238a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mScroller.setScroll(mScroller.getScrollNeededToBeFullScreen()); 3248a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } else { 3258a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mScroller.setVisibility(View.GONE); 3268a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 3278a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 3288a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 32923889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos mDrawablesToTint = new ArrayList<>(); 330d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mSelectAccountFragmentListener= (SelectAccountDialogFragmentListener) getFragmentManager() 331d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell .findFragmentByTag(FRAGMENT_TAG_SELECT_ACCOUNT); 332d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell if (mSelectAccountFragmentListener == null) { 333d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mSelectAccountFragmentListener = new SelectAccountDialogFragmentListener(); 334d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell getFragmentManager().beginTransaction().add(0, mSelectAccountFragmentListener, 335d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell FRAGMENT_TAG_SELECT_ACCOUNT).commit(); 336d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mSelectAccountFragmentListener.setRetainInstance(true); 337d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 338d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mSelectAccountFragmentListener.setQuickContactActivity(this); 33923889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos 3408a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.endSection(); 3418a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 3428a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 3438a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell protected void onActivityResult(int requestCode, int resultCode, 3448a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Intent data) { 3458a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (requestCode == REQUEST_CODE_CONTACT_EDITOR_ACTIVITY && 3468a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell resultCode == ContactDeletionInteraction.RESULT_CODE_DELETED) { 3478a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // The contact that we were showing has been deleted. 3488a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell finish(); 349b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell } 3508a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 351dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki 3528a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell @Override 3538a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell protected void onNewIntent(Intent intent) { 3548a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell super.onNewIntent(intent); 3558a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mHasAlreadyBeenOpened = true; 356d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell processIntent(intent); 357d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 358d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 359d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell private void processIntent(Intent intent) { 360d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell Uri lookupUri = intent.getData(); 361d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 362d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // Check to see whether it comes from the old version. 363d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell if (lookupUri != null && LEGACY_AUTHORITY.equals(lookupUri.getAuthority())) { 364d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell final long rawContactId = ContentUris.parseId(lookupUri); 365d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell lookupUri = RawContacts.getContactLookupUri(getContentResolver(), 366d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId)); 367d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 368d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mExtraMode = getIntent().getIntExtra(QuickContact.EXTRA_MODE, 369d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell QuickContact.MODE_LARGE); 370d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell final Uri oldLookupUri = mLookupUri; 371d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 372d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mLookupUri = Preconditions.checkNotNull(lookupUri, "missing lookupUri"); 373d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mExcludeMimes = intent.getStringArrayExtra(QuickContact.EXTRA_EXCLUDE_MIMES); 374d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell if (oldLookupUri == null) { 375d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mContactLoader = (ContactLoader) getLoaderManager().initLoader( 376d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell LOADER_CONTACT_ID, null, mLoaderContactCallbacks); 377d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } else if (oldLookupUri != mLookupUri) { 378d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // After copying a directory contact, the contact URI changes. Therefore, 379d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // we need to restart the loader and reload the new contact. 380d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mContactLoader = (ContactLoader) getLoaderManager().restartLoader( 381d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell LOADER_CONTACT_ID, null, mLoaderContactCallbacks); 382899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos for (int interactionLoaderId : mRecentLoaderIds) { 383899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos getLoaderManager().destroyLoader(interactionLoaderId); 384899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos } 385d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 3862426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann } 387edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 388b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell private void runEntranceAnimation() { 3898a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (mHasAlreadyBeenOpened) { 3908a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell return; 3918a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 3928a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mHasAlreadyBeenOpened = true; 393b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell final int bottomScroll = mScroller.getScrollUntilOffBottom() - 1; 394b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell final ObjectAnimator scrollAnimation 3958a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell = ObjectAnimator.ofInt(mScroller, "scroll", -bottomScroll, 3968a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mExtraMode != MODE_FULLY_EXPANDED ? 0 : mScroller.getScrollNeededToBeFullScreen()); 3978a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell scrollAnimation.setDuration(ANIMATION_SLIDE_OPEN_DURATION); 398b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell scrollAnimation.start(); 399b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell } 400b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell 40181281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan /** Assign this string to the view if it is not empty. */ 402d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell private void setHeaderNameText(int resId) { 403d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell getActionBar().setTitle(getText(resId)); 40481281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan } 40581281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan 40681281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan /** Assign this string to the view if it is not empty. */ 407d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell private void setHeaderNameText(CharSequence value) { 408d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell if (!TextUtils.isEmpty(value)) { 409d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell getActionBar().setTitle(value); 41081281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan } 41181281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan } 41281281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan 41381281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan /** 414edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Check if the given MIME-type appears in the list of excluded MIME-types 415edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * that the most-recent caller requested. 416edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */ 417edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann private boolean isMimeExcluded(String mimeType) { 418edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann if (mExcludeMimes == null) return false; 419edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann for (String excludedMime : mExcludeMimes) { 420edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann if (TextUtils.equals(excludedMime, mimeType)) { 421edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann return true; 422edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 423edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 424edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann return false; 425edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 426edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 427edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann /** 428cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann * Handle the result from the ContactLoader 429edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */ 4308a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private void bindContactData(final Contact data) { 4318a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.beginSection("bindContactData"); 4326cb6f6f8304d4b42fc9db4bbb0cc4058ab53afe3Yorke Lee mContactData = data; 433d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell invalidateOptionsMenu(); 434edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 435edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann mDefaultsMap.clear(); 436edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 4378a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.endSection(); 4388a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.beginSection("Set display photo & name"); 439dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki 4406219668d0612f7522bd15a9d34c6232cb15b9a6cYorke Lee mPhotoSetter.setupContactPhoto(data, mPhotoView); 44131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell extractAndApplyTintFromPhotoViewAsynchronously(); 442d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell setHeaderNameText(data.getDisplayName()); 443edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 4448a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.endSection(); 445dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki 4468a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final List<String> sortedActionMimeTypes = Lists.newArrayList(); 447b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos // Maintain a list of phone numbers to pass into SmsInteractionsLoader 448899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos final Set<String> phoneNumbers = new HashSet<>(); 449899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos // Maintain a list of email addresses to pass into CalendarInteractionsLoader 450899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos final Set<String> emailAddresses = new HashSet<>(); 4518a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // List of Entry that makes up the ExpandingEntryCardView 4528a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final List<Entry> entries = Lists.newArrayList(); 4538a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 4548a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mEntriesAndActionsTask = new AsyncTask<Void, Void, Void>() { 4558a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell @Override 4568a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell protected Void doInBackground(Void... params) { 457899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos computeEntriesAndActions(data, phoneNumbers, emailAddresses, 458899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos sortedActionMimeTypes, entries); 4598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell return null; 4608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 4618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 4628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell @Override 4638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell protected void onPostExecute(Void aVoid) { 4648a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell super.onPostExecute(aVoid); 4658a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // Check that original AsyncTask parameters are still valid and the activity 4668a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // is still running before binding to UI. A new intent could invalidate 4678a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // the results, for example. 4688a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (data == mContactData && !isCancelled()) { 469899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos bindEntriesAndActions(entries, phoneNumbers, emailAddresses, 470899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos sortedActionMimeTypes); 4718a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell showActivity(); 4728a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 4738a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 4748a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell }; 4758a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mEntriesAndActionsTask.execute(); 4768a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 4778a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 4788a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private void bindEntriesAndActions(List<Entry> entries, 479899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos Set<String> phoneNumbers, 480899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos Set<String> emailAddresses, 4818a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell List<String> sortedActionMimeTypes) { 4828a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.beginSection("start sms loader"); 483899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos final Bundle smsExtraBundle = new Bundle(); 4848a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell smsExtraBundle.putStringArray(KEY_LOADER_EXTRA_SMS_PHONES, 4858a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell phoneNumbers.toArray(new String[phoneNumbers.size()])); 4868a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell getLoaderManager().initLoader( 4878a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell LOADER_SMS_ID, 4888a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell smsExtraBundle, 4898a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mLoaderInteractionsCallbacks); 490899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos Trace.endSection(); 4918a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 492899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos Trace.beginSection("start calendar loader"); 493899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos final Bundle calendarExtraBundle = new Bundle(); 494899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos calendarExtraBundle.putStringArray(KEY_LOADER_EXTRA_CALENDAR_EMAILS, 495899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos emailAddresses.toArray(new String[emailAddresses.size()])); 496899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos getLoaderManager().initLoader( 497899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos LOADER_CALENDAR_ID, 498899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos calendarExtraBundle, 499899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos mLoaderInteractionsCallbacks); 5008a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.endSection(); 5018a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 502899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos Trace.beginSection("bind communicate card"); 5038a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (entries.size() > 0) { 5048a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mCommunicationCard.initialize(entries, 5058a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell /* numInitialVisibleEntries = */ MIN_NUM_COMMUNICATION_ENTRIES_SHOWN, 5068a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell /* isExpanded = */ false, 5078a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell /* themeColor = */ 0); 5088a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 5098a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 5108a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final boolean hasData = !sortedActionMimeTypes.isEmpty(); 511d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mCommunicationCard.setVisibility(hasData ? View.VISIBLE : View.GONE); 5128a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 5138a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.endSection(); 5148a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 5158a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 5168a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private void showActivity() { 5178a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (mScroller != null) { 5188a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mScroller.setVisibility(View.VISIBLE); 5198a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell SchedulingUtils.doOnPreDraw(mScroller, /* drawNextFrame = */ false, 5208a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell new Runnable() { 5218a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell @Override 5228a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell public void run() { 5238a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell runEntranceAnimation(); 5248a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 5258a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell }); 5268a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 5278a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 5288a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 529899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos private void computeEntriesAndActions(Contact data, Set<String> phoneNumbers, 530899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos Set<String> emailAddresses, List<String> sortedActionMimeTypes, List<Entry> entries) { 5318a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.beginSection("inflate entries and actions"); 5328a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 5338a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final ResolveCache cache = ResolveCache.getInstance(this); 534851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu for (RawContact rawContact : data.getRawContacts()) { 535851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu for (DataItem dataItem : rawContact.getDataItems()) { 536851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu final String mimeType = dataItem.getMimeType(); 53747b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng final AccountType accountType = rawContact.getAccountType(this); 53847b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng final DataKind dataKind = AccountTypeManager.getInstance(this) 53947b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng .getKindOrFallback(accountType, mimeType); 540cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann 541b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos if (dataItem instanceof PhoneDataItem) { 542b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos phoneNumbers.add(((PhoneDataItem) dataItem).getNormalizedNumber()); 543b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 544b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 545899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos if (dataItem instanceof EmailDataItem) { 546899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos emailAddresses.add(((EmailDataItem) dataItem).getAddress()); 547899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos } 548899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos 549cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann // Skip this data item if MIME-type excluded 550cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann if (isMimeExcluded(mimeType)) continue; 551cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann 552851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu final long dataId = dataItem.getId(); 553851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu final boolean isPrimary = dataItem.isPrimary(); 554851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu final boolean isSuperPrimary = dataItem.isSuperPrimary(); 555cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann 55647b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng if (dataKind != null) { 557cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann // Build an action for this data entry, find a mapping to a UI 558cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann // element, build its summary from the cursor, and collect it 559cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann // along with all others of this MIME-type. 5608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final Action action = new DataAction(getApplicationContext(), 5618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell dataItem, dataKind); 5628a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu final boolean wasAdded = considerAdd(action, cache, isSuperPrimary); 563cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann if (wasAdded) { 564cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann // Remember the default 565cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann if (isSuperPrimary || (isPrimary && (mDefaultsMap.get(mimeType) == null))) { 566cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann mDefaultsMap.put(mimeType, action); 567edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 568edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 569edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 570edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 571cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann // Handle Email rows with presence data as Im entry 5729daca14706f3699c9e9d46dfb522132fc566e57eDaniel Lehmann final DataStatus status = data.getStatuses().get(dataId); 573851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu if (status != null && dataItem instanceof EmailDataItem) { 574851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu final EmailDataItem email = (EmailDataItem) dataItem; 575851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu final ImDataItem im = ImDataItem.createFromEmail(email); 57647b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng if (dataKind != null) { 5778a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final DataAction action = new DataAction(getApplicationContext(), 5788a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell im, dataKind); 5799daca14706f3699c9e9d46dfb522132fc566e57eDaniel Lehmann action.setPresence(status.getPresence()); 5808a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu considerAdd(action, cache, isSuperPrimary); 581cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann } 582edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 583edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 584edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 585edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 5868a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.endSection(); 5878a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.beginSection("collapsing action list"); 588dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki 589edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann // Collapse Action Lists (remove e.g. duplicate e-mail addresses from different sources) 590edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann for (List<Action> actionChildren : mActions.values()) { 591edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann Collapser.collapseList(actionChildren); 592edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 593edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 5948a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.endSection(); 5958a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.beginSection("sort mimetypes"); 596edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 597edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann // All the mime-types to add. 598edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann final Set<String> containedTypes = new HashSet<String>(mActions.keySet()); 599edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann // First, add LEADING_MIMETYPES, which are most common. 600edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann for (String mimeType : LEADING_MIMETYPES) { 601edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann if (containedTypes.contains(mimeType)) { 6028a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell sortedActionMimeTypes.add(mimeType); 603edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann containedTypes.remove(mimeType); 6042d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos entries.addAll(actionsToEntries(mActions.get(mimeType))); 605edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 606edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 607edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 608edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann // Add all the remaining ones that are not TRAILING 609edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann for (String mimeType : containedTypes.toArray(new String[containedTypes.size()])) { 610edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann if (!TRAILING_MIMETYPES.contains(mimeType)) { 6118a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell sortedActionMimeTypes.add(mimeType); 612edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann containedTypes.remove(mimeType); 6132d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos entries.addAll(actionsToEntries(mActions.get(mimeType))); 614edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 615edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 616edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 617edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann // Then, add TRAILING_MIMETYPES, which are least common. 618edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann for (String mimeType : TRAILING_MIMETYPES) { 619edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann if (containedTypes.contains(mimeType)) { 620edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann containedTypes.remove(mimeType); 6218a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell sortedActionMimeTypes.add(mimeType); 6222d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos entries.addAll(actionsToEntries(mActions.get(mimeType))); 623edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 624edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 625b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 6268a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.endSection(); 627edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 628edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 629edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann /** 63031b2d42fb0889e61515d27314aa5a245147100daBrian Attwell * Asynchronously extract the most vibrant color from the PhotoView. Once extracted, 63131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell * apply this tint to {@link MultiShrinkScroller}. This operation takes about 20-30ms 63231b2d42fb0889e61515d27314aa5a245147100daBrian Attwell * on a Nexus 5. 63331b2d42fb0889e61515d27314aa5a245147100daBrian Attwell */ 63431b2d42fb0889e61515d27314aa5a245147100daBrian Attwell private void extractAndApplyTintFromPhotoViewAsynchronously() { 63531b2d42fb0889e61515d27314aa5a245147100daBrian Attwell if (mScroller == null) { 63631b2d42fb0889e61515d27314aa5a245147100daBrian Attwell return; 63731b2d42fb0889e61515d27314aa5a245147100daBrian Attwell } 63831b2d42fb0889e61515d27314aa5a245147100daBrian Attwell final Drawable imageViewDrawable = mPhotoView.getDrawable(); 63931b2d42fb0889e61515d27314aa5a245147100daBrian Attwell new AsyncTask<Void, Void, Integer>() { 64031b2d42fb0889e61515d27314aa5a245147100daBrian Attwell @Override 64131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell protected Integer doInBackground(Void... params) { 64231b2d42fb0889e61515d27314aa5a245147100daBrian Attwell if (imageViewDrawable instanceof BitmapDrawable) { 6438a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final Bitmap bitmap = ((BitmapDrawable) imageViewDrawable).getBitmap(); 6448a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell return colorFromBitmap(bitmap); 6458a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 6468a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (imageViewDrawable instanceof LetterTileDrawable) { 64731b2d42fb0889e61515d27314aa5a245147100daBrian Attwell // LetterTileDrawable doesn't normally draw unless it is visible. Therefore, 64831b2d42fb0889e61515d27314aa5a245147100daBrian Attwell // we need to directly ask it for its color via getColor(). We could directly 64931b2d42fb0889e61515d27314aa5a245147100daBrian Attwell // return this color. However, in the future Palette#generate() may incorporate 65031b2d42fb0889e61515d27314aa5a245147100daBrian Attwell // saturation boosting. So I want to use Palette#generate() for the sake of 65131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell // consistency. 65231b2d42fb0889e61515d27314aa5a245147100daBrian Attwell final LetterTileDrawable tileDrawable = (LetterTileDrawable) imageViewDrawable; 65331b2d42fb0889e61515d27314aa5a245147100daBrian Attwell final int PALETTE_BITMAP_SIZE = 1; 6548a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final Bitmap bitmap = Bitmap.createBitmap(PALETTE_BITMAP_SIZE, 65531b2d42fb0889e61515d27314aa5a245147100daBrian Attwell PALETTE_BITMAP_SIZE, Bitmap.Config.ARGB_8888); 6568a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // If Palette can not extract a primary color, our UX person says we are better 6578a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // off using the LetterTileDrawable's non vibrant color than falling back 6588a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // to the app's default color. 6598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final int color = colorFromBitmap(bitmap); 6608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (color == 0) { 6618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell return tileDrawable.getColor(); 6628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } else { 6638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell return color; 6648a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 66531b2d42fb0889e61515d27314aa5a245147100daBrian Attwell } 6668a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell return 0; 66731b2d42fb0889e61515d27314aa5a245147100daBrian Attwell } 66831b2d42fb0889e61515d27314aa5a245147100daBrian Attwell 66931b2d42fb0889e61515d27314aa5a245147100daBrian Attwell @Override 67031b2d42fb0889e61515d27314aa5a245147100daBrian Attwell protected void onPostExecute(Integer color) { 67131b2d42fb0889e61515d27314aa5a245147100daBrian Attwell super.onPostExecute(color); 67223889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos mColorFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP); 67323889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos // Make sure the color is valid. Also check that the Photo has not changed. If it 67423889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos // has changed, the new tint color needs to be extracted 67531b2d42fb0889e61515d27314aa5a245147100daBrian Attwell if (color != 0 && imageViewDrawable == mPhotoView.getDrawable()) { 67631b2d42fb0889e61515d27314aa5a245147100daBrian Attwell // TODO: animate from the previous tint. 67731b2d42fb0889e61515d27314aa5a245147100daBrian Attwell mScroller.setHeaderTintColor(color); 6788a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 6798a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // Create a darker version of the actionbar color. HSV is device dependent 6808a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // and not perceptually-linear. Therefore, we can't say mStatusBarColor is 6818a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // 70% as bright as the action bar color. We can only say: it is a bit darker. 6828a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final float hsvComponents[] = new float[3]; 6838a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Color.colorToHSV(color, hsvComponents); 6848a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell hsvComponents[2] *= SYSTEM_BAR_BRIGHTNESS_FACTOR; 6858a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mStatusBarColor = Color.HSVToColor(hsvComponents); 6868a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 6878a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell updateStatusBarColor(); 68823889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos for (Drawable drawable : mDrawablesToTint) { 68923889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos applyThemeColorIfAvailable(drawable); 69023889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos } 69123889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos mDrawablesToTint.clear(); 69231b2d42fb0889e61515d27314aa5a245147100daBrian Attwell } 69331b2d42fb0889e61515d27314aa5a245147100daBrian Attwell } 69431b2d42fb0889e61515d27314aa5a245147100daBrian Attwell }.execute(); 69531b2d42fb0889e61515d27314aa5a245147100daBrian Attwell } 69631b2d42fb0889e61515d27314aa5a245147100daBrian Attwell 6978a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private void updateStatusBarColor() { 6988a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (mScroller == null) { 6998a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell return; 7008a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 7018a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final int desiredStatusBarColor; 7028a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // Only use a custom status bar color if QuickContacts touches the top of the viewport. 7038a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (mScroller.getScrollNeededToBeFullScreen() <= 0) { 7048a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell desiredStatusBarColor = mStatusBarColor; 7058a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } else { 7068a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell desiredStatusBarColor = Color.TRANSPARENT; 7078a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 7088a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // Animate to the new color. 7098a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (desiredStatusBarColor != getWindow().getStatusBarColor()) { 7108a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final ObjectAnimator animation = ObjectAnimator.ofInt(getWindow(), "statusBarColor", 7118a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell getWindow().getStatusBarColor(), desiredStatusBarColor); 7128a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell animation.setDuration(ANIMATION_STATUS_BAR_COLOR_CHANGE_DURATION); 7138a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell animation.setEvaluator(new ArgbEvaluator()); 7148a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell animation.start(); 7158a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 7168a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 7178a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 7188a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell private int colorFromBitmap(Bitmap bitmap) { 7198a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // Author of Palette recommends using 24 colors when analyzing profile photos. 7208a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final int NUMBER_OF_PALETTE_COLORS = 24; 7218a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell final Palette palette = Palette.generate(bitmap, NUMBER_OF_PALETTE_COLORS); 7228a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (palette != null && palette.getVibrantColor() != null) { 7238a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell return palette.getVibrantColor().getRgb(); 7248a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 7258a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell return 0; 7268a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 7278a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 72831b2d42fb0889e61515d27314aa5a245147100daBrian Attwell /** 729edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Consider adding the given {@link Action}, which will only happen if 730edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * {@link PackageManager} finds an application to handle 731edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * {@link Action#getIntent()}. 7328a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu * @param action the action to handle 7338a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu * @param resolveCache cache of applications that can handle actions 7348a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu * @param front indicates whether to add the action to the front of the list 735edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * @return true if action has been added 736edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */ 7378a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu private boolean considerAdd(Action action, ResolveCache resolveCache, boolean front) { 738edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann if (resolveCache.hasResolve(action)) { 7398a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu mActions.put(action.getMimeType(), action, front); 740edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann return true; 741edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 742edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann return false; 743edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 744edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 745edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann /** 7462d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * Converts a list of Action into a list of Entry 7472d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * @param actions The list of Action to convert 7482d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * @return The converted list of Entry 749edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */ 7502d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos private List<Entry> actionsToEntries(List<Action> actions) { 7512d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos List<Entry> entries = new ArrayList<>(); 7522d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos for (Action action : actions) { 75323889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos String header = null; 75423889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos String body = null; 75523889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos String footer = null; 75623889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos Drawable icon = null; 75723889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos switch (action.getMimeType()) { 75823889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos case Phone.CONTENT_ITEM_TYPE: 75902477604d7cc803b6a7de10b45ed176c4e70f312Brian Attwell header = String.valueOf(action.getBody()); 76002477604d7cc803b6a7de10b45ed176c4e70f312Brian Attwell footer = String.valueOf(action.getSubtitle()); 76123889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos icon = applyThemeColorIfAvailable( 76223889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos getResources().getDrawable(R.drawable.ic_phone_24dp)); 76323889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos break; 76423889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos case Email.CONTENT_ITEM_TYPE: 76502477604d7cc803b6a7de10b45ed176c4e70f312Brian Attwell header = String.valueOf(action.getBody()); 76602477604d7cc803b6a7de10b45ed176c4e70f312Brian Attwell footer = String.valueOf(action.getSubtitle()); 76723889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos icon = applyThemeColorIfAvailable( 76823889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos getResources().getDrawable(R.drawable.ic_email_24dp)); 76923889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos break; 77023889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos case StructuredPostal.CONTENT_ITEM_TYPE: 77102477604d7cc803b6a7de10b45ed176c4e70f312Brian Attwell header = String.valueOf(action.getBody()); 77202477604d7cc803b6a7de10b45ed176c4e70f312Brian Attwell footer = String.valueOf(action.getSubtitle()); 77323889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos icon = applyThemeColorIfAvailable( 77423889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos getResources().getDrawable(R.drawable.ic_place_24dp)); 77523889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos break; 77623889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos default: 77702477604d7cc803b6a7de10b45ed176c4e70f312Brian Attwell header = String.valueOf(action.getSubtitle()); 77802477604d7cc803b6a7de10b45ed176c4e70f312Brian Attwell footer = String.valueOf(action.getBody()); 77923889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos icon = ResolveCache.getInstance(this).getIcon(action); 78023889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos } 78123889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos entries.add(new Entry(icon, header, body, footer, action.getIntent(), 78223889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos /* isEditable= */ false)); 78323889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos 78423889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos // Add SMS in addition to phone calls 78523889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos if (action.getMimeType().equals(Phone.CONTENT_ITEM_TYPE)) { 78623889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos entries.add(new Entry(applyThemeColorIfAvailable(getResources().getDrawable( 78723889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos R.drawable.ic_message_24dp)), 78823889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos getResources().getString(R.string.send_message), null, header, 78923889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos action.getAlternateIntent(), /* isEditable = */ false)); 79023889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos } 7912d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos } 7922d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos return entries; 793edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann } 794edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann 795b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private List<Entry> contactInteractionsToEntries(List<ContactInteraction> interactions) { 796b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos List<Entry> entries = new ArrayList<>(); 797b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos for (ContactInteraction interaction : interactions) { 79823889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos entries.add(new Entry(applyThemeColorIfAvailable(interaction.getIcon(this)), 799b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos interaction.getViewHeader(this), 800b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos interaction.getViewBody(this), 801b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos interaction.getBodyIcon(this), 802b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos interaction.getViewFooter(this), 803b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos interaction.getFooterIcon(this), 804b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos interaction.getIntent(), 805b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos /* isEditable = */ false)); 806b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 807b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos return entries; 808b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 809b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 810b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private LoaderCallbacks<Contact> mLoaderContactCallbacks = 811851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu new LoaderCallbacks<Contact>() { 812cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann @Override 813851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu public void onLoaderReset(Loader<Contact> loader) { 814cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann } 815cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann 816cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann @Override 817851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu public void onLoadFinished(Loader<Contact> loader, Contact data) { 8188a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.beginSection("onLoadFinished()"); 8198a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 820cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann if (isFinishing()) { 821cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann return; 822cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann } 823cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann if (data.isError()) { 824cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann // This shouldn't ever happen, so throw an exception. The {@link ContactLoader} 825cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann // should log the actual exception. 826cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann throw new IllegalStateException("Failed to load contact", data.getException()); 827cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann } 828cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann if (data.isNotFound()) { 8298a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (mHasAlreadyBeenOpened) { 8308a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell finish(); 8318a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } else { 8328a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Log.i(TAG, "No contact found: " + ((ContactLoader)loader).getLookupUri()); 8338a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Toast.makeText(QuickContactActivity.this, R.string.invalidContactMessage, 8348a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Toast.LENGTH_LONG).show(); 8358a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 836cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann return; 837cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann } 838cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann 839b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos bindContactData(data); 840cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann 8418a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell Trace.endSection(); 842cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann } 843cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann 844cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann @Override 845851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu public Loader<Contact> onCreateLoader(int id, Bundle args) { 846cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann if (mLookupUri == null) { 847cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann Log.wtf(TAG, "Lookup uri wasn't initialized. Loader was started too early"); 848cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann } 849d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // Load all contact data. We need loadGroupMetaData=true to determine whether the 850d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // contact is invisible. If it is, we need to display an "Add to Contacts" MenuItem. 851b2b435a944947fbf1965c3bb7c202a97f0273259Yorke Lee return new ContactLoader(getApplicationContext(), mLookupUri, 852d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell true /*loadGroupMetaData*/, false /*loadInvitableAccountTypes*/, 85345f23d4d67438c0561f74ef87b7028f6d74f7503Paul Sliwowski false /*postViewNotification*/, true /*computeFormattedPhoneNumber*/); 854cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann } 855cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann }; 856b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 857b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell @Override 858b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell public void onBackPressed() { 859b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell if (mScroller != null) { 860b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell // TODO: implement exit animation if the scroller isn't already off the screen 861b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell finish(); 862b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell } else { 863b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell super.onBackPressed(); 864b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell } 865b7e4364d6536449271ac4534dbeb7430134c096bBrian Attwell } 866b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 8678a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell @Override 8688a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell public void finish() { 8698a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell super.finish(); 8708a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 8718a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // override transitions to skip the standard window animations 8728a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell overridePendingTransition(0, 0); 8738a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 8748a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 875b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private LoaderCallbacks<List<ContactInteraction>> mLoaderInteractionsCallbacks = 876b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos new LoaderCallbacks<List<ContactInteraction>>() { 877b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 878b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos @Override 879b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos public Loader<List<ContactInteraction>> onCreateLoader(int id, Bundle args) { 880b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos Log.v(TAG, "onCreateLoader"); 881b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos Loader<List<ContactInteraction>> loader = null; 882b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos switch (id) { 883b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos case LOADER_SMS_ID: 884b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos Log.v(TAG, "LOADER_SMS_ID"); 885b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos loader = new SmsInteractionsLoader( 886b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos QuickContactActivity.this, 887b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos args.getStringArray(KEY_LOADER_EXTRA_SMS_PHONES), 888b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos MAX_SMS_RETRIEVE); 889b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos break; 890899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos case LOADER_CALENDAR_ID: 891899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos Log.v(TAG, "LOADER_CALENDAR_ID"); 892899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos loader = new CalendarInteractionsLoader( 893899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos QuickContactActivity.this, 894899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos Arrays.asList(args.getStringArray(KEY_LOADER_EXTRA_CALENDAR_EMAILS)), 895899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos MAX_FUTURE_CALENDAR_RETRIEVE, 896899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos MAX_PAST_CALENDAR_RETRIEVE, 897899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos FUTURE_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR, 898899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos PAST_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR); 899899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos break; 900b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 901b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos return loader; 902b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 903b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 904b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos @Override 905b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos public void onLoadFinished(Loader<List<ContactInteraction>> loader, 906b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos List<ContactInteraction> data) { 907b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos if (mRecentLoaderResults == null) { 908b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos mRecentLoaderResults = new HashMap<Integer, List<ContactInteraction>>(); 909b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 910899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos Log.v(TAG, "onLoadFinished ~ loader.getId() " + loader.getId() + " data.size() " + 911899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos data.size()); 912b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos mRecentLoaderResults.put(loader.getId(), data); 913b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 914b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos if (isAllRecentDataLoaded()) { 915b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos bindRecentData(); 916b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 917b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 918b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 919b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos @Override 920b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos public void onLoaderReset(Loader<List<ContactInteraction>> loader) { 921b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos mRecentLoaderResults.remove(loader.getId()); 922b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 923b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 924b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos }; 925b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 926b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private boolean isAllRecentDataLoaded() { 927b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos return mRecentLoaderResults.size() == mRecentLoaderIds.length; 928b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 929b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 930b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos private void bindRecentData() { 931b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos List<ContactInteraction> allInteractions = new ArrayList<>(); 932b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos for (List<ContactInteraction> loaderInteractions : mRecentLoaderResults.values()) { 933b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos allInteractions.addAll(loaderInteractions); 934b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 935b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 936b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos // Sort the interactions by most recent 937b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos Collections.sort(allInteractions, new Comparator<ContactInteraction>() { 938b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos @Override 939b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos public int compare(ContactInteraction a, ContactInteraction b) { 940b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos return a.getInteractionDate() >= b.getInteractionDate() ? -1 : 1; 941b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 942b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos }); 943b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos 944b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos if (allInteractions.size() > 0) { 945b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos mRecentCard.initialize(contactInteractionsToEntries(allInteractions), 946b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos /* numInitialVisibleEntries = */ MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN, 947b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos /* isExpanded = */ false, 948b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos /* themeColor = */ 0); 949b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos mRecentCard.setVisibility(View.VISIBLE); 950b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 951b3054e551173887029c55cb10b83f1afb7f8a6fePaul Soulos } 9528a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 9538a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell @Override 9548a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell protected void onStop() { 9558a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell super.onStop(); 9568a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell 9578a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell if (mEntriesAndActionsTask != null) { 9588a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // Once the activity is stopped, we will no longer want to bind mEntriesAndActionsTask's 9598a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // results on the UI thread. In some circumstances Activities are killed without 9608a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // onStop() being called. This is not a problem, because in these circumstances 9618a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell // the entire process will be killed. 9628a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell mEntriesAndActionsTask.cancel(/* mayInterruptIfRunning = */ false); 9638a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 9648a6f4ade05e5a8a89d91078ef9c22944450ac8baBrian Attwell } 96523889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos 96623889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos /** 96723889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos * Applies the theme color as extracted in 968d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell * {@link #extractAndApplyTintFromPhotoViewAsynchronously()} if available. If the color is not 96923889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos * available, store a reference to the drawable to tint when a color becomes available. 97023889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos */ 97123889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos private Drawable applyThemeColorIfAvailable(Drawable drawable) { 97223889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos if (mColorFilter != null) { 97323889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos drawable.setColorFilter(mColorFilter); 97423889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos } else { 97523889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos mDrawablesToTint.add(drawable); 97623889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos } 977899aa21e911ee7170beab228d44d7fed68c414e4Paul Soulos return drawable; 978d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 979d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 980d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell /** 981d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell * Returns true if it is possible to edit the current contact. 982d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell */ 983d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell private boolean isContactEditable() { 984d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell return mContactData != null && !mContactData.isDirectoryEntry(); 985d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 986d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 987d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell private void editContact() { 988d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell final Intent intent = new Intent(Intent.ACTION_EDIT, mLookupUri); 989d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mContactLoader.cacheResult(); 990d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 991d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell startActivityForResult(intent, REQUEST_CODE_CONTACT_EDITOR_ACTIVITY); 992d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 993d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 994d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell private void toggleStar(MenuItem starredMenuItem) { 995d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // Make sure there is a contact 996d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell if (mLookupUri != null) { 997d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // Read the current starred value from the UI instead of using the last 998d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // loaded state. This allows rapid tapping without writing the same 999d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // value several times 1000d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell final boolean isStarred = starredMenuItem.isChecked(); 1001d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 1002d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // To improve responsiveness, swap out the picture (and tag) in the UI already 1003d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell ContactDetailDisplayUtils.configureStarredMenuItem(starredMenuItem, 1004d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mContactData.isDirectoryEntry(), mContactData.isUserProfile(), 1005d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell !isStarred); 1006d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 1007d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // Now perform the real save 1008d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell Intent intent = ContactSaveService.createSetStarredIntent( 1009d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell QuickContactActivity.this, mLookupUri, !isStarred); 1010d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell startService(intent); 1011d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 1012d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 1013d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 1014752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell /** 1015752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell * Calls into the contacts provider to get a pre-authorized version of the given URI. 1016752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell */ 1017752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell private Uri getPreAuthorizedUri(Uri uri) { 1018752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell final Bundle uriBundle = new Bundle(); 1019752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell uriBundle.putParcelable(ContactsContract.Authorization.KEY_URI_TO_AUTHORIZE, uri); 1020752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell final Bundle authResponse = getContentResolver().call( 1021752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell ContactsContract.AUTHORITY_URI, 1022752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell ContactsContract.Authorization.AUTHORIZATION_METHOD, 1023752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell null, 1024752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell uriBundle); 1025752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell if (authResponse != null) { 1026752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell return (Uri) authResponse.getParcelable( 1027752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell ContactsContract.Authorization.KEY_AUTHORIZED_URI); 1028752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell } else { 1029752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell return uri; 1030752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell } 1031752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell } 1032752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell private void shareContact() { 1033752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell final String lookupKey = mContactData.getLookupKey(); 1034752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell Uri shareUri = Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, lookupKey); 1035752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell if (mContactData.isUserProfile()) { 1036752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell // User is sharing the profile. We don't want to force the receiver to have 1037752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell // the highly-privileged READ_PROFILE permission, so we need to request a 1038752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell // pre-authorized URI from the provider. 1039752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell shareUri = getPreAuthorizedUri(shareUri); 1040752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell } 1041752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell 1042752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell final Intent intent = new Intent(Intent.ACTION_SEND); 1043752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell intent.setType(Contacts.CONTENT_VCARD_TYPE); 1044752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell intent.putExtra(Intent.EXTRA_STREAM, shareUri); 1045752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell 1046752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell // Launch chooser to share contact via 1047752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell final CharSequence chooseTitle = getText(R.string.share_via); 1048752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell final Intent chooseIntent = Intent.createChooser(intent, chooseTitle); 1049752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell 1050752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell try { 1051752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell this.startActivity(chooseIntent); 1052752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell } catch (ActivityNotFoundException ex) { 1053752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell Toast.makeText(this, R.string.share_error, Toast.LENGTH_SHORT).show(); 1054752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell } 1055752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell } 1056752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell 1057752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell /** 1058752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell * Creates a launcher shortcut with the current contact. 1059752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell */ 1060752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell private void createLauncherShortcutWithContact() { 1061752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell final ShortcutIntentBuilder builder = new ShortcutIntentBuilder(this, 1062752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell new OnShortcutIntentCreatedListener() { 1063752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell 1064752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell @Override 1065752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell public void onShortcutIntentCreated(Uri uri, Intent shortcutIntent) { 1066752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell // Broadcast the shortcutIntent to the launcher to create a 1067752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell // shortcut to this contact 1068752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell shortcutIntent.setAction(ACTION_INSTALL_SHORTCUT); 1069752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell QuickContactActivity.this.sendBroadcast(shortcutIntent); 1070752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell 1071752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell // Send a toast to give feedback to the user that a shortcut to this 1072752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell // contact was added to the launcher. 1073752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell Toast.makeText(QuickContactActivity.this, 1074752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell R.string.createContactShortcutSuccessful, 1075752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell Toast.LENGTH_SHORT).show(); 1076752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell } 1077752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell 1078752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell }); 1079752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell builder.createContactShortcutIntent(mLookupUri); 1080752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell } 1081752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell 1082d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell @Override 1083d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell public boolean onCreateOptionsMenu(Menu menu) { 1084d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell MenuInflater inflater = getMenuInflater(); 1085d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell inflater.inflate(R.menu.quickcontact, menu); 1086d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell return true; 1087d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 1088d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 1089d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell @Override 1090d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell public boolean onPrepareOptionsMenu(Menu menu) { 1091d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell if (mContactData != null) { 1092d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell final MenuItem starredMenuItem = menu.findItem(R.id.menu_star); 1093d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell ContactDetailDisplayUtils.configureStarredMenuItem(starredMenuItem, 1094d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mContactData.isDirectoryEntry(), mContactData.isUserProfile(), 1095d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mContactData.getStarred()); 1096d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell // Configure edit MenuItem 1097d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell final MenuItem editMenuItem = menu.findItem(R.id.menu_edit); 1098d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell editMenuItem.setVisible(true); 1099d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell if (DirectoryContactUtil.isDirectoryContact(mContactData) || InvisibleContactUtil 1100d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell .isInvisibleAndAddable(mContactData, this)) { 1101d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell editMenuItem.setIcon(R.drawable.ic_person_add_24dp); 1102d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } else if (isContactEditable()) { 1103d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell editMenuItem.setIcon(R.drawable.ic_create_24dp); 1104d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } else { 1105d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell editMenuItem.setVisible(false); 1106d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 1107d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 1108d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell return true; 1109d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 1110d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell 1111d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell @Override 1112d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell public boolean onOptionsItemSelected(MenuItem item) { 1113d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell switch (item.getItemId()) { 1114d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell case R.id.menu_star: 1115d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell toggleStar(item); 1116d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell return true; 1117d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell case R.id.menu_edit: 1118d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell if (DirectoryContactUtil.isDirectoryContact(mContactData)) { 1119d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell DirectoryContactUtil.addToMyContacts(mContactData, this, getFragmentManager(), 1120d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell mSelectAccountFragmentListener); 1121d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } else if (InvisibleContactUtil.isInvisibleAndAddable(mContactData, this)) { 1122d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell InvisibleContactUtil.addToDefaultGroup(mContactData, this); 1123d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } else if (isContactEditable()) { 1124d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell editContact(); 1125d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 1126d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell return true; 1127752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell case R.id.menu_share: 1128752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell shareContact(); 1129752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell return true; 1130752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell case R.id.menu_create_contact_shortcut: 1131752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell createLauncherShortcutWithContact(); 1132752cccf954bd6070c5fb623875314951c8e9849dBrian Attwell return true; 1133d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell default: 1134d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell return super.onOptionsItemSelected(item); 1135d28851f436c39a83f02d3b405fd91f0fb4833b2aBrian Attwell } 113623889ba7ca18ed4ea56248355438a734511bc0b7Paul Soulos } 1137edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann} 1138