ContactDetailActivity.java revision 5c3a0a1440625fab859aab420cb08bc0276358a0
1/* 2 * Copyright (C) 2010 The Android Open Source Project 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 17package com.android.contacts.activities; 18 19import com.android.contacts.ContactLoader; 20import com.android.contacts.ContactSaveService; 21import com.android.contacts.ContactsActivity; 22import com.android.contacts.R; 23import com.android.contacts.detail.ContactDetailDisplayUtils; 24import com.android.contacts.detail.ContactDetailFragment; 25import com.android.contacts.detail.ContactDetailLayoutController; 26import com.android.contacts.detail.ContactLoaderFragment; 27import com.android.contacts.detail.ContactLoaderFragment.ContactLoaderFragmentListener; 28import com.android.contacts.interactions.ContactDeletionInteraction; 29import com.android.contacts.model.AccountWithDataSet; 30import com.android.contacts.util.PhoneCapabilityTester; 31 32import android.app.ActionBar; 33import android.app.Fragment; 34import android.content.ActivityNotFoundException; 35import android.content.ContentValues; 36import android.content.Intent; 37import android.net.Uri; 38import android.os.Bundle; 39import android.os.Handler; 40import android.text.TextUtils; 41import android.util.Log; 42import android.view.KeyEvent; 43import android.view.Menu; 44import android.view.MenuInflater; 45import android.view.MenuItem; 46import android.view.View; 47import android.view.View.OnClickListener; 48import android.view.ViewGroup; 49import android.view.accessibility.AccessibilityEvent; 50import android.view.accessibility.AccessibilityManager; 51import android.widget.CheckBox; 52import android.widget.Toast; 53 54import java.util.ArrayList; 55 56public class ContactDetailActivity extends ContactsActivity { 57 private static final String TAG = "ContactDetailActivity"; 58 59 /** 60 * Boolean intent key that specifies whether pressing the "up" affordance in this activity 61 * should cause it to finish itself or launch an intent to bring the user back to a specific 62 * parent activity - the {@link PeopleActivity}. 63 */ 64 public static final String INTENT_KEY_FINISH_ACTIVITY_ON_UP_SELECTED = 65 "finishActivityOnUpSelected"; 66 67 private ContactLoader.Result mContactData; 68 private Uri mLookupUri; 69 private boolean mFinishActivityOnUpSelected; 70 71 private ContactDetailLayoutController mContactDetailLayoutController; 72 private ContactLoaderFragment mLoaderFragment; 73 74 private Handler mHandler = new Handler(); 75 76 @Override 77 public void onCreate(Bundle savedState) { 78 super.onCreate(savedState); 79 if (PhoneCapabilityTester.isUsingTwoPanes(this)) { 80 // This activity must not be shown. We have to select the contact in the 81 // PeopleActivity instead ==> Create a forward intent and finish 82 final Intent originalIntent = getIntent(); 83 Intent intent = new Intent(); 84 intent.setAction(originalIntent.getAction()); 85 intent.setDataAndType(originalIntent.getData(), originalIntent.getType()); 86 intent.setFlags( 87 Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_FORWARD_RESULT 88 | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); 89 90 intent.setClass(this, PeopleActivity.class); 91 startActivity(intent); 92 finish(); 93 return; 94 } 95 96 mFinishActivityOnUpSelected = getIntent().getBooleanExtra( 97 INTENT_KEY_FINISH_ACTIVITY_ON_UP_SELECTED, false); 98 99 setContentView(R.layout.contact_detail_activity); 100 101 mContactDetailLayoutController = new ContactDetailLayoutController(this, savedState, 102 getFragmentManager(), findViewById(R.id.contact_detail_container), 103 mContactDetailFragmentListener); 104 105 // We want the UP affordance but no app icon. 106 // Setting HOME_AS_UP, SHOW_TITLE and clearing SHOW_HOME does the trick. 107 ActionBar actionBar = getActionBar(); 108 if (actionBar != null) { 109 actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE, 110 ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE 111 | ActionBar.DISPLAY_SHOW_HOME); 112 actionBar.setTitle(""); 113 } 114 115 Log.i(TAG, getIntent().getData().toString()); 116 } 117 118 @Override 119 public void onAttachFragment(Fragment fragment) { 120 if (fragment instanceof ContactLoaderFragment) { 121 mLoaderFragment = (ContactLoaderFragment) fragment; 122 mLoaderFragment.setListener(mLoaderFragmentListener); 123 mLoaderFragment.loadUri(getIntent().getData()); 124 } 125 } 126 127 @Override 128 public boolean onCreateOptionsMenu(Menu menu) { 129 super.onCreateOptionsMenu(menu); 130 MenuInflater inflater = getMenuInflater(); 131 inflater.inflate(R.menu.star, menu); 132 return true; 133 } 134 135 @Override 136 public boolean onPrepareOptionsMenu(Menu menu) { 137 MenuItem starredMenuItem = menu.findItem(R.id.menu_star); 138 ViewGroup starredContainer = (ViewGroup) getLayoutInflater().inflate( 139 R.layout.favorites_star, null, false); 140 final CheckBox starredView = (CheckBox) starredContainer.findViewById(R.id.star); 141 starredView.setOnClickListener(new OnClickListener() { 142 @Override 143 public void onClick(View v) { 144 // Toggle "starred" state 145 // Make sure there is a contact 146 if (mLookupUri != null) { 147 Intent intent = ContactSaveService.createSetStarredIntent( 148 ContactDetailActivity.this, mLookupUri, starredView.isChecked()); 149 ContactDetailActivity.this.startService(intent); 150 } 151 } 152 }); 153 // If there is contact data, update the starred state 154 if (mContactData != null) { 155 ContactDetailDisplayUtils.setStarred(mContactData, starredView); 156 } 157 starredMenuItem.setActionView(starredContainer); 158 return true; 159 } 160 161 @Override 162 public boolean onKeyDown(int keyCode, KeyEvent event) { 163 // First check if the {@link ContactLoaderFragment} can handle the key 164 if (mLoaderFragment != null && mLoaderFragment.handleKeyDown(keyCode)) return true; 165 166 // Otherwise find the correct fragment to handle the event 167 FragmentKeyListener mCurrentFragment = mContactDetailLayoutController.getCurrentPage(); 168 if (mCurrentFragment != null && mCurrentFragment.handleKeyDown(keyCode)) return true; 169 170 // In the last case, give the key event to the superclass. 171 return super.onKeyDown(keyCode, event); 172 } 173 174 @Override 175 protected void onSaveInstanceState(Bundle outState) { 176 super.onSaveInstanceState(outState); 177 if (mContactDetailLayoutController != null) { 178 mContactDetailLayoutController.onSaveInstanceState(outState); 179 } 180 } 181 182 private final ContactLoaderFragmentListener mLoaderFragmentListener = 183 new ContactLoaderFragmentListener() { 184 @Override 185 public void onContactNotFound() { 186 finish(); 187 } 188 189 @Override 190 public void onDetailsLoaded(final ContactLoader.Result result) { 191 if (result == null) { 192 return; 193 } 194 // Since {@link FragmentTransaction}s cannot be done in the onLoadFinished() of the 195 // {@link LoaderCallbacks}, then post this {@link Runnable} to the {@link Handler} 196 // on the main thread to execute later. 197 mHandler.post(new Runnable() { 198 @Override 199 public void run() { 200 // If the activity is destroyed (or will be destroyed soon), don't update the UI 201 if (isFinishing()) { 202 return; 203 } 204 mContactData = result; 205 mLookupUri = result.getLookupUri(); 206 invalidateOptionsMenu(); 207 setupTitle(); 208 mContactDetailLayoutController.setContactData(mContactData); 209 } 210 }); 211 } 212 213 @Override 214 public void onEditRequested(Uri contactLookupUri) { 215 Intent intent = new Intent(Intent.ACTION_EDIT, contactLookupUri); 216 intent.putExtra( 217 ContactEditorActivity.INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED, true); 218 // Don't finish the detail activity after launching the editor because when the 219 // editor is done, we will still want to show the updated contact details using 220 // this activity. 221 startActivity(intent); 222 } 223 224 @Override 225 public void onDeleteRequested(Uri contactUri) { 226 ContactDeletionInteraction.start(ContactDetailActivity.this, contactUri, true); 227 } 228 }; 229 230 /** 231 * Setup the activity title and subtitle with contact name and company. 232 */ 233 private void setupTitle() { 234 CharSequence displayName = ContactDetailDisplayUtils.getDisplayName(this, mContactData); 235 String company = ContactDetailDisplayUtils.getCompany(this, mContactData); 236 237 ActionBar actionBar = getActionBar(); 238 actionBar.setTitle(displayName); 239 actionBar.setSubtitle(company); 240 241 if (!TextUtils.isEmpty(displayName) && 242 AccessibilityManager.getInstance(this).isEnabled()) { 243 View decorView = getWindow().getDecorView(); 244 decorView.setContentDescription(displayName); 245 decorView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 246 } 247 } 248 249 private final ContactDetailFragment.Listener mContactDetailFragmentListener = 250 new ContactDetailFragment.Listener() { 251 @Override 252 public void onItemClicked(Intent intent) { 253 if (intent == null) { 254 return; 255 } 256 try { 257 startActivity(intent); 258 } catch (ActivityNotFoundException e) { 259 Log.e(TAG, "No activity found for intent: " + intent); 260 } 261 } 262 263 @Override 264 public void onCreateRawContactRequested( 265 ArrayList<ContentValues> values, AccountWithDataSet account) { 266 Toast.makeText(ContactDetailActivity.this, R.string.toast_making_personal_copy, 267 Toast.LENGTH_LONG).show(); 268 Intent serviceIntent = ContactSaveService.createNewRawContactIntent( 269 ContactDetailActivity.this, values, account, 270 ContactDetailActivity.class, Intent.ACTION_VIEW); 271 startService(serviceIntent); 272 273 } 274 }; 275 276 /** 277 * This interface should be implemented by {@link Fragment}s within this 278 * activity so that the activity can determine whether the currently 279 * displayed view is handling the key event or not. 280 */ 281 public interface FragmentKeyListener { 282 /** 283 * Returns true if the key down event will be handled by the implementing class, or false 284 * otherwise. 285 */ 286 public boolean handleKeyDown(int keyCode); 287 } 288 289 @Override 290 public boolean onOptionsItemSelected(MenuItem item) { 291 292 switch (item.getItemId()) { 293 case android.R.id.home: 294 if (mFinishActivityOnUpSelected) { 295 finish(); 296 return true; 297 } 298 Intent intent = new Intent(this, PeopleActivity.class); 299 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 300 startActivity(intent); 301 finish(); 302 return true; 303 default: 304 break; 305 } 306 return super.onOptionsItemSelected(item); 307 } 308} 309