QuickContactActivity.java revision 851222a96b5d68602fb361ea3527101e893f67e3
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
59e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.Collapser;
60e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
61851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.Contact;
62851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.ContactLoader;
63851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContact;
64851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.dataitem.DataItem;
65851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.dataitem.DataKind;
66851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.dataitem.EmailDataItem;
67851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.dataitem.ImDataItem;
68e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.Constants;
69e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.DataStatus;
70e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.ImageViewDrawableSetter;
71e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.SchedulingUtils;
72e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.StopWatch;
73e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.base.Preconditions;
74e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.google.common.collect.Lists;
75e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
76edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.HashMap;
77edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.HashSet;
78edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.List;
79edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannimport java.util.Set;
80edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
81edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann// TODO: Save selected tab index during rotation
82edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
83edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann/**
84edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * Mostly translucent {@link Activity} that shows QuickContact dialog. It loads
85edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * data asynchronously, and then shows a popup with details centered around
86edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann * {@link Intent#getSourceBounds()}.
87edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann */
88edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmannpublic class QuickContactActivity extends Activity {
89edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final String TAG = "QuickContact";
90edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
91edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final boolean TRACE_LAUNCH = false;
92edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final String TRACE_TAG = "quickcontact";
93ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus    private static final int POST_DRAW_WAIT_DURATION = 60;
94dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki    private static final boolean ENABLE_STOPWATCH = false;
95dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
96edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
97edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @SuppressWarnings("deprecation")
98edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final String LEGACY_AUTHORITY = android.provider.Contacts.AUTHORITY;
99edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
100edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private Uri mLookupUri;
101edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private String[] mExcludeMimes;
102edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private List<String> mSortedActionMimeTypes = Lists.newArrayList();
103edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
104edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private FloatingChildLayout mFloatingLayout;
105edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
106edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private View mPhotoContainer;
107edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private ViewGroup mTrack;
108edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private HorizontalScrollView mTrackScroller;
109edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private View mSelectedTabRectangle;
1101792b08c500ed528e7d21401affd936b3a7b3dc6Daniel Lehmann    private View mLineAfterTrack;
111edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
112edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private ImageButton mOpenDetailsButton;
113edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private ImageButton mOpenDetailsPushLayerButton;
114edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private ViewPager mListPager;
115edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
1169815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann    private ContactLoader mContactLoader;
1179815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann
1189758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus    private final ImageViewDrawableSetter mPhotoSetter = new ImageViewDrawableSetter();
1199758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus
120edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
121edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Keeps the default action per mimetype. Empty if no default actions are set
122edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
123edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private HashMap<String, Action> mDefaultsMap = new HashMap<String, Action>();
124edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
125edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
126edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Set of {@link Action} that are associated with the aggregate currently
127edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * displayed by this dialog, represented as a map from {@link String}
128edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * MIME-type to a list of {@link Action}.
129edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
130edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private ActionMultiMap mActions = new ActionMultiMap();
131edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
132edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
133edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * {@link #LEADING_MIMETYPES} and {@link #TRAILING_MIMETYPES} are used to sort MIME-types.
134edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     *
135edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * <p>The MIME-types in {@link #LEADING_MIMETYPES} appear in the front of the dialog,
136edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * in the order specified here.</p>
137edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     *
138edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * <p>The ones in {@link #TRAILING_MIMETYPES} appear in the end of the dialog, in the order
139edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * specified here.</p>
140edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     *
141edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * <p>The rest go between them, in the order in the array.</p>
142edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
143edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final List<String> LEADING_MIMETYPES = Lists.newArrayList(
144edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            Phone.CONTENT_ITEM_TYPE, SipAddress.CONTENT_ITEM_TYPE, Email.CONTENT_ITEM_TYPE);
145edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
146edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /** See {@link #LEADING_MIMETYPES}. */
147edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private static final List<String> TRAILING_MIMETYPES = Lists.newArrayList(
148edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            StructuredPostal.CONTENT_ITEM_TYPE, Website.CONTENT_ITEM_TYPE);
149edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
150cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann    /** Id for the background loader */
151cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann    private static final int LOADER_ID = 0;
152edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
153dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki    private StopWatch mStopWatch = ENABLE_STOPWATCH
154dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            ? StopWatch.start("QuickContact") : StopWatch.getNullStopWatch();
155dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
156edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @Override
157edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    protected void onCreate(Bundle icicle) {
158dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("c"); // create start
159edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        super.onCreate(icicle);
160edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
161dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("sc"); // super.onCreate
162dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
1632426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann        if (TRACE_LAUNCH) android.os.Debug.startMethodTracing(TRACE_TAG);
1642426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann
165dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        // Parse intent
166dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        final Intent intent = getIntent();
167dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
168dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        Uri lookupUri = intent.getData();
169dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
170dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        // Check to see whether it comes from the old version.
171dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        if (lookupUri != null && LEGACY_AUTHORITY.equals(lookupUri.getAuthority())) {
172dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            final long rawContactId = ContentUris.parseId(lookupUri);
173dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            lookupUri = RawContacts.getContactLookupUri(getContentResolver(),
174dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
175dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        }
176dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
177dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mLookupUri = Preconditions.checkNotNull(lookupUri, "missing lookupUri");
178dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
179dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mExcludeMimes = intent.getStringArrayExtra(QuickContact.EXTRA_EXCLUDE_MIMES);
180dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
181dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("i"); // intent parsed
182dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
183dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mContactLoader = (ContactLoader) getLoaderManager().initLoader(
184dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki                LOADER_ID, null, mLoaderCallbacks);
185dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
186dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("ld"); // loader started
187dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
18810d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa        // Show QuickContact in front of soft input
18910d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
19010d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
19110d7df7bab8c332744fad64b9167c2ef061070e4Daisuke Miyakawa
192edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        setContentView(R.layout.quickcontact_activity);
193edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
194dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("l"); // layout inflated
195dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
196edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mFloatingLayout = (FloatingChildLayout) findViewById(R.id.floating_layout);
197edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mTrack = (ViewGroup) findViewById(R.id.track);
198edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mTrackScroller = (HorizontalScrollView) findViewById(R.id.track_scroller);
199edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mOpenDetailsButton = (ImageButton) findViewById(R.id.open_details_button);
200edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mOpenDetailsPushLayerButton = (ImageButton) findViewById(R.id.open_details_push_layer);
201edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mListPager = (ViewPager) findViewById(R.id.item_list_pager);
202edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mSelectedTabRectangle = findViewById(R.id.selected_tab_rectangle);
2031792b08c500ed528e7d21401affd936b3a7b3dc6Daniel Lehmann        mLineAfterTrack = findViewById(R.id.line_after_track);
204edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
205edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mFloatingLayout.setOnOutsideTouchListener(new View.OnTouchListener() {
206edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            @Override
207edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            public boolean onTouch(View v, MotionEvent event) {
2082426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                handleOutsideTouch();
2092426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                return true;
210edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
211edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        });
212edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
213edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final OnClickListener openDetailsClickHandler = new OnClickListener() {
214edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            @Override
215edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            public void onClick(View v) {
216edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                final Intent intent = new Intent(Intent.ACTION_VIEW, mLookupUri);
2179815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann                mContactLoader.cacheResult();
2188ca93ed0938e00ee94b03e6d609895593cfdbdbdAdam Powell                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
219edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                startActivity(intent);
2202426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                close(false);
221edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
222edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        };
223edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mOpenDetailsButton.setOnClickListener(openDetailsClickHandler);
224edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mOpenDetailsPushLayerButton.setOnClickListener(openDetailsClickHandler);
225edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mListPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));
226edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mListPager.setOnPageChangeListener(new PageChangeListener());
227edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
228d1e501105d1ce2fb3e286635d0b2195e77e000afDaniel Lehmann        final Rect sourceBounds = intent.getSourceBounds();
229802fa62aac8edc92be136b8227ccafa53cd774fbMakoto Onuki        if (sourceBounds != null) {
230802fa62aac8edc92be136b8227ccafa53cd774fbMakoto Onuki            mFloatingLayout.setChildTargetScreen(sourceBounds);
231802fa62aac8edc92be136b8227ccafa53cd774fbMakoto Onuki        }
232edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
233edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // find and prepare correct header view
234edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mPhotoContainer = findViewById(R.id.photo_container);
23581281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        setHeaderNameText(R.id.name, R.string.missing_name);
236edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
237dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("v"); // view initialized
238edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
2393a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann        SchedulingUtils.doAfterLayout(mFloatingLayout, new Runnable() {
2403a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann            @Override
2413a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann            public void run() {
2423a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann                mFloatingLayout.fadeInBackground();
2433a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann            }
2443a53c73f04eef94b311bb0469c1d0ca7059c0411Daniel Lehmann        });
245dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
246dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("cf"); // onCreate finished
2472426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann    }
248edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
2492426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann    private void handleOutsideTouch() {
2502426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann        if (mFloatingLayout.isContentFullyVisible()) {
2512426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            close(true);
2522426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann        }
253edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
254edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
2552426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann    private void close(boolean withAnimation) {
256edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // cancel any pending queries
257cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        getLoaderManager().destroyLoader(LOADER_ID);
258edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
259edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        if (withAnimation) {
2602426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            mFloatingLayout.fadeOutBackground();
2612426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            final boolean animated = mFloatingLayout.hideContent(new Runnable() {
262edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                @Override
263edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                public void run() {
264ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                    // Wait until the final animation frame has been drawn, otherwise
265ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                    // there is jank as the framework transitions to the next Activity.
266ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                    SchedulingUtils.doAfterDraw(mFloatingLayout, new Runnable() {
267ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                        @Override
268ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                        public void run() {
269ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // Unfortunately, we need to also use postDelayed() to wait a moment
270ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // for the frame to be drawn, else the framework's activity-transition
271ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // animation will kick in before the final frame is available to it.
272ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // This seems unavoidable.  The problem isn't merely that there is no
273ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // post-draw listener API; if that were so, it would be sufficient to
274ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            // call post() instead of postDelayed().
275ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            new Handler().postDelayed(new Runnable() {
276ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                                @Override
277ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                                public void run() {
278ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                                    finish();
279ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                                }
280ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                            }, POST_DRAW_WAIT_DURATION);
281ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                        }
282ee287e9a7617fc38119a026f7e802f6d7d47113cJosh Gargus                    });
283edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                }
284edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            });
2852426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            if (!animated) {
2862426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                // If we were in the wrong state, simply quit (this can happen for example
2872426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                // if the user pushes BACK before anything has loaded)
2882426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                finish();
2892426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            }
290edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        } else {
291edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            finish();
292edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
293edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
294edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
295edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @Override
296edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    public void onBackPressed() {
2972426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann        close(true);
298edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
299edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
30081281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /** Assign this string to the view if it is not empty. */
30181281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    private void setHeaderNameText(int id, int resId) {
30281281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        setHeaderNameText(id, getText(resId));
30381281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    }
30481281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan
30581281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /** Assign this string to the view if it is not empty. */
30681281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    private void setHeaderNameText(int id, CharSequence value) {
30781281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        final View view = mPhotoContainer.findViewById(id);
30881281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        if (view instanceof TextView) {
30981281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan            if (!TextUtils.isEmpty(value)) {
31081281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan                ((TextView)view).setText(value);
31181281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan            }
31281281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan        }
31381281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    }
31481281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan
31581281eefd5aaf339cbfa080ddfa6c6f63caca71aKatherine Kuan    /**
316edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Check if the given MIME-type appears in the list of excluded MIME-types
317edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * that the most-recent caller requested.
318edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
319edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private boolean isMimeExcluded(String mimeType) {
320edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        if (mExcludeMimes == null) return false;
321edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String excludedMime : mExcludeMimes) {
322edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (TextUtils.equals(excludedMime, mimeType)) {
323edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                return true;
324edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
325edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
326edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        return false;
327edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
328edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
329edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
330cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann     * Handle the result from the ContactLoader
331edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
332851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private void bindData(Contact data) {
333edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final ResolveCache cache = ResolveCache.getInstance(this);
334edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final Context context = this;
335edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
336edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mOpenDetailsButton.setVisibility(isMimeExcluded(Contacts.CONTENT_ITEM_TYPE) ? View.GONE
337edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                : View.VISIBLE);
338edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
339edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mDefaultsMap.clear();
340edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
341851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        mStopWatch.lap("sph"); // Start photo setting
342dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
343edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final ImageView photoView = (ImageView) mPhotoContainer.findViewById(R.id.photo);
3449758a92fac3e9f64892d893c992f6020d7fe3bfdJosh Gargus        mPhotoSetter.setupContactPhoto(data, photoView);
345edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
346dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("ph"); // Photo set
347dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
348851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        for (RawContact rawContact : data.getRawContacts()) {
349851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            for (DataItem dataItem : rawContact.getDataItems()) {
350851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final String mimeType = dataItem.getMimeType();
351cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
352cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                // Skip this data item if MIME-type excluded
353cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                if (isMimeExcluded(mimeType)) continue;
354cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
355851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final long dataId = dataItem.getId();
356851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final boolean isPrimary = dataItem.isPrimary();
357851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final boolean isSuperPrimary = dataItem.isSuperPrimary();
358cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
359851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                if (dataItem.getDataKind() != null) {
360cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    // Build an action for this data entry, find a mapping to a UI
361cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    // element, build its summary from the cursor, and collect it
362cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    // along with all others of this MIME-type.
363851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    final Action action = new DataAction(context, dataItem);
3648a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu                    final boolean wasAdded = considerAdd(action, cache, isSuperPrimary);
365cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    if (wasAdded) {
366cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        // Remember the default
367cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        if (isSuperPrimary || (isPrimary && (mDefaultsMap.get(mimeType) == null))) {
368cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                            mDefaultsMap.put(mimeType, action);
369edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                        }
370edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    }
371edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                }
372edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
373cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                // Handle Email rows with presence data as Im entry
3749daca14706f3699c9e9d46dfb522132fc566e57eDaniel Lehmann                final DataStatus status = data.getStatuses().get(dataId);
375851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                if (status != null && dataItem instanceof EmailDataItem) {
376851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    final EmailDataItem email = (EmailDataItem) dataItem;
377851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    final ImDataItem im = ImDataItem.createFromEmail(email);
378851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    if (im.getDataKind() != null) {
379851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                        final DataAction action = new DataAction(context, im);
3809daca14706f3699c9e9d46dfb522132fc566e57eDaniel Lehmann                        action.setPresence(status.getPresence());
3818a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu                        considerAdd(action, cache, isSuperPrimary);
382cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    }
383edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                }
384edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
385edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
386edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
387dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("e"); // Entities inflated
388dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
389edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // Collapse Action Lists (remove e.g. duplicate e-mail addresses from different sources)
390edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (List<Action> actionChildren : mActions.values()) {
391edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            Collapser.collapseList(actionChildren);
392edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
393edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
394dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("c"); // List collapsed
395dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
396cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        setHeaderNameText(R.id.name, data.getDisplayName());
397edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
398edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // All the mime-types to add.
399edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final Set<String> containedTypes = new HashSet<String>(mActions.keySet());
400edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mSortedActionMimeTypes.clear();
401edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // First, add LEADING_MIMETYPES, which are most common.
402edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String mimeType : LEADING_MIMETYPES) {
403edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (containedTypes.contains(mimeType)) {
404edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                mSortedActionMimeTypes.add(mimeType);
405edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                containedTypes.remove(mimeType);
406edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
407edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
408edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
409edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // Add all the remaining ones that are not TRAILING
410edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String mimeType : containedTypes.toArray(new String[containedTypes.size()])) {
411edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (!TRAILING_MIMETYPES.contains(mimeType)) {
412edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                mSortedActionMimeTypes.add(mimeType);
413edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                containedTypes.remove(mimeType);
414edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
415edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
416edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
417edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // Then, add TRAILING_MIMETYPES, which are least common.
418edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String mimeType : TRAILING_MIMETYPES) {
419edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (containedTypes.contains(mimeType)) {
420edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                containedTypes.remove(mimeType);
421edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                mSortedActionMimeTypes.add(mimeType);
422edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            }
423edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
424edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
425dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("mt"); // Mime types initialized
426dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
427edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // Add buttons for each mimetype
428cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        mTrack.removeAllViews();
429edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        for (String mimeType : mSortedActionMimeTypes) {
430edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final View actionView = inflateAction(mimeType, cache, mTrack);
431edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            mTrack.addView(actionView);
432edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
433edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
434dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki        mStopWatch.lap("mt"); // Buttons added
435dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
436edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final boolean hasData = !mSortedActionMimeTypes.isEmpty();
437edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mTrackScroller.setVisibility(hasData ? View.VISIBLE : View.GONE);
438edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mSelectedTabRectangle.setVisibility(hasData ? View.VISIBLE : View.GONE);
4391792b08c500ed528e7d21401affd936b3a7b3dc6Daniel Lehmann        mLineAfterTrack.setVisibility(hasData ? View.VISIBLE : View.GONE);
440edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        mListPager.setVisibility(hasData ? View.VISIBLE : View.GONE);
441edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
442edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
443edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
444edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Consider adding the given {@link Action}, which will only happen if
445edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * {@link PackageManager} finds an application to handle
446edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * {@link Action#getIntent()}.
4478a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu     * @param action the action to handle
4488a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu     * @param resolveCache cache of applications that can handle actions
4498a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu     * @param front indicates whether to add the action to the front of the list
450edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * @return true if action has been added
451edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
4528a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu    private boolean considerAdd(Action action, ResolveCache resolveCache, boolean front) {
453edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        if (resolveCache.hasResolve(action)) {
4548a0dd0f08ab11e9c6dad386e4411aeeb4c0cd73fMaurice Chu            mActions.put(action.getMimeType(), action, front);
455edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            return true;
456edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
457edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        return false;
458edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
459edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
460edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /**
461edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Inflate the in-track view for the action of the given MIME-type, collapsing duplicate values.
462edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     * Will use the icon provided by the {@link DataKind}.
463edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann     */
464edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private View inflateAction(String mimeType, ResolveCache resolveCache, ViewGroup root) {
465edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final CheckableImageView typeView = (CheckableImageView) getLayoutInflater().inflate(
466edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                R.layout.quickcontact_track_button, root, false);
467edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
468edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        List<Action> children = mActions.get(mimeType);
469edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        typeView.setTag(mimeType);
470edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final Action firstInfo = children.get(0);
471edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
472edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        // Set icon and listen for clicks
473edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final CharSequence descrip = resolveCache.getDescription(firstInfo);
474edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final Drawable icon = resolveCache.getIcon(firstInfo);
475edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        typeView.setChecked(false);
476edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        typeView.setContentDescription(descrip);
477edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        typeView.setImageDrawable(icon);
478edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        typeView.setOnClickListener(mTypeViewClickListener);
479edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
480edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        return typeView;
481edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
482edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
483edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private CheckableImageView getActionViewAt(int position) {
484edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        return (CheckableImageView) mTrack.getChildAt(position);
485edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
486edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
487edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    @Override
488edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    public void onAttachFragment(Fragment fragment) {
489edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        final QuickContactListFragment listFragment = (QuickContactListFragment) fragment;
490edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        listFragment.setListener(mListFragmentListener);
491edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
492edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
493851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private LoaderCallbacks<Contact> mLoaderCallbacks =
494851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            new LoaderCallbacks<Contact>() {
495cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
496851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoaderReset(Loader<Contact> loader) {
497cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
498cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
499cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
500851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoadFinished(Loader<Contact> loader, Contact data) {
501dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            mStopWatch.lap("lf"); // onLoadFinished
502cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (isFinishing()) {
5032426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                close(false);
504cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                return;
505cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
506cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (data.isError()) {
507cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                // This shouldn't ever happen, so throw an exception. The {@link ContactLoader}
508cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                // should log the actual exception.
509cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                throw new IllegalStateException("Failed to load contact", data.getException());
510cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
511cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (data.isNotFound()) {
512cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                Log.i(TAG, "No contact found: " + ((ContactLoader)loader).getLookupUri());
513cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                Toast.makeText(QuickContactActivity.this, R.string.invalidContactMessage,
514cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        Toast.LENGTH_LONG).show();
5152426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                close(false);
516cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                return;
517cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
518cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
519cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            bindData(data);
520cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
521dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            mStopWatch.lap("bd"); // bindData finished
522dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki
5232426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann            if (TRACE_LAUNCH) android.os.Debug.stopMethodTracing();
524fc0a89fdb1e0bfe5c47e733f867ca520e117316bMakoto Onuki            if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
525fc0a89fdb1e0bfe5c47e733f867ca520e117316bMakoto Onuki                Log.d(Constants.PERFORMANCE_TAG, "QuickContact shown");
526fc0a89fdb1e0bfe5c47e733f867ca520e117316bMakoto Onuki            }
527cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
528cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            // Data bound and ready, pull curtain to show. Put this on the Handler to ensure
529cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            // that the layout passes are completed
5306f5557e3dc3cd12182026bdfea17b15d4d9b7dfcJosh Gargus            SchedulingUtils.doAfterLayout(mFloatingLayout, new Runnable() {
531cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                @Override
532cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                public void run() {
5332426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                    mFloatingLayout.showContent(new Runnable() {
534cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        @Override
535cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        public void run() {
5369815d7f98baf80ce51b0cf1f01f48a3dbb9a9db9Daniel Lehmann                            mContactLoader.upgradeToFullContact();
537cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                        }
538cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                    });
539cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                }
540cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            });
541dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            mStopWatch.stopAndLog(TAG, 0);
542dfe8cc82e8aa31929bb85eb68b7de3492b875d57Makoto Onuki            mStopWatch = StopWatch.getNullStopWatch(); // We're done with it.
543cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
544cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
545cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        @Override
546851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public Loader<Contact> onCreateLoader(int id, Bundle args) {
547cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            if (mLookupUri == null) {
548cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann                Log.wtf(TAG, "Lookup uri wasn't initialized. Loader was started too early");
549cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann            }
55045ee872fe7be69c6b3f0c59167eecd11af467812Makoto Onuki            return new ContactLoader(getApplicationContext(), mLookupUri, false);
551cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann        }
552cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann    };
553cb8d73fc8ea538d0b63dd77210c05c5b8de32f03Daniel Lehmann
554edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    /** A type (e.g. Call/Addresses was clicked) */
555edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private final OnClickListener mTypeViewClickListener = new OnClickListener() {
556edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
557edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public void onClick(View view) {
558edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final CheckableImageView actionView = (CheckableImageView)view;
559edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final String mimeType = (String) actionView.getTag();
560edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            int index = mSortedActionMimeTypes.indexOf(mimeType);
561edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            mListPager.setCurrentItem(index, true);
562edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
563edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    };
564edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
565edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private class ViewPagerAdapter extends FragmentPagerAdapter {
566edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public ViewPagerAdapter(FragmentManager fragmentManager) {
567edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            super(fragmentManager);
568edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
569edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
570edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
571edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public Fragment getItem(int position) {
572edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            QuickContactListFragment fragment = new QuickContactListFragment();
573edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final String mimeType = mSortedActionMimeTypes.get(position);
574edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final List<Action> actions = mActions.get(mimeType);
575edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            fragment.setActions(actions);
576edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            return fragment;
577edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
578edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
579edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
580edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public int getCount() {
581edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            return mSortedActionMimeTypes.size();
582edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
583edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
584edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
585edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private class PageChangeListener extends SimpleOnPageChangeListener {
586edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
587edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public void onPageSelected(int position) {
588edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final CheckableImageView actionView = getActionViewAt(position);
589edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            mTrackScroller.requestChildRectangleOnScreen(actionView,
590edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    new Rect(0, 0, actionView.getWidth(), actionView.getHeight()), false);
591edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
592edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
593edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
594edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
595edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final RelativeLayout.LayoutParams layoutParams =
596edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    (RelativeLayout.LayoutParams) mSelectedTabRectangle.getLayoutParams();
597edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final int width = mSelectedTabRectangle.getWidth();
598edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            layoutParams.leftMargin = (int) ((position + positionOffset) * width);
599edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            mSelectedTabRectangle.setLayoutParams(layoutParams);
600edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
601edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    }
602edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
603edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    private final QuickContactListFragment.Listener mListFragmentListener =
604edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            new QuickContactListFragment.Listener() {
605edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
606edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public void onOutsideClick() {
607edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            // If there is no background, we want to dismiss, because to the user it seems
608edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            // like he had touched outside. If the ViewPager is solid however, those taps
609edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            // must be ignored
610edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final boolean isTransparent = mListPager.getBackground() == null;
611edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            if (isTransparent) handleOutsideTouch();
612edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
613edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
614edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        @Override
615edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        public void onItemClicked(final Action action, final boolean alternate) {
616edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            final Runnable startAppRunnable = new Runnable() {
617edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                @Override
618edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                public void run() {
619edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    try {
620edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                        startActivity(alternate ? action.getAlternateIntent() : action.getIntent());
621edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    } catch (ActivityNotFoundException e) {
622edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                        Toast.makeText(QuickContactActivity.this, R.string.quickcontact_missing_app,
623edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                                Toast.LENGTH_SHORT).show();
624edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                    }
625edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann
6262426cb015ba4cb679a525bd1ffe223527375468cDaniel Lehmann                    close(false);
627edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann                }
628edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            };
629edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            // Defer the action to make the window properly repaint
630edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann            new Handler().post(startAppRunnable);
631edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann        }
632edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann    };
633edb576aab33efff623691a89ace3c76cb2ff12d1Daniel Lehmann}
634