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     private static final int TAB_INDEX_DIALER = 0;
     48     private static final int TAB_INDEX_CALL_LOG = 1;
     49     private static final int TAB_INDEX_CONTACTS = 2;
     50     private static final int TAB_INDEX_FAVORITES = 3;
     51 
     52     static final String EXTRA_IGNORE_STATE = "ignore-state";
     53 
     54     /** If true, when handling the contacts intent the favorites tab will be shown instead */
     55     private static final String PREF_FAVORITES_AS_CONTACTS = "favorites_as_contacts";
     56     private static final boolean PREF_FAVORITES_AS_CONTACTS_DEFAULT = false;
     57 
     58     private TabHost mTabHost;
     59     private String mFilterText;
     60     private Uri mDialUri;
     61 
     62     @Override
     63     protected void onCreate(Bundle icicle) {
     64         super.onCreate(icicle);
     65 
     66         final Intent intent = getIntent();
     67 
     68         requestWindowFeature(Window.FEATURE_NO_TITLE);
     69         setContentView(R.layout.dialer_activity);
     70 
     71         mTabHost = getTabHost();
     72         mTabHost.setOnTabChangedListener(this);
     73 
     74         // Setup the tabs
     75         setupDialerTab();
     76         setupCallLogTab();
     77         setupContactsTab();
     78         setupFavoritesTab();
     79 
     80         setCurrentTab(intent);
     81 
     82         if (intent.getAction().equals(UI.FILTER_CONTACTS_ACTION)
     83                 && icicle == null) {
     84             setupFilterText(intent);
     85         }
     86     }
     87 
     88     @Override
     89     protected void onPause() {
     90         super.onPause();
     91 
     92         final int currentTabIndex = mTabHost.getCurrentTab();
     93         final SharedPreferences.Editor editor =
     94                 getSharedPreferences(StickyTabs.PREFERENCES_NAME, MODE_PRIVATE).edit();
     95         if (currentTabIndex == TAB_INDEX_CONTACTS || currentTabIndex == TAB_INDEX_FAVORITES) {
     96             editor.putBoolean(PREF_FAVORITES_AS_CONTACTS, currentTabIndex == TAB_INDEX_FAVORITES);
     97         }
     98 
     99         editor.apply();
    100     }
    101 
    102     private void setupCallLogTab() {
    103         // Force the class since overriding tab entries doesn't work
    104         Intent intent = new Intent("com.android.phone.action.RECENT_CALLS");
    105         intent.setClass(this, RecentCallsListActivity.class);
    106         StickyTabs.setTab(intent, TAB_INDEX_CALL_LOG);
    107 
    108         mTabHost.addTab(mTabHost.newTabSpec("call_log")
    109                 .setIndicator(getString(R.string.recentCallsIconLabel),
    110                         getResources().getDrawable(R.drawable.ic_tab_recent))
    111                 .setContent(intent));
    112     }
    113 
    114     private void setupDialerTab() {
    115         Intent intent = new Intent("com.android.phone.action.TOUCH_DIALER");
    116         intent.setClass(this, TwelveKeyDialer.class);
    117         StickyTabs.setTab(intent, TAB_INDEX_DIALER);
    118 
    119         mTabHost.addTab(mTabHost.newTabSpec("dialer")
    120                 .setIndicator(getString(R.string.dialerIconLabel),
    121                         getResources().getDrawable(R.drawable.ic_tab_dialer))
    122                 .setContent(intent));
    123     }
    124 
    125     private void setupContactsTab() {
    126         Intent intent = new Intent(UI.LIST_DEFAULT);
    127         intent.setClass(this, ContactsListActivity.class);
    128         StickyTabs.setTab(intent, TAB_INDEX_CONTACTS);
    129 
    130         mTabHost.addTab(mTabHost.newTabSpec("contacts")
    131                 .setIndicator(getText(R.string.contactsIconLabel),
    132                         getResources().getDrawable(R.drawable.ic_tab_contacts))
    133                 .setContent(intent));
    134     }
    135 
    136     private void setupFavoritesTab() {
    137         Intent intent = new Intent(UI.LIST_STREQUENT_ACTION);
    138         intent.setClass(this, ContactsListActivity.class);
    139         StickyTabs.setTab(intent, TAB_INDEX_FAVORITES);
    140 
    141         mTabHost.addTab(mTabHost.newTabSpec("favorites")
    142                 .setIndicator(getString(R.string.contactsFavoritesLabel),
    143                         getResources().getDrawable(R.drawable.ic_tab_starred))
    144                 .setContent(intent));
    145     }
    146 
    147     /**
    148      * Sets the current tab based on the intent's request type
    149      *
    150      * @param intent Intent that contains information about which tab should be selected
    151      */
    152     private void setCurrentTab(Intent intent) {
    153         // Dismiss menu provided by any children activities
    154         Activity activity = getLocalActivityManager().
    155                 getActivity(mTabHost.getCurrentTabTag());
    156         if (activity != null) {
    157             activity.closeOptionsMenu();
    158         }
    159 
    160         // Tell the children activities that they should ignore any possible saved
    161         // state and instead reload their state from the parent's intent
    162         intent.putExtra(EXTRA_IGNORE_STATE, true);
    163 
    164         // Choose the tab based on the inbound intent
    165         String componentName = intent.getComponent().getClassName();
    166         if (getClass().getName().equals(componentName)) {
    167             if (phoneIsInUse()) {
    168                 // We are in a call, show the dialer tab (which allows going back to the call)
    169                 mTabHost.setCurrentTab(TAB_INDEX_DIALER);
    170             } else if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
    171                 // launched from history (long-press home) --> nothing to change
    172             } else if (isDialIntent(intent)) {
    173                 // The dialer was explicitly requested
    174                 mTabHost.setCurrentTab(TAB_INDEX_DIALER);
    175             } else if (Calls.CONTENT_TYPE.equals(intent.getType())) {
    176                 // After a call, show the call log
    177                 mTabHost.setCurrentTab(TAB_INDEX_CALL_LOG);
    178             } else {
    179                 // Load the last tab used to make a phone call. default to the dialer in
    180                 // first launch
    181                 mTabHost.setCurrentTab(StickyTabs.loadTab(this, TAB_INDEX_DIALER));
    182             }
    183         } else if (FAVORITES_ENTRY_COMPONENT.equals(componentName)) {
    184             mTabHost.setCurrentTab(TAB_INDEX_FAVORITES);
    185         } else {
    186             // Launched as "Contacts" --> Go either to favorites or contacts, whichever is more
    187             // recent
    188             final SharedPreferences prefs = getSharedPreferences(StickyTabs.PREFERENCES_NAME,
    189                     MODE_PRIVATE);
    190             final boolean favoritesAsContacts = prefs.getBoolean(PREF_FAVORITES_AS_CONTACTS,
    191                     PREF_FAVORITES_AS_CONTACTS_DEFAULT);
    192             if (favoritesAsContacts) {
    193                 mTabHost.setCurrentTab(TAB_INDEX_FAVORITES);
    194             } else {
    195                 mTabHost.setCurrentTab(TAB_INDEX_CONTACTS);
    196             }
    197         }
    198 
    199         // Tell the children activities that they should honor their saved states
    200         // instead of the state from the parent's intent
    201         intent.putExtra(EXTRA_IGNORE_STATE, false);
    202     }
    203 
    204     @Override
    205     public void onNewIntent(Intent newIntent) {
    206         setIntent(newIntent);
    207         setCurrentTab(newIntent);
    208         final String action = newIntent.getAction();
    209         if (action.equals(UI.FILTER_CONTACTS_ACTION)) {
    210             setupFilterText(newIntent);
    211         } else if (isDialIntent(newIntent)) {
    212             setupDialUri(newIntent);
    213         }
    214     }
    215 
    216     /** Returns true if the given intent contains a phone number to populate the dialer with */
    217     private boolean isDialIntent(Intent intent) {
    218         final String action = intent.getAction();
    219         if (Intent.ACTION_DIAL.equals(action)) {
    220             return true;
    221         }
    222         if (Intent.ACTION_VIEW.equals(action)) {
    223             final Uri data = intent.getData();
    224             if (data != null && "tel".equals(data.getScheme())) {
    225                 return true;
    226             }
    227         }
    228         return false;
    229     }
    230 
    231     /**
    232      * Retrieves the filter text stored in {@link #setupFilterText(Intent)}.
    233      * This text originally came from a FILTER_CONTACTS_ACTION intent received
    234      * by this activity. The stored text will then be cleared after after this
    235      * method returns.
    236      *
    237      * @return The stored filter text
    238      */
    239     public String getAndClearFilterText() {
    240         String filterText = mFilterText;
    241         mFilterText = null;
    242         return filterText;
    243     }
    244 
    245     /**
    246      * Stores the filter text associated with a FILTER_CONTACTS_ACTION intent.
    247      * This is so child activities can check if they are supposed to display a filter.
    248      *
    249      * @param intent The intent received in {@link #onNewIntent(Intent)}
    250      */
    251     private void setupFilterText(Intent intent) {
    252         // If the intent was relaunched from history, don't apply the filter text.
    253         if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
    254             return;
    255         }
    256         String filter = intent.getStringExtra(UI.FILTER_TEXT_EXTRA_KEY);
    257         if (filter != null && filter.length() > 0) {
    258             mFilterText = filter;
    259         }
    260     }
    261 
    262     /**
    263      * Retrieves the uri stored in {@link #setupDialUri(Intent)}. This uri
    264      * originally came from a dial intent received by this activity. The stored
    265      * uri will then be cleared after after this method returns.
    266      *
    267      * @return The stored uri
    268      */
    269     public Uri getAndClearDialUri() {
    270         Uri dialUri = mDialUri;
    271         mDialUri = null;
    272         return dialUri;
    273     }
    274 
    275     /**
    276      * Stores the uri associated with a dial intent. This is so child activities can
    277      * check if they are supposed to display new dial info.
    278      *
    279      * @param intent The intent received in {@link #onNewIntent(Intent)}
    280      */
    281     private void setupDialUri(Intent intent) {
    282         // If the intent was relaunched from history, don't reapply the intent.
    283         if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
    284             return;
    285         }
    286         mDialUri = intent.getData();
    287     }
    288 
    289     @Override
    290     public void onBackPressed() {
    291         if (isTaskRoot()) {
    292             // Instead of stopping, simply push this to the back of the stack.
    293             // This is only done when running at the top of the stack;
    294             // otherwise, we have been launched by someone else so need to
    295             // allow the user to go back to the caller.
    296             moveTaskToBack(false);
    297         } else {
    298             super.onBackPressed();
    299         }
    300     }
    301 
    302     /** {@inheritDoc} */
    303     @Override
    304     public void onTabChanged(String tabId) {
    305         // Because we're using Activities as our tab children, we trigger
    306         // onWindowFocusChanged() to let them know when they're active.  This may
    307         // seem to duplicate the purpose of onResume(), but it's needed because
    308         // onResume() can't reliably check if a keyguard is active.
    309         Activity activity = getLocalActivityManager().getActivity(tabId);
    310         if (activity != null) {
    311             activity.onWindowFocusChanged(true);
    312         }
    313     }
    314 
    315     /**
    316      * @return true if the phone is "in use", meaning that at least one line
    317      *              is active (ie. off hook or ringing or dialing).
    318      */
    319     private boolean phoneIsInUse() {
    320         boolean phoneInUse = false;
    321         try {
    322             ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
    323             if (phone != null) phoneInUse = !phone.isIdle();
    324         } catch (RemoteException e) {
    325             Log.w(TAG, "phone.isIdle() failed", e);
    326         }
    327         return phoneInUse;
    328     }
    329 }
    330