Home | History | Annotate | Download | only in activities
      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 
     17 package com.android.contacts.activities;
     18 
     19 import com.android.contacts.ContactLoader;
     20 import com.android.contacts.ContactSaveService;
     21 import com.android.contacts.ContactsActivity;
     22 import com.android.contacts.R;
     23 import com.android.contacts.detail.ContactDetailDisplayUtils;
     24 import com.android.contacts.detail.ContactDetailFragment;
     25 import com.android.contacts.detail.ContactDetailLayoutController;
     26 import com.android.contacts.detail.ContactLoaderFragment;
     27 import com.android.contacts.detail.ContactLoaderFragment.ContactLoaderFragmentListener;
     28 import com.android.contacts.interactions.ContactDeletionInteraction;
     29 import com.android.contacts.model.AccountWithDataSet;
     30 import com.android.contacts.util.PhoneCapabilityTester;
     31 
     32 import android.app.ActionBar;
     33 import android.app.Fragment;
     34 import android.content.ActivityNotFoundException;
     35 import android.content.ContentValues;
     36 import android.content.Intent;
     37 import android.net.Uri;
     38 import android.os.Bundle;
     39 import android.os.Handler;
     40 import android.text.TextUtils;
     41 import android.util.Log;
     42 import android.view.KeyEvent;
     43 import android.view.Menu;
     44 import android.view.MenuInflater;
     45 import android.view.MenuItem;
     46 import android.view.View;
     47 import android.view.View.OnClickListener;
     48 import android.view.ViewGroup;
     49 import android.view.accessibility.AccessibilityEvent;
     50 import android.view.accessibility.AccessibilityManager;
     51 import android.widget.CheckBox;
     52 import android.widget.Toast;
     53 
     54 import java.util.ArrayList;
     55 
     56 public 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