Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 1 | /* |
Daniel Lehmann | ef3f8f0 | 2010-07-26 18:55:25 -0700 | [diff] [blame] | 2 | * Copyright (C) 2010 The Android Open Source Project |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License |
| 15 | */ |
| 16 | |
| 17 | package com.android.contacts.activities; |
| 18 | |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 19 | import com.android.contacts.ContactLoader; |
Dmitri Plotnikov | 18ffaa2 | 2010-12-03 14:28:00 -0800 | [diff] [blame] | 20 | import com.android.contacts.ContactSaveService; |
Dmitri Plotnikov | 6f667b5 | 2011-01-09 12:53:13 -0800 | [diff] [blame] | 21 | import com.android.contacts.ContactsActivity; |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 22 | import com.android.contacts.ContactsSearchManager; |
| 23 | import com.android.contacts.R; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 24 | import com.android.contacts.detail.ContactDetailAboutFragment; |
Dmitri Plotnikov | 18ffaa2 | 2010-12-03 14:28:00 -0800 | [diff] [blame] | 25 | import com.android.contacts.detail.ContactDetailFragment; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 26 | import com.android.contacts.detail.ContactDetailHeaderView; |
| 27 | import com.android.contacts.detail.ContactDetailTabCarousel; |
| 28 | import com.android.contacts.detail.ContactDetailUpdatesFragment; |
Daniel Lehmann | 69e7fec | 2010-07-20 14:14:56 -0700 | [diff] [blame] | 29 | import com.android.contacts.interactions.ContactDeletionInteraction; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 30 | import com.android.contacts.list.ContactBrowseListFragment; |
Daniel Lehmann | c90c705 | 2011-03-16 18:42:34 -0700 | [diff] [blame] | 31 | import com.android.contacts.util.PhoneCapabilityTester; |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 32 | |
Dmitri Plotnikov | caf0bc7 | 2010-09-03 15:16:21 -0700 | [diff] [blame] | 33 | import android.accounts.Account; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 34 | import android.app.Fragment; |
| 35 | import android.app.FragmentManager; |
Daniel Lehmann | 60be1a1 | 2010-08-05 18:37:21 -0700 | [diff] [blame] | 36 | import android.content.ActivityNotFoundException; |
Dmitri Plotnikov | caf0bc7 | 2010-09-03 15:16:21 -0700 | [diff] [blame] | 37 | import android.content.ContentValues; |
Daniel Lehmann | 18f104f | 2010-05-07 15:41:11 -0700 | [diff] [blame] | 38 | import android.content.Intent; |
Daniel Lehmann | c2687c3 | 2010-04-19 18:20:44 -0700 | [diff] [blame] | 39 | import android.net.Uri; |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 40 | import android.os.Bundle; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 41 | import android.support.v13.app.FragmentPagerAdapter; |
| 42 | import android.support.v4.view.ViewPager; |
| 43 | import android.support.v4.view.ViewPager.OnPageChangeListener; |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 44 | import android.util.Log; |
| 45 | import android.view.KeyEvent; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 46 | import android.view.MotionEvent; |
| 47 | import android.view.View; |
| 48 | import android.view.View.OnTouchListener; |
Dmitri Plotnikov | caf0bc7 | 2010-09-03 15:16:21 -0700 | [diff] [blame] | 49 | import android.widget.Toast; |
| 50 | |
| 51 | import java.util.ArrayList; |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 52 | |
Dmitri Plotnikov | 6f667b5 | 2011-01-09 12:53:13 -0800 | [diff] [blame] | 53 | public class ContactDetailActivity extends ContactsActivity { |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 54 | private static final String TAG = "ContactDetailActivity"; |
| 55 | |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 56 | public static final int FRAGMENT_COUNT = 2; |
| 57 | |
| 58 | private ContactDetailAboutFragment mAboutFragment; |
| 59 | private ContactDetailUpdatesFragment mUpdatesFragment; |
| 60 | |
| 61 | private ContactDetailTabCarousel mTabCarousel; |
| 62 | private ViewPager mViewPager; |
| 63 | |
| 64 | private Uri mUri; |
Daniel Lehmann | 25a0282 | 2010-05-11 15:52:43 -0700 | [diff] [blame] | 65 | |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 66 | @Override |
| 67 | public void onCreate(Bundle savedState) { |
| 68 | super.onCreate(savedState); |
| 69 | |
Daniel Lehmann | c90c705 | 2011-03-16 18:42:34 -0700 | [diff] [blame] | 70 | if (PhoneCapabilityTester.isUsingTwoPanes(this)) { |
| 71 | // This activity must not be shown. We have to select the contact in the |
Dave Santoro | 5e684a4 | 2011-06-10 13:23:35 -0700 | [diff] [blame] | 72 | // PeopleActivity instead ==> Create a forward intent and finish |
Daniel Lehmann | c90c705 | 2011-03-16 18:42:34 -0700 | [diff] [blame] | 73 | final Intent originalIntent = getIntent(); |
| 74 | Intent intent = new Intent(); |
| 75 | intent.setAction(originalIntent.getAction()); |
| 76 | intent.setDataAndType(originalIntent.getData(), originalIntent.getType()); |
| 77 | intent.setFlags( |
| 78 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_FORWARD_RESULT |
| 79 | | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); |
| 80 | |
Katherine Kuan | 9856fce | 2011-06-01 10:24:09 -0700 | [diff] [blame] | 81 | intent.setClass(this, PeopleActivity.class); |
Daniel Lehmann | c90c705 | 2011-03-16 18:42:34 -0700 | [diff] [blame] | 82 | startActivity(intent); |
| 83 | finish(); |
| 84 | return; |
| 85 | } |
| 86 | |
Daniel Lehmann | 25a0282 | 2010-05-11 15:52:43 -0700 | [diff] [blame] | 87 | setContentView(R.layout.contact_detail_activity); |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 88 | |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 89 | mViewPager = (ViewPager) findViewById(R.id.pager); |
| 90 | mViewPager.setAdapter(new ViewPagerAdapter(getFragmentManager())); |
| 91 | mViewPager.setOnPageChangeListener(mOnPageChangeListener); |
Daniel Lehmann | cdef2b6 | 2010-06-06 18:25:49 -0700 | [diff] [blame] | 92 | |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 93 | mTabCarousel = (ContactDetailTabCarousel) findViewById(R.id.tab_carousel); |
| 94 | mTabCarousel.setListener(mTabCarouselListener); |
| 95 | |
| 96 | mUri = getIntent().getData(); |
Daniel Lehmann | cdef2b6 | 2010-06-06 18:25:49 -0700 | [diff] [blame] | 97 | Log.i(TAG, getIntent().getData().toString()); |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 98 | } |
| 99 | |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 100 | |
| 101 | @Override |
| 102 | public void onAttachFragment(Fragment fragment) { |
| 103 | if (fragment instanceof ContactDetailAboutFragment) { |
| 104 | mAboutFragment = (ContactDetailAboutFragment) fragment; |
| 105 | mAboutFragment.setListener(mFragmentListener); |
| 106 | mAboutFragment.loadUri(mUri); |
| 107 | } else if (fragment instanceof ContactDetailUpdatesFragment) { |
| 108 | mUpdatesFragment = (ContactDetailUpdatesFragment) fragment; |
| 109 | } |
| 110 | } |
| 111 | |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 112 | @Override |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 113 | public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData, |
| 114 | boolean globalSearch) { |
| 115 | if (globalSearch) { |
| 116 | super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch); |
| 117 | } else { |
| 118 | ContactsSearchManager.startSearch(this, initialQuery); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | @Override |
| 123 | public boolean onKeyDown(int keyCode, KeyEvent event) { |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 124 | FragmentKeyListener mCurrentFragment; |
| 125 | switch (mViewPager.getCurrentItem()) { |
| 126 | case 0: |
| 127 | mCurrentFragment = (FragmentKeyListener) mAboutFragment; |
| 128 | break; |
| 129 | case 1: |
| 130 | mCurrentFragment = (FragmentKeyListener) mUpdatesFragment; |
| 131 | break; |
| 132 | default: |
| 133 | throw new IllegalStateException("Invalid current item for ViewPager"); |
| 134 | } |
| 135 | if (mCurrentFragment.handleKeyDown(keyCode)) return true; |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 136 | |
| 137 | return super.onKeyDown(keyCode, event); |
| 138 | } |
Daniel Lehmann | 18f104f | 2010-05-07 15:41:11 -0700 | [diff] [blame] | 139 | |
Daniel Lehmann | cdef2b6 | 2010-06-06 18:25:49 -0700 | [diff] [blame] | 140 | private final ContactDetailFragment.Listener mFragmentListener = |
| 141 | new ContactDetailFragment.Listener() { |
Daniel Lehmann | 69e7fec | 2010-07-20 14:14:56 -0700 | [diff] [blame] | 142 | @Override |
Daniel Lehmann | cdef2b6 | 2010-06-06 18:25:49 -0700 | [diff] [blame] | 143 | public void onContactNotFound() { |
Daniel Lehmann | 18f104f | 2010-05-07 15:41:11 -0700 | [diff] [blame] | 144 | finish(); |
| 145 | } |
| 146 | |
Daniel Lehmann | 69e7fec | 2010-07-20 14:14:56 -0700 | [diff] [blame] | 147 | @Override |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 148 | public void onDetailsLoaded(ContactLoader.Result result) { |
| 149 | mTabCarousel.loadData(result); |
| 150 | } |
| 151 | |
| 152 | @Override |
Daniel Lehmann | 825cb62 | 2010-08-27 11:44:29 -0700 | [diff] [blame] | 153 | public void onEditRequested(Uri contactLookupUri) { |
| 154 | startActivity(new Intent(Intent.ACTION_EDIT, contactLookupUri)); |
Daniel Lehmann | 18f104f | 2010-05-07 15:41:11 -0700 | [diff] [blame] | 155 | } |
| 156 | |
Daniel Lehmann | 69e7fec | 2010-07-20 14:14:56 -0700 | [diff] [blame] | 157 | @Override |
Daniel Lehmann | cdef2b6 | 2010-06-06 18:25:49 -0700 | [diff] [blame] | 158 | public void onItemClicked(Intent intent) { |
Daniel Lehmann | 60be1a1 | 2010-08-05 18:37:21 -0700 | [diff] [blame] | 159 | try { |
| 160 | startActivity(intent); |
| 161 | } catch (ActivityNotFoundException e) { |
| 162 | Log.e(TAG, "No activity found for intent: " + intent); |
| 163 | } |
Daniel Lehmann | 18f104f | 2010-05-07 15:41:11 -0700 | [diff] [blame] | 164 | } |
Daniel Lehmann | cdef2b6 | 2010-06-06 18:25:49 -0700 | [diff] [blame] | 165 | |
Daniel Lehmann | 69e7fec | 2010-07-20 14:14:56 -0700 | [diff] [blame] | 166 | @Override |
Dmitri Plotnikov | 66bca8f | 2010-11-24 16:59:24 -0800 | [diff] [blame] | 167 | public void onDeleteRequested(Uri contactUri) { |
Dmitri Plotnikov | c9eda37 | 2011-02-23 08:58:13 -0800 | [diff] [blame] | 168 | ContactDeletionInteraction.start(ContactDetailActivity.this, contactUri, true); |
Daniel Lehmann | cdef2b6 | 2010-06-06 18:25:49 -0700 | [diff] [blame] | 169 | } |
Dmitri Plotnikov | caf0bc7 | 2010-09-03 15:16:21 -0700 | [diff] [blame] | 170 | |
| 171 | @Override |
| 172 | public void onCreateRawContactRequested( |
| 173 | ArrayList<ContentValues> values, Account account) { |
| 174 | Toast.makeText(ContactDetailActivity.this, R.string.toast_making_personal_copy, |
| 175 | Toast.LENGTH_LONG).show(); |
| 176 | Intent serviceIntent = ContactSaveService.createNewRawContactIntent( |
Dmitri Plotnikov | 9d730dd | 2010-11-24 13:22:23 -0800 | [diff] [blame] | 177 | ContactDetailActivity.this, values, account, |
| 178 | ContactDetailActivity.class, Intent.ACTION_VIEW); |
Dmitri Plotnikov | caf0bc7 | 2010-09-03 15:16:21 -0700 | [diff] [blame] | 179 | startService(serviceIntent); |
| 180 | |
| 181 | } |
Daniel Lehmann | cdef2b6 | 2010-06-06 18:25:49 -0700 | [diff] [blame] | 182 | }; |
Katherine Kuan | 7970088 | 2011-06-14 17:40:33 -0700 | [diff] [blame^] | 183 | |
| 184 | public class ViewPagerAdapter extends FragmentPagerAdapter{ |
| 185 | |
| 186 | public ViewPagerAdapter(FragmentManager fm) { |
| 187 | super(fm); |
| 188 | } |
| 189 | |
| 190 | @Override |
| 191 | public Fragment getItem(int position) { |
| 192 | switch (position) { |
| 193 | case 0: |
| 194 | return new ContactDetailAboutFragment(); |
| 195 | case 1: |
| 196 | return new ContactDetailUpdatesFragment(); |
| 197 | } |
| 198 | throw new IllegalStateException("No fragment at position " + position); |
| 199 | } |
| 200 | |
| 201 | @Override |
| 202 | public int getCount() { |
| 203 | return FRAGMENT_COUNT; |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | private OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener() { |
| 208 | |
| 209 | @Override |
| 210 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { |
| 211 | // The user is horizontally dragging the {@link ViewPager}, so send |
| 212 | // these scroll changes to the tab carousel. Ignore these events though if the carousel |
| 213 | // is actually controlling the {@link ViewPager} scrolls because it will already be |
| 214 | // in the correct position. |
| 215 | if (mViewPager.isFakeDragging()) { |
| 216 | return; |
| 217 | } |
| 218 | int x = (int) ((position + positionOffset) * mTabCarousel.getAllowedScrollLength()); |
| 219 | mTabCarousel.scrollTo(x, 0); |
| 220 | } |
| 221 | |
| 222 | @Override |
| 223 | public void onPageSelected(int position) { |
| 224 | // Since a new page has been selected by the {@link ViewPager}, |
| 225 | // update the tab selection in the carousel. |
| 226 | mTabCarousel.setCurrentTab(position); |
| 227 | } |
| 228 | |
| 229 | @Override |
| 230 | public void onPageScrollStateChanged(int state) {} |
| 231 | |
| 232 | }; |
| 233 | |
| 234 | private ContactDetailTabCarousel.Listener mTabCarouselListener = |
| 235 | new ContactDetailTabCarousel.Listener() { |
| 236 | |
| 237 | @Override |
| 238 | public void onTouchDown() { |
| 239 | // The user just started scrolling the carousel, so begin "fake dragging" the |
| 240 | // {@link ViewPager} if it's not already doing so. |
| 241 | if (mViewPager.isFakeDragging()) { |
| 242 | return; |
| 243 | } |
| 244 | mViewPager.beginFakeDrag(); |
| 245 | } |
| 246 | |
| 247 | @Override |
| 248 | public void onTouchUp() { |
| 249 | // The user just stopped scrolling the carousel, so stop "fake dragging" the |
| 250 | // {@link ViewPager} if was doing so before. |
| 251 | if (mViewPager.isFakeDragging()) { |
| 252 | mViewPager.endFakeDrag(); |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | @Override |
| 257 | public void onScrollChanged(int l, int t, int oldl, int oldt) { |
| 258 | // The user is scrolling the carousel, so send the scroll deltas to the |
| 259 | // {@link ViewPager} so it can move in sync. |
| 260 | if (mViewPager.isFakeDragging()) { |
| 261 | mViewPager.fakeDragBy(oldl-l); |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | @Override |
| 266 | public void onTabSelected(int position) { |
| 267 | // The user selected a tab, so update the {@link ViewPager} |
| 268 | mViewPager.setCurrentItem(position); |
| 269 | } |
| 270 | }; |
| 271 | |
| 272 | /** |
| 273 | * This interface should be implemented by {@link Fragment}s within this |
| 274 | * activity so that the activity can determine whether the currently |
| 275 | * displayed view is handling the key event or not. |
| 276 | */ |
| 277 | public interface FragmentKeyListener { |
| 278 | /** |
| 279 | * Returns true if the key down event will be handled by the implementing class, or false |
| 280 | * otherwise. |
| 281 | */ |
| 282 | public boolean handleKeyDown(int keyCode); |
| 283 | } |
Daniel Lehmann | 4cd9441 | 2010-04-08 16:44:36 -0700 | [diff] [blame] | 284 | } |