Home | History | Annotate | Download | only in contacts
      1 /*
      2  * Copyright (C) 2008 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;
     18 
     19 import com.android.internal.telephony.ITelephony;
     20 
     21 import android.app.Activity;
     22 import android.app.TabActivity;
     23 import android.content.Intent;
     24 import android.content.SharedPreferences;
     25 import android.net.Uri;
     26 import android.os.Bundle;
     27 import android.os.RemoteException;
     28 import android.os.ServiceManager;
     29 import android.provider.CallLog.Calls;
     30 import android.provider.ContactsContract.Intents.UI;
     31 import android.util.Log;
     32 import android.view.Window;
     33 import android.widget.TabHost;
     34 
     35 /**
     36  * The dialer activity that has one tab with the virtual 12key
     37  * dialer, a tab with recent calls in it, a tab with the contacts and
     38  * a tab with the favorite. This is the container and the tabs are
     39  * embedded using intents.
     40  * The dialer tab's title is 'phone', a more common name (see strings.xml).
     41  */
     42 public class DialtactsActivity extends TabActivity implements TabHost.OnTabChangeListener {
     43     private static final String TAG = "Dailtacts";
     44     private static final String FAVORITES_ENTRY_COMPONENT =
     45             "com.android.contacts.DialtactsFavoritesEntryActivity";
     46 
     47     /** Opens the Contacts app in the state the user has last set it to */
     48     private static final String CONTACTS_LAUNCH_ACTIVITY =
     49             "com.android.contacts.ContactsLaunchActivity";
     50 
     51     private static final int TAB_INDEX_DIALER = 0;
     52     private static final int TAB_INDEX_CALL_LOG = 1;
     53     private static final int TAB_INDEX_CONTACTS = 2;
     54     private static final int TAB_INDEX_FAVORITES = 3;
     55 
     56     static final String EXTRA_IGNORE_STATE = "ignore-state";
     57 
     58     /** Name of the dialtacts shared preferences */
     59     static final String PREFS_DIALTACTS = "dialtacts";
     60     /** If true, when handling the contacts intent the favorites tab will be shown instead */
     61     static final String PREF_FAVORITES_AS_CONTACTS = "favorites_as_contacts";
     62     static final boolean PREF_FAVORITES_AS_CONTACTS_DEFAULT = false;
     63 
     64     /** Last manually selected tab index */
     65     private static final String PREF_LAST_MANUALLY_SELECTED_TAB = "last_manually_selected_tab";
     66     private static final int PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT = TAB_INDEX_DIALER;
     67 
     68     private TabHost mTabHost;
     69     private String mFilterText;
     70     private Uri mDialUri;
     71 
     72     /**
     73      * The index of the tab that has last been manually selected (the user clicked on a tab).
     74      * This value does not keep track of programmatically set Tabs (e.g. Call Log after a Call)
     75      */
     76     private int mLastManuallySelectedTab;
     77 
     78     @Override
     79     protected void onCreate(Bundle icicle) {
     80         super.onCreate(icicle);
     81 
     82         final Intent intent = getIntent();
     83         fixIntent(intent);
     84 
     85         requestWindowFeature(Window.FEATURE_NO_TITLE);
     86         setContentView(R.layout.dialer_activity);
     87 
     88         mTabHost = getTabHost();
     89         mTabHost.setOnTabChangedListener(this);
     90 
     91         // Setup the tabs
     92         setupDialerTab();
     93         setupCallLogTab();
     94         setupContactsTab();
     95         setupFavoritesTab();
     96 
     97         // Load the last manually loaded tab
     98         final SharedPreferences prefs = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE);
     99         mLastManuallySelectedTab = prefs.getInt(PREF_LAST_MANUALLY_SELECTED_TAB,
    100                 PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT);
    101 
    102         setCurrentTab(intent);
    103 
    104         if (intent.getAction().equals(UI.FILTER_CONTACTS_ACTION)
    105                 && icicle == null) {
    106             setupFilterText(intent);
    107         }
    108     }
    109 
    110     @Override
    111     protected void onPause() {
    112         super.onPause();
    113 
    114         final int currentTabIndex = mTabHost.getCurrentTab();
    115         final SharedPreferences.Editor editor =
    116                 getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE).edit();
    117         if (currentTabIndex == TAB_INDEX_CONTACTS || currentTabIndex == TAB_INDEX_FAVORITES) {
    118             editor.putBoolean(PREF_FAVORITES_AS_CONTACTS, currentTabIndex == TAB_INDEX_FAVORITES);
    119         }
    120         editor.putInt(PREF_LAST_MANUALLY_SELECTED_TAB, mLastManuallySelectedTab);
    121 
    122         editor.commit();
    123     }
    124 
    125     private void fixIntent(Intent intent) {
    126         // This should be cleaned up: the call key used to send an Intent
    127         // that just said to go to the recent calls list.  It now sends this
    128         // abstract action, but this class hasn't been rewritten to deal with it.
    129         if (Intent.ACTION_CALL_BUTTON.equals(intent.getAction())) {
    130             intent.setDataAndType(Calls.CONTENT_URI, Calls.CONTENT_TYPE);
    131             intent.putExtra("call_key", true);
    132             setIntent(intent);
    133         }
    134     }
    135 
    136     private void setupCallLogTab() {
    137         // Force the class since overriding tab entries doesn't work
    138         Intent intent = new Intent("com.android.phone.action.RECENT_CALLS");
    139         intent.setClass(this, RecentCallsListActivity.class);
    140 
    141         mTabHost.addTab(mTabHost.newTabSpec("call_log")
    142                 .setIndicator(getString(R.string.recentCallsIconLabel),
    143                         getResources().getDrawable(R.drawable.ic_tab_recent))
    144                 .setContent(intent));
    145     }
    146 
    147     private void setupDialerTab() {
    148         Intent intent = new Intent("com.android.phone.action.TOUCH_DIALER");
    149         intent.setClass(this, TwelveKeyDialer.class);
    150 
    151         mTabHost.addTab(mTabHost.newTabSpec("dialer")
    152                 .setIndicator(getString(R.string.dialerIconLabel),
    153                         getResources().getDrawable(R.drawable.ic_tab_dialer))
    154                 .setContent(intent));
    155     }
    156 
    157     private void setupContactsTab() {
    158         Intent intent = new Intent(UI.LIST_DEFAULT);
    159         intent.setClass(this, ContactsListActivity.class);
    160 
    161         mTabHost.addTab(mTabHost.newTabSpec("contacts")
    162                 .setIndicator(getText(R.string.contactsIconLabel),
    163                         getResources().getDrawable(R.drawable.ic_tab_contacts))
    164                 .setContent(intent));
    165     }
    166 
    167     private void setupFavoritesTab() {
    168         Intent intent = new Intent(UI.LIST_STREQUENT_ACTION);
    169         intent.setClass(this, ContactsListActivity.class);
    170 
    171         mTabHost.addTab(mTabHost.newTabSpec("favorites")
    172                 .setIndicator(getString(R.string.contactsFavoritesLabel),
    173                         getResources().getDrawable(R.drawable.ic_tab_starred))
    174                 .setContent(intent));
    175     }
    176 
    177     /**
    178      * Returns true if the intent is due to hitting the green send key while in a call.
    179      *
    180      * @param intent the intent that launched this activity
    181      * @param recentCallsRequest true if the intent is requesting to view recent calls
    182      * @return true if the intent is due to hitting the green send key while in a call
    183      */
    184     private boolean isSendKeyWhileInCall(final Intent intent, final boolean recentCallsRequest) {
    185         // If there is a call in progress go to the call screen
    186         if (recentCallsRequest) {
    187             final boolean callKey = intent.getBooleanExtra("call_key", false);
    188 
    189             try {
    190                 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
    191                 if (callKey && phone != null && phone.showCallScreen()) {
    192                     return true;
    193                 }
    194             } catch (RemoteException e) {
    195                 Log.e(TAG, "Failed to handle send while in call", e);
    196             }
    197         }
    198 
    199         return false;
    200     }
    201 
    202     /**
    203      * Sets the current tab based on the intent's request type
    204      *
    205      * @param intent Intent that contains information about which tab should be selected
    206      */
    207     private void setCurrentTab(Intent intent) {
    208         // If we got here by hitting send and we're in call forward along to the in-call activity
    209         final boolean recentCallsRequest = Calls.CONTENT_TYPE.equals(intent.getType());
    210         if (isSendKeyWhileInCall(intent, recentCallsRequest)) {
    211             finish();
    212             return;
    213         }
    214 
    215         // Dismiss menu provided by any children activities
    216         Activity activity = getLocalActivityManager().
    217                 getActivity(mTabHost.getCurrentTabTag());
    218         if (activity != null) {
    219             activity.closeOptionsMenu();
    220         }
    221 
    222         // Tell the children activities that they should ignore any possible saved
    223         // state and instead reload their state from the parent's intent
    224         intent.putExtra(EXTRA_IGNORE_STATE, true);
    225 
    226         // Remember the old manually selected tab index so that it can be restored if it is
    227         // overwritten by one of the programmatic tab selections
    228         final int savedTabIndex = mLastManuallySelectedTab;
    229 
    230         // Choose the tab based on the inbound intent
    231         String componentName = intent.getComponent().getClassName();
    232         if (getClass().getName().equals(componentName)) {
    233             if (recentCallsRequest) {
    234                 mTabHost.setCurrentTab(TAB_INDEX_CALL_LOG);
    235             } else {
    236                 mTabHost.setCurrentTab(TAB_INDEX_DIALER);
    237             }
    238         } else if (FAVORITES_ENTRY_COMPONENT.equals(componentName)) {
    239             mTabHost.setCurrentTab(TAB_INDEX_FAVORITES);
    240         } else if (CONTACTS_LAUNCH_ACTIVITY.equals(componentName)) {
    241             mTabHost.setCurrentTab(mLastManuallySelectedTab);
    242         } else {
    243             SharedPreferences prefs = getSharedPreferences(PREFS_DIALTACTS, MODE_PRIVATE);
    244             boolean favoritesAsContacts = prefs.getBoolean(PREF_FAVORITES_AS_CONTACTS,
    245                     PREF_FAVORITES_AS_CONTACTS_DEFAULT);
    246             if (favoritesAsContacts) {
    247                 mTabHost.setCurrentTab(TAB_INDEX_FAVORITES);
    248             } else {
    249                 mTabHost.setCurrentTab(TAB_INDEX_CONTACTS);
    250             }
    251         }
    252 
    253         // Restore to the previous manual selection
    254         mLastManuallySelectedTab = savedTabIndex;
    255 
    256         // Tell the children activities that they should honor their saved states
    257         // instead of the state from the parent's intent
    258         intent.putExtra(EXTRA_IGNORE_STATE, false);
    259     }
    260 
    261     @Override
    262     public void onNewIntent(Intent newIntent) {
    263         setIntent(newIntent);
    264         fixIntent(newIntent);
    265         setCurrentTab(newIntent);
    266         final String action = newIntent.getAction();
    267         if (action.equals(UI.FILTER_CONTACTS_ACTION)) {
    268             setupFilterText(newIntent);
    269         } else if (isDialIntent(newIntent)) {
    270             setupDialUri(newIntent);
    271         }
    272     }
    273 
    274     /** Returns true if the given intent contains a phone number to populate the dialer with */
    275     private boolean isDialIntent(Intent intent) {
    276         final String action = intent.getAction();
    277         if (Intent.ACTION_DIAL.equals(action)) {
    278             return true;
    279         }
    280         if (Intent.ACTION_VIEW.equals(action)) {
    281             final Uri data = intent.getData();
    282             if (data != null && "tel".equals(data.getScheme())) {
    283                 return true;
    284             }
    285         }
    286         return false;
    287     }
    288 
    289     /**
    290      * Retrieves the filter text stored in {@link #setupFilterText(Intent)}.
    291      * This text originally came from a FILTER_CONTACTS_ACTION intent received
    292      * by this activity. The stored text will then be cleared after after this
    293      * method returns.
    294      *
    295      * @return The stored filter text
    296      */
    297     public String getAndClearFilterText() {
    298         String filterText = mFilterText;
    299         mFilterText = null;
    300         return filterText;
    301     }
    302 
    303     /**
    304      * Stores the filter text associated with a FILTER_CONTACTS_ACTION intent.
    305      * This is so child activities can check if they are supposed to display a filter.
    306      *
    307      * @param intent The intent received in {@link #onNewIntent(Intent)}
    308      */
    309     private void setupFilterText(Intent intent) {
    310         // If the intent was relaunched from history, don't apply the filter text.
    311         if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
    312             return;
    313         }
    314         String filter = intent.getStringExtra(UI.FILTER_TEXT_EXTRA_KEY);
    315         if (filter != null && filter.length() > 0) {
    316             mFilterText = filter;
    317         }
    318     }
    319 
    320     /**
    321      * Retrieves the uri stored in {@link #setupDialUri(Intent)}. This uri
    322      * originally came from a dial intent received by this activity. The stored
    323      * uri will then be cleared after after this method returns.
    324      *
    325      * @return The stored uri
    326      */
    327     public Uri getAndClearDialUri() {
    328         Uri dialUri = mDialUri;
    329         mDialUri = null;
    330         return dialUri;
    331     }
    332 
    333     /**
    334      * Stores the uri associated with a dial intent. This is so child activities can
    335      * check if they are supposed to display new dial info.
    336      *
    337      * @param intent The intent received in {@link #onNewIntent(Intent)}
    338      */
    339     private void setupDialUri(Intent intent) {
    340         // If the intent was relaunched from history, don't reapply the intent.
    341         if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
    342             return;
    343         }
    344         mDialUri = intent.getData();
    345     }
    346 
    347     @Override
    348     public void onBackPressed() {
    349         if (isTaskRoot()) {
    350             // Instead of stopping, simply push this to the back of the stack.
    351             // This is only done when running at the top of the stack;
    352             // otherwise, we have been launched by someone else so need to
    353             // allow the user to go back to the caller.
    354             moveTaskToBack(false);
    355         } else {
    356             super.onBackPressed();
    357         }
    358     }
    359 
    360     /** {@inheritDoc} */
    361     public void onTabChanged(String tabId) {
    362         // Because we're using Activities as our tab children, we trigger
    363         // onWindowFocusChanged() to let them know when they're active.  This may
    364         // seem to duplicate the purpose of onResume(), but it's needed because
    365         // onResume() can't reliably check if a keyguard is active.
    366         Activity activity = getLocalActivityManager().getActivity(tabId);
    367         if (activity != null) {
    368             activity.onWindowFocusChanged(true);
    369         }
    370 
    371         // Remember this tab index. This function is also called, if the tab is set automatically
    372         // in which case the setter (setCurrentTab) has to set this to its old value afterwards
    373         mLastManuallySelectedTab = mTabHost.getCurrentTab();
    374     }
    375 }
    376