QuickContactActivity.java revision 0d5588da244d0992c3ff8f25d0875fdf95a8c644
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
19edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.app.Activity;
20edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.app.Fragment;
21edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.app.FragmentManager;
22cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks;
23edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.ActivityNotFoundException;
24edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.ContentUris;
25edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.Context;
26edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.Intent;
27cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmannimport android.content.Loader;
28edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.content.pm.PackageManager;
29edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.graphics.Rect;
30edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.graphics.drawable.Drawable;
31edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.net.Uri;
32edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.os.Bundle;
33edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.os.Handler;
34edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Email;
35edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Phone;
36edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.SipAddress;
37edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
38edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Website;
39edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.Contacts;
40edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.QuickContact;
41edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.provider.ContactsContract.RawContacts;
42edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.support.v13.app.FragmentPagerAdapter;
43edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.support.v4.view.ViewPager;
44edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.support.v4.view.ViewPager.SimpleOnPageChangeListener;
45edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.text.TextUtils;
46edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.util.Log;
47edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.view.MotionEvent;
48edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.view.View;
49edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.view.View.OnClickListener;
50edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.view.ViewGroup;
5110d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawaimport android.view.WindowManager;
52edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.widget.HorizontalScrollView;
53edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.widget.ImageButton;
54edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.widget.ImageView;
55edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.widget.RelativeLayout;
56edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.widget.TextView;
57edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport android.widget.Toast;
58edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
59d7ca03e23948c3b2d5f97ec5598d8b50e3fc0b25Chiao Chengimport com.android.contacts.common.Collapser;
60e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
610d5588da244d0992c3ff8f25d0875fdf95a8c644Chiao Chengimport com.android.contacts.common.model.AccountTypeManager;
62851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.Contact;
63851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.ContactLoader;
64851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContact;
65428f008513d1591cc08fcfe2cf0c9237fb313241Chiao Chengimport com.android.contacts.common.model.account.AccountType;
66851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.dataitem.DataItem;
67428f008513d1591cc08fcfe2cf0c9237fb313241Chiao Chengimport com.android.contacts.common.model.dataitem.DataKind;
68851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.dataitem.EmailDataItem;
69851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.dataitem.ImDataItem;
70d9eab4da8b9946b76a2091e5cce6c858663ef1bbChiao Chengimport com.android.contacts.common.util.Constants;
71e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.DataStatus;
72e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.ImageViewDrawableSetter;
73e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.SchedulingUtils;
749f2a5e78c9604d9c407f1464c7cb72ec5f2bb04dChiao Chengimport com.android.contacts.common.util.StopWatch;
75e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.base.Preconditions;
76e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.collect.Lists;
77e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
78edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.HashMap;
79edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.HashSet;
80edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.List;
81edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.Set;
82edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
83edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann// TODO: Save selected tab index during rotation
84edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
85edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann/**
86edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Mostly translucent {@link Activity} that shows QuickContact dialog. It loads
87edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * data asynchronously, and then shows a popup with details centered around
88edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * {@link Intent#getSourceBounds()}.
89edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */
90edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannpublic class QuickContactActivity extends Activity {
91edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final String TAG = "QuickContact";
92edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
93edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final boolean TRACE_LAUNCH = false;
94edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final String TRACE_TAG = "quickcontact";
95ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus    private static final int POST_DRAW_WAIT_DURATION = 60;
96dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki    private static final boolean ENABLE_STOPWATCH = false;
97dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
98edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
99edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @SuppressWarnings("deprecation")
100edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final String LEGACY_AUTHORITY = android.provider.Contacts.AUTHORITY;
101edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
102edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private Uri mLookupUri;
103edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private String[] mExcludeMimes;
104edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private List<String> mSortedActionMimeTypes = Lists.newArrayList();
105edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
106edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private FloatingChildLayout mFloatingLayout;
107edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
108edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private View mPhotoContainer;
109edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private ViewGroup mTrack;
110edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private HorizontalScrollView mTrackScroller;
111edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private View mSelectedTabRectangle;
1121792b08c500ed528e7d21401affd936b3a7b3dc6Daniel Lehmann    private View mLineAfterTrack;
113edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1149d85a2a39a4b9a0bacee8d25b2830784caf8551cYorke Lee    private ImageView mOpenDetailsImage;
115edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private ImageButton mOpenDetailsPushLayerButton;
116edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private ViewPager mListPager;
117edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1189815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann    private ContactLoader mContactLoader;
1199815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann
1209758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus    private final ImageViewDrawableSetter mPhotoSetter = new ImageViewDrawableSetter();
1219758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus
122edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
123edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Keeps the default action per mimetype. Empty if no default actions are set
124edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
125edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private HashMap<String, Action> mDefaultsMap = new HashMap<String, Action>();
126edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
127edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
128edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Set of {@link Action} that are associated with the aggregate currently
129edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * displayed by this dialog, represented as a map from {@link String}
130edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * MIME-type to a list of {@link Action}.
131edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
132edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private ActionMultiMap mActions = new ActionMultiMap();
133edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
134edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
135edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * {@link #LEADING_MIMETYPES} and {@link #TRAILING_MIMETYPES} are used to sort MIME-types.
136edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     *
137edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * <p>The MIME-types in {@link #LEADING_MIMETYPES} appear in the front of the dialog,
138edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * in the order specified here.</p>
139edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     *
140edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * <p>The ones in {@link #TRAILING_MIMETYPES} appear in the end of the dialog, in the order
141edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * specified here.</p>
142edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     *
143edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * <p>The rest go between them, in the order in the array.</p>
144edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
145edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final List<String> LEADING_MIMETYPES = Lists.newArrayList(
146edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            Phone.CONTENT_ITEM_TYPE, SipAddress.CONTENT_ITEM_TYPE, Email.CONTENT_ITEM_TYPE);
147edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
148edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /** See {@link #LEADING_MIMETYPES}. */
149edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final List<String> TRAILING_MIMETYPES = Lists.newArrayList(
150edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            StructuredPostal.CONTENT_ITEM_TYPE, Website.CONTENT_ITEM_TYPE);
151edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
152cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann    /** Id for the background loader */
153cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann    private static final int LOADER_ID = 0;
154edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
155dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki    private StopWatch mStopWatch = ENABLE_STOPWATCH
156dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            ? StopWatch.start("QuickContact") : StopWatch.getNullStopWatch();
157dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
158edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @Override
159edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    protected void onCreate(Bundle icicle) {
160dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("c"); // create start
161edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        super.onCreate(icicle);
162edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
163dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("sc"); // super.onCreate
164dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
1652426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann        if (TRACE_LAUNCH) android.os.Debug.startMethodTracing(TRACE_TAG);
1662426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann
167dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        // Parse intent
168dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        final Intent intent = getIntent();
169dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
170dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        Uri lookupUri = intent.getData();
171dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
172dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        // Check to see whether it comes from the old version.
173dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        if (lookupUri != null && LEGACY_AUTHORITY.equals(lookupUri.getAuthority())) {
174dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            final long rawContactId = ContentUris.parseId(lookupUri);
175dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            lookupUri = RawContacts.getContactLookupUri(getContentResolver(),
176dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
177dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        }
178dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
179dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mLookupUri = Preconditions.checkNotNull(lookupUri, "missing lookupUri");
180dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
181dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mExcludeMimes = intent.getStringArrayExtra(QuickContact.EXTRA_EXCLUDE_MIMES);
182dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
183dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("i"); // intent parsed
184dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
185dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mContactLoader = (ContactLoader) getLoaderManager().initLoader(
186dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki                LOADER_ID, null, mLoaderCallbacks);
187dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
188dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("ld"); // loader started
189dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
19010d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa        // Show QuickContact in front of soft input
19110d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
19210d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
19310d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa
194edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        setContentView(R.layout.quickcontact_activity);
195edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
196dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("l"); // layout inflated
197dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
198edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mFloatingLayout = (FloatingChildLayout) findViewById(R.id.floating_layout);
199edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mTrack = (ViewGroup) findViewById(R.id.track);
200edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mTrackScroller = (HorizontalScrollView) findViewById(R.id.track_scroller);
2019d85a2a39a4b9a0bacee8d25b2830784caf8551cYorke Lee        mOpenDetailsImage = (ImageView) findViewById(R.id.contact_details_image);
202edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mOpenDetailsPushLayerButton = (ImageButton) findViewById(R.id.open_details_push_layer);
203edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mListPager = (ViewPager) findViewById(R.id.item_list_pager);
204edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mSelectedTabRectangle = findViewById(R.id.selected_tab_rectangle);
2051792b08c500ed528e7d21401affd936b3a7b3dc6Daniel Lehmann        mLineAfterTrack = findViewById(R.id.line_after_track);
206edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
207edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mFloatingLayout.setOnOutsideTouchListener(new View.OnTouchListener() {
208edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            @Override
209edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            public boolean onTouch(View v, MotionEvent event) {
2102426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                handleOutsideTouch();
2112426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                return true;
212edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
213edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        });
214edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
215edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final OnClickListener openDetailsClickHandler = new OnClickListener() {
216edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            @Override
217edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            public void onClick(View v) {
218edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                final Intent intent = new Intent(Intent.ACTION_VIEW, mLookupUri);
2199815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann                mContactLoader.cacheResult();
2208ca93ed0938e00ee94b03e6d609895593cfdbdbdAdam Powell                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
221edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                startActivity(intent);
2222426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                close(false);
223edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
224edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        };
225edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mOpenDetailsPushLayerButton.setOnClickListener(openDetailsClickHandler);
226edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mListPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));
227edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mListPager.setOnPageChangeListener(new PageChangeListener());
228edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
229d1e501105d1ce2fb3e286635d0b2195e77e000afDaniel Lehmann        final Rect sourceBounds = intent.getSourceBounds();
230802fa62aac8edc92be136b8227ccafa53cd774fbMakoto Onuki        if (sourceBounds != null) {
231802fa62aac8edc92be136b8227ccafa53cd774fbMakoto Onuki            mFloatingLayout.setChildTargetScreen(sourceBounds);
232802fa62aac8edc92be136b8227ccafa53cd774fbMakoto Onuki        }
233edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
234edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // find and prepare correct header view
235edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mPhotoContainer = findViewById(R.id.photo_container);
23681281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        setHeaderNameText(R.id.name, R.string.missing_name);
237edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
238dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("v"); // view initialized
239edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
2403a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann        SchedulingUtils.doAfterLayout(mFloatingLayout, new Runnable() {
2413a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann            @Override
2423a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann            public void run() {
2433a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann                mFloatingLayout.fadeInBackground();
2443a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann            }
2453a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann        });
246dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
247dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("cf"); // onCreate finished
2482426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann    }
249edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
2502426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann    private void handleOutsideTouch() {
2512426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann        if (mFloatingLayout.isContentFullyVisible()) {
2522426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            close(true);
2532426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann        }
254edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
255edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
2562426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann    private void close(boolean withAnimation) {
257edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // cancel any pending queries
258cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        getLoaderManager().destroyLoader(LOADER_ID);
259edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
260edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        if (withAnimation) {
2612426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            mFloatingLayout.fadeOutBackground();
2622426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            final boolean animated = mFloatingLayout.hideContent(new Runnable() {
263edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                @Override
264edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                public void run() {
265ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                    // Wait until the final animation frame has been drawn, otherwise
266ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                    // there is jank as the framework transitions to the next Activity.
267ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                    SchedulingUtils.doAfterDraw(mFloatingLayout, new Runnable() {
268ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                        @Override
269ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                        public void run() {
270ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // Unfortunately, we need to also use postDelayed() to wait a moment
271ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // for the frame to be drawn, else the framework's activity-transition
272ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // animation will kick in before the final frame is available to it.
273ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // This seems unavoidable.  The problem isn't merely that there is no
274ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // post-draw listener API; if that were so, it would be sufficient to
275ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // call post() instead of postDelayed().
276ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            new Handler().postDelayed(new Runnable() {
277ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                                @Override
278ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                                public void run() {
279ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                                    finish();
280ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                                }
281ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            }, POST_DRAW_WAIT_DURATION);
282ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                        }
283ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                    });
284edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                }
285edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            });
2862426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            if (!animated) {
2872426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                // If we were in the wrong state, simply quit (this can happen for example
2882426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                // if the user pushes BACK before anything has loaded)
2892426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                finish();
2902426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            }
291edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        } else {
292edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            finish();
293edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
294edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
295edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
296edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @Override
297edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    public void onBackPressed() {
2982426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann        close(true);
299edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
300edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
30181281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /** Assign this string to the view if it is not empty. */
30281281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    private void setHeaderNameText(int id, int resId) {
30381281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        setHeaderNameText(id, getText(resId));
30481281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    }
30581281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan
30681281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /** Assign this string to the view if it is not empty. */
30781281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    private void setHeaderNameText(int id, CharSequence value) {
30881281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        final View view = mPhotoContainer.findViewById(id);
30981281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        if (view instanceof TextView) {
31081281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan            if (!TextUtils.isEmpty(value)) {
31181281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan                ((TextView)view).setText(value);
31281281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan            }
31381281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        }
31481281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    }
31581281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan
31681281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /**
317edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Check if the given MIME-type appears in the list of excluded MIME-types
318edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * that the most-recent caller requested.
319edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
320edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private boolean isMimeExcluded(String mimeType) {
321edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        if (mExcludeMimes == null) return false;
322edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String excludedMime : mExcludeMimes) {
323edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (TextUtils.equals(excludedMime, mimeType)) {
324edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                return true;
325edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
326edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
327edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        return false;
328edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
329edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
330edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
331cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann     * Handle the result from the ContactLoader
332edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
333851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private void bindData(Contact data) {
334edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final ResolveCache cache = ResolveCache.getInstance(this);
335edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final Context context = this;
336edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
3379d85a2a39a4b9a0bacee8d25b2830784caf8551cYorke Lee        mOpenDetailsImage.setVisibility(isMimeExcluded(Contacts.CONTENT_ITEM_TYPE) ? View.GONE
338edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                : View.VISIBLE);
339edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
340edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mDefaultsMap.clear();
341edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
342851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        mStopWatch.lap("sph"); // Start photo setting
343dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
344edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final ImageView photoView = (ImageView) mPhotoContainer.findViewById(R.id.photo);
3459758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus        mPhotoSetter.setupContactPhoto(data, photoView);
346edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
347dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("ph"); // Photo set
348dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
349851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        for (RawContact rawContact : data.getRawContacts()) {
350851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            for (DataItem dataItem : rawContact.getDataItems()) {
351851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final String mimeType = dataItem.getMimeType();
35247b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                final AccountType accountType = rawContact.getAccountType(this);
35347b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                final DataKind dataKind = AccountTypeManager.getInstance(this)
35447b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                        .getKindOrFallback(accountType, mimeType);
355cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
356cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                // Skip this data item if MIME-type excluded
357cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                if (isMimeExcluded(mimeType)) continue;
358cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
359851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final long dataId = dataItem.getId();
360851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final boolean isPrimary = dataItem.isPrimary();
361851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final boolean isSuperPrimary = dataItem.isSuperPrimary();
362cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
36347b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                if (dataKind != null) {
364cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    // Build an action for this data entry, find a mapping to a UI
365cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    // element, build its summary from the cursor, and collect it
366cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    // along with all others of this MIME-type.
36747b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                    final Action action = new DataAction(context, dataItem, dataKind);
3688a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu                    final boolean wasAdded = considerAdd(action, cache, isSuperPrimary);
369cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    if (wasAdded) {
370cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        // Remember the default
371cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        if (isSuperPrimary || (isPrimary && (mDefaultsMap.get(mimeType) == null))) {
372cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                            mDefaultsMap.put(mimeType, action);
373edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                        }
374edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    }
375edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                }
376edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
377cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                // Handle Email rows with presence data as Im entry
3789daca14706f3699c9e9d46dfb522132fc566e57eDaniel Lehmann                final DataStatus status = data.getStatuses().get(dataId);
379851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                if (status != null && dataItem instanceof EmailDataItem) {
380851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    final EmailDataItem email = (EmailDataItem) dataItem;
381851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    final ImDataItem im = ImDataItem.createFromEmail(email);
38247b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                    if (dataKind != null) {
38347b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                        final DataAction action = new DataAction(context, im, dataKind);
3849daca14706f3699c9e9d46dfb522132fc566e57eDaniel Lehmann                        action.setPresence(status.getPresence());
3858a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu                        considerAdd(action, cache, isSuperPrimary);
386cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    }
387edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                }
388edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
389edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
390edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
391dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("e"); // Entities inflated
392dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
393edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // Collapse Action Lists (remove e.g. duplicate e-mail addresses from different sources)
394edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (List<Action> actionChildren : mActions.values()) {
395edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            Collapser.collapseList(actionChildren);
396edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
397edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
398dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("c"); // List collapsed
399dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
400cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        setHeaderNameText(R.id.name, data.getDisplayName());
401edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
402edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // All the mime-types to add.
403edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final Set<String> containedTypes = new HashSet<String>(mActions.keySet());
404edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mSortedActionMimeTypes.clear();
405edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // First, add LEADING_MIMETYPES, which are most common.
406edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String mimeType : LEADING_MIMETYPES) {
407edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (containedTypes.contains(mimeType)) {
408edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                mSortedActionMimeTypes.add(mimeType);
409edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                containedTypes.remove(mimeType);
410edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
411edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
412edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
413edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // Add all the remaining ones that are not TRAILING
414edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String mimeType : containedTypes.toArray(new String[containedTypes.size()])) {
415edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (!TRAILING_MIMETYPES.contains(mimeType)) {
416edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                mSortedActionMimeTypes.add(mimeType);
417edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                containedTypes.remove(mimeType);
418edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
419edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
420edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
421edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // Then, add TRAILING_MIMETYPES, which are least common.
422edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String mimeType : TRAILING_MIMETYPES) {
423edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (containedTypes.contains(mimeType)) {
424edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                containedTypes.remove(mimeType);
425edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                mSortedActionMimeTypes.add(mimeType);
426edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
427edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
428edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
429dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("mt"); // Mime types initialized
430dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
431edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // Add buttons for each mimetype
432cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        mTrack.removeAllViews();
433edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String mimeType : mSortedActionMimeTypes) {
434edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final View actionView = inflateAction(mimeType, cache, mTrack);
435edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            mTrack.addView(actionView);
436edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
437edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
438dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("mt"); // Buttons added
439dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
440edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final boolean hasData = !mSortedActionMimeTypes.isEmpty();
441edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mTrackScroller.setVisibility(hasData ? View.VISIBLE : View.GONE);
442edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mSelectedTabRectangle.setVisibility(hasData ? View.VISIBLE : View.GONE);
4431792b08c500ed528e7d21401affd936b3a7b3dc6Daniel Lehmann        mLineAfterTrack.setVisibility(hasData ? View.VISIBLE : View.GONE);
444edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mListPager.setVisibility(hasData ? View.VISIBLE : View.GONE);
445edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
446edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
447edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
448edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Consider adding the given {@link Action}, which will only happen if
449edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * {@link PackageManager} finds an application to handle
450edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * {@link Action#getIntent()}.
4518a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu     * @param action the action to handle
4528a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu     * @param resolveCache cache of applications that can handle actions
4538a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu     * @param front indicates whether to add the action to the front of the list
454edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * @return true if action has been added
455edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
4568a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu    private boolean considerAdd(Action action, ResolveCache resolveCache, boolean front) {
457edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        if (resolveCache.hasResolve(action)) {
4588a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu            mActions.put(action.getMimeType(), action, front);
459edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            return true;
460edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
461edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        return false;
462edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
463edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
464edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
465edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Inflate the in-track view for the action of the given MIME-type, collapsing duplicate values.
466edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Will use the icon provided by the {@link DataKind}.
467edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
468edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private View inflateAction(String mimeType, ResolveCache resolveCache, ViewGroup root) {
469edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final CheckableImageView typeView = (CheckableImageView) getLayoutInflater().inflate(
470edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                R.layout.quickcontact_track_button, root, false);
471edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
472edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        List<Action> children = mActions.get(mimeType);
473edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        typeView.setTag(mimeType);
474edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final Action firstInfo = children.get(0);
475edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
476edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // Set icon and listen for clicks
477edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final CharSequence descrip = resolveCache.getDescription(firstInfo);
478edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final Drawable icon = resolveCache.getIcon(firstInfo);
479edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        typeView.setChecked(false);
480edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        typeView.setContentDescription(descrip);
481edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        typeView.setImageDrawable(icon);
482edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        typeView.setOnClickListener(mTypeViewClickListener);
483edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
484edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        return typeView;
485edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
486edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
487edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private CheckableImageView getActionViewAt(int position) {
488edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        return (CheckableImageView) mTrack.getChildAt(position);
489edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
490edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
491edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @Override
492edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    public void onAttachFragment(Fragment fragment) {
493edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final QuickContactListFragment listFragment = (QuickContactListFragment) fragment;
494edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        listFragment.setListener(mListFragmentListener);
495edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
496edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
497851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private LoaderCallbacks<Contact> mLoaderCallbacks =
498851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            new LoaderCallbacks<Contact>() {
499cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
500851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoaderReset(Loader<Contact> loader) {
501cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
502cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
503cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
504851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoadFinished(Loader<Contact> loader, Contact data) {
505dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            mStopWatch.lap("lf"); // onLoadFinished
506cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (isFinishing()) {
5072426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                close(false);
508cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                return;
509cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
510cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (data.isError()) {
511cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                // This shouldn't ever happen, so throw an exception. The {@link ContactLoader}
512cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                // should log the actual exception.
513cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                throw new IllegalStateException("Failed to load contact", data.getException());
514cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
515cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (data.isNotFound()) {
516cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                Log.i(TAG, "No contact found: " + ((ContactLoader)loader).getLookupUri());
517cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                Toast.makeText(QuickContactActivity.this, R.string.invalidContactMessage,
518cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        Toast.LENGTH_LONG).show();
5192426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                close(false);
520cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                return;
521cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
522cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
523cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            bindData(data);
524cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
525dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            mStopWatch.lap("bd"); // bindData finished
526dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
5272426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            if (TRACE_LAUNCH) android.os.Debug.stopMethodTracing();
528fc0a89fdb1e0bfe5c47e733f867ca520e117316bMakoto Onuki            if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
529fc0a89fdb1e0bfe5c47e733f867ca520e117316bMakoto Onuki                Log.d(Constants.PERFORMANCE_TAG, "QuickContact shown");
530fc0a89fdb1e0bfe5c47e733f867ca520e117316bMakoto Onuki            }
531cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
532cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            // Data bound and ready, pull curtain to show. Put this on the Handler to ensure
533cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            // that the layout passes are completed
5346f5557e3dc3cd12182026bdfea17b15d4d9b7dfcJosh Gargus            SchedulingUtils.doAfterLayout(mFloatingLayout, new Runnable() {
535cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                @Override
536cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                public void run() {
5372426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                    mFloatingLayout.showContent(new Runnable() {
538cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        @Override
539cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        public void run() {
5409815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann                            mContactLoader.upgradeToFullContact();
541cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        }
542cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    });
543cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                }
544cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            });
545dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            mStopWatch.stopAndLog(TAG, 0);
546dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            mStopWatch = StopWatch.getNullStopWatch(); // We're done with it.
547cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
548cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
549cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
550851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public Loader<Contact> onCreateLoader(int id, Bundle args) {
551cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (mLookupUri == null) {
552cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                Log.wtf(TAG, "Lookup uri wasn't initialized. Loader was started too early");
553cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
55445ee872fe7be69c6b3f0c59167eecd11af467812Makoto Onuki            return new ContactLoader(getApplicationContext(), mLookupUri, false);
555cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
556cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann    };
557cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
558edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /** A type (e.g. Call/Addresses was clicked) */
559edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private final OnClickListener mTypeViewClickListener = new OnClickListener() {
560edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
561edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public void onClick(View view) {
562edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final CheckableImageView actionView = (CheckableImageView)view;
563edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final String mimeType = (String) actionView.getTag();
564edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            int index = mSortedActionMimeTypes.indexOf(mimeType);
565edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            mListPager.setCurrentItem(index, true);
566edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
567edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    };
568edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
569edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private class ViewPagerAdapter extends FragmentPagerAdapter {
570edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public ViewPagerAdapter(FragmentManager fragmentManager) {
571edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            super(fragmentManager);
572edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
573edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
574edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
575edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public Fragment getItem(int position) {
576edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            QuickContactListFragment fragment = new QuickContactListFragment();
577edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final String mimeType = mSortedActionMimeTypes.get(position);
578edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final List<Action> actions = mActions.get(mimeType);
579edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            fragment.setActions(actions);
580edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            return fragment;
581edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
582edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
583edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
584edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public int getCount() {
585edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            return mSortedActionMimeTypes.size();
586edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
587edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
588edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
589edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private class PageChangeListener extends SimpleOnPageChangeListener {
590edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
591edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public void onPageSelected(int position) {
592edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final CheckableImageView actionView = getActionViewAt(position);
593edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            mTrackScroller.requestChildRectangleOnScreen(actionView,
594edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    new Rect(0, 0, actionView.getWidth(), actionView.getHeight()), false);
5954c2909075a8271b9478506358c15e55fd458e0ccChiao Cheng            renderSelectedRectangle(position, 0);
596edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
597edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
598edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
599edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
6004c2909075a8271b9478506358c15e55fd458e0ccChiao Cheng            renderSelectedRectangle(position, positionOffset);
6014c2909075a8271b9478506358c15e55fd458e0ccChiao Cheng        }
6024c2909075a8271b9478506358c15e55fd458e0ccChiao Cheng
6034c2909075a8271b9478506358c15e55fd458e0ccChiao Cheng        private void renderSelectedRectangle(int position, float positionOffset) {
604edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final RelativeLayout.LayoutParams layoutParams =
605edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    (RelativeLayout.LayoutParams) mSelectedTabRectangle.getLayoutParams();
6064c2909075a8271b9478506358c15e55fd458e0ccChiao Cheng            final int width = layoutParams.width;
607edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            layoutParams.leftMargin = (int) ((position + positionOffset) * width);
608edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            mSelectedTabRectangle.setLayoutParams(layoutParams);
609edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
610edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
611edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
612edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private final QuickContactListFragment.Listener mListFragmentListener =
613edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            new QuickContactListFragment.Listener() {
614edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
615edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public void onOutsideClick() {
616edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            // If there is no background, we want to dismiss, because to the user it seems
617edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            // like he had touched outside. If the ViewPager is solid however, those taps
618edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            // must be ignored
619edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final boolean isTransparent = mListPager.getBackground() == null;
620edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (isTransparent) handleOutsideTouch();
621edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
622edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
623edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
624edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public void onItemClicked(final Action action, final boolean alternate) {
625edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final Runnable startAppRunnable = new Runnable() {
626edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                @Override
627edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                public void run() {
628edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    try {
629edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                        startActivity(alternate ? action.getAlternateIntent() : action.getIntent());
630edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    } catch (ActivityNotFoundException e) {
631edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                        Toast.makeText(QuickContactActivity.this, R.string.quickcontact_missing_app,
632edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                                Toast.LENGTH_SHORT).show();
633edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    }
634edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
6352426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                    close(false);
636edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                }
637edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            };
638edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            // Defer the action to make the window properly repaint
639edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            new Handler().post(startAppRunnable);
640edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
641edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    };
642edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann}
643