Cleaning up single-pane layout. Phase I.

o Now using an overlay to determine whether to use a two-pane
or single-pane layout.

o Fixing search mode layout on the phone.

o Moving search activity to activities and renaming it

o Setting a custom theme for contact pickers

Change-Id: Iafe61df60206fbdab554c1772b05ca0e5bd74f6f
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7817e3a..4ffe15e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -167,6 +167,7 @@
         <activity android:name=".activities.ContactBrowserActivity"
             android:label="@string/contactsList"
             android:clearTaskOnLaunch="true"
+            android:theme="@style/ContactBrowserTheme"
         >
             <intent-filter>
                 <action android:name="com.android.contacts.action.LIST_DEFAULT" />
@@ -214,6 +215,7 @@
         <activity android:name=".activities.ContactSelectionActivity"
             android:label="@string/contactsList"
             android:clearTaskOnLaunch="true"
+            android:theme="@style/ContactPickerTheme"
         >
             <intent-filter>
                 <action android:name="android.intent.action.INSERT_OR_EDIT" />
@@ -272,7 +274,7 @@
         </activity>
 
         <!-- The contacts search/filter UI -->
-        <activity android:name="ContactsSearchActivity"
+        <activity android:name=".activities.ContactSearchActivity"
             android:theme="@style/ContactsSearchTheme"
             android:windowSoftInputMode="stateAlwaysVisible"
         >
@@ -286,7 +288,7 @@
 
         <!-- The contacts search/filter UI -->
         <activity-alias android:name="SearchResultsActivity"
-            android:targetActivity="ContactsSearchActivity"
+            android:targetActivity=".activities.ContactSearchActivity"
         >
             <intent-filter>
                 <action android:name="android.intent.action.SEARCH" />
diff --git a/res/layout/two_pane_activity.xml b/res/layout-xlarge/contact_browser.xml
similarity index 93%
rename from res/layout/two_pane_activity.xml
rename to res/layout-xlarge/contact_browser.xml
index 9676de0..18212d3 100644
--- a/res/layout/two_pane_activity.xml
+++ b/res/layout-xlarge/contact_browser.xml
@@ -20,14 +20,14 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <FrameLayout 
-        android:id="@+id/two_pane_list"
+        android:id="@+id/list_container"
         android:layout_width="0px"
         android:layout_height="match_parent"
         android:layout_weight="1" />
 
     <!--  Holder for detail- or editor-fragment. -->
     <FrameLayout
-        android:id="@+id/two_pane_right_view"
+        android:id="@+id/detail_container"
         android:layout_width="0px"
         android:layout_height="match_parent"
         android:layout_weight="1"
diff --git a/res/layout/contact_browser.xml b/res/layout/contact_browser.xml
new file mode 100644
index 0000000..0b4bb63
--- /dev/null
+++ b/res/layout/contact_browser.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/list_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+</FrameLayout>
diff --git a/res/values-xlarge/styles.xml b/res/values-xlarge/styles.xml
new file mode 100644
index 0000000..f514aad
--- /dev/null
+++ b/res/values-xlarge/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <style name="ContactBrowserTheme" parent="@android:Theme.WithActionBar">
+    </style>
+    <style name="ContactPickerTheme" parent="@android:Theme.Dialog">
+    </style>
+
+</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 93ae91d..385cc53 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -104,4 +104,11 @@
     <style name="DummyAnimation">
         <item name="android:windowExitAnimation">@anim/dummy_animation</item>
     </style>
+    
+    <style name="ContactBrowserTheme" parent="@android:Theme">
+    </style>
+    
+    <style name="ContactPickerTheme" parent="@android:Theme">
+    </style>
+    
 </resources>
diff --git a/src/com/android/contacts/ContactsSearchActivity.java b/src/com/android/contacts/ContactsSearchActivity.java
deleted file mode 100644
index ef2fe25..0000000
--- a/src/com/android/contacts/ContactsSearchActivity.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts;
-
-import com.android.contacts.activities.ContactBrowserActivity;
-
-public class ContactsSearchActivity extends ContactBrowserActivity {
-
-}
diff --git a/src/com/android/contacts/activities/ContactBrowserActivity.java b/src/com/android/contacts/activities/ContactBrowserActivity.java
index 1fe292a..40b5693 100644
--- a/src/com/android/contacts/activities/ContactBrowserActivity.java
+++ b/src/com/android/contacts/activities/ContactBrowserActivity.java
@@ -34,24 +34,19 @@
 import com.android.contacts.views.detail.ContactNoneFragment;
 import com.android.contacts.views.editor.ContactEditorFragment;
 import com.android.contacts.widget.ContextMenuAdapter;
-import com.android.contacts.widget.SearchEditText;
-import com.android.contacts.widget.SearchEditText.OnFilterTextListener;
 
 import android.app.ActionBar;
 import android.app.Activity;
 import android.app.Dialog;
 import android.app.Fragment;
-import android.app.FragmentTransaction;
 import android.content.ContentValues;
 import android.content.Intent;
-import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -102,12 +97,13 @@
     private boolean mSearchInitiated;
 
     private ContactsRequest mRequest;
-    private SearchEditText mSearchEditText;
 
-    private boolean mTwoPaneLayout;
+    private boolean mContactContentDisplayed;
     private NavigationBar mNavigationBar;
     private int mMode = -1;
 
+    private boolean mHasActionBar;
+
     public ContactBrowserActivity() {
         mIntentResolver = new ContactsIntentResolver(this);
     }
@@ -152,138 +148,101 @@
             return;
         }
 
-        // The user launched the config based front door, pick the right activity to go to
-        Configuration config = getResources().getConfiguration();
-        int screenLayoutSize = config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
-        mTwoPaneLayout = (screenLayoutSize == Configuration.SCREENLAYOUT_SIZE_XLARGE);
-        if (mTwoPaneLayout) {
-            configureTwoPaneLayout(savedState);
-        } else {
-            configureSinglePaneLayout();
-        }
-    }
-
-    private void configureSinglePaneLayout() {
         setTitle(mRequest.getActivityTitle());
+        setContentView(R.layout.contact_browser);
 
-        mListFragment = createListFragment(mRequest.getActionCode());
 
-        int listFragmentContainerId;
-        if (mRequest.isSearchMode()) {
-            setContentView(R.layout.contacts_search_content);
-            listFragmentContainerId = R.id.list_container;
-            mSearchEditText = (SearchEditText)findViewById(R.id.search_src_text);
-            mSearchEditText.setText(mRequest.getQueryString());
-            mSearchEditText.setOnFilterTextListener(new OnFilterTextListener() {
-                public void onFilterChange(String queryString) {
-                    mListFragment.setQueryString(queryString);
-                }
+        mHasActionBar = getWindow().hasFeature(Window.FEATURE_ACTION_BAR);
+        if (mHasActionBar) {
+            mNavigationBar = new NavigationBar(this);
+            mNavigationBar.onCreate(savedState, mRequest);
+            mNavigationBar.setListener(this);
 
-                public void onCancelSearch() {
-                    finish();
-                }
-            });
-        } else {
-            listFragmentContainerId = android.R.id.content;
+            ActionBar actionBar = getActionBar();
+            View navBarView = mNavigationBar.onCreateView(getLayoutInflater());
+            actionBar.setCustomNavigationMode(navBarView);
         }
 
-        FragmentTransaction transaction = openFragmentTransaction();
-        transaction.add(listFragmentContainerId, mListFragment);
-        transaction.commit();
-    }
-
-    private void configureTwoPaneLayout(Bundle savedState) {
-
-        // TODO: set the theme conditionally in AndroidManifest, once that feature is available
-        setTheme(android.R.style.Theme_WithActionBar);
-        requestWindowFeature(Window.FEATURE_ACTION_BAR);
-
-        setContentView(R.layout.two_pane_activity);
-
-        mNavigationBar = new NavigationBar(this);
-        mNavigationBar.onCreate(savedState, mRequest);
-        mNavigationBar.setListener(this);
-
-        ActionBar actionBar = getActionBar();
-        View navBarView = mNavigationBar.onCreateView(getLayoutInflater());
-        actionBar.setCustomNavigationMode(navBarView);
-
-        if (mListFragment == null) {
-            configureListFragment();
-        }
-
-        if (mEmptyFragment == null && mDetailFragment == null && mEditorFragment == null) {
-            setupContactDetailFragment(null);
-        }
-
-    }
-
-    @Override
-    public void onNavigationBarChange() {
         configureListFragment();
+
+        mContactContentDisplayed = findViewById(R.id.detail_container) != null;
+        if (mContactContentDisplayed) {
+            setupContactDetailFragment(mListFragment.getSelectedContactUri());
+        }
     }
 
     private void configureListFragment() {
-        int mode = mNavigationBar.getMode();
-        if (mode == NavigationBar.MODE_SEARCH
-                && TextUtils.isEmpty(mNavigationBar.getQueryString())) {
-            mode = mNavigationBar.getDefaultMode();
+        int mode = -1;
+        if (mHasActionBar) {
+            mode = mNavigationBar.getMode();
+            if (mode == NavigationBar.MODE_SEARCH
+                    && TextUtils.isEmpty(mNavigationBar.getQueryString())) {
+                mode = mNavigationBar.getDefaultMode();
+            }
+        } else {
+            int actionCode = mRequest.getActionCode();
+            if (actionCode == ContactsRequest.ACTION_FREQUENT ||
+                    actionCode == ContactsRequest.ACTION_STARRED ||
+                    actionCode == ContactsRequest.ACTION_STREQUENT) {
+                mode = NavigationBar.MODE_FAVORITES;
+            } else {
+                mode = NavigationBar.MODE_CONTACTS;
+            }
         }
 
-        if (mode == mMode) {
-            if (mode == NavigationBar.MODE_SEARCH) {
-                mListFragment.setQueryString(mNavigationBar.getQueryString());
-            }
-            return;
-        }
-
-        closeListFragment();
-
-        mMode = mode;
-        switch (mMode) {
-            case NavigationBar.MODE_CONTACTS: {
-                mListFragment = createListFragment(ContactsRequest.ACTION_DEFAULT);
-                break;
-            }
-            case NavigationBar.MODE_FAVORITES: {
-                int favoritesAction = mRequest.getActionCode();
-                if (favoritesAction == ContactsRequest.ACTION_DEFAULT) {
-                    favoritesAction = ContactsRequest.ACTION_STREQUENT;
+        boolean replaceList = (mode != mMode);
+        if (replaceList) {
+            closeListFragment();
+            mMode = mode;
+            switch (mMode) {
+                case NavigationBar.MODE_CONTACTS: {
+                    mListFragment = createListFragment(ContactsRequest.ACTION_DEFAULT);
+                    break;
                 }
-                mListFragment = createListFragment(favoritesAction);
-                break;
-            }
-            case NavigationBar.MODE_SEARCH: {
-                mListFragment = createContactSearchFragment();
-                break;
+                case NavigationBar.MODE_FAVORITES: {
+                    int favoritesAction = mRequest.getActionCode();
+                    if (favoritesAction == ContactsRequest.ACTION_DEFAULT) {
+                        favoritesAction = ContactsRequest.ACTION_STREQUENT;
+                    }
+                    mListFragment = createListFragment(favoritesAction);
+                    break;
+                }
+                case NavigationBar.MODE_SEARCH: {
+                    mListFragment = createContactSearchFragment();
+                    break;
+                }
             }
         }
 
-        Bundle savedState = mNavigationBar.getSavedStateForMode(mMode);
-        if (savedState != null) {
-            mListFragment.restoreSavedState(savedState);
-        }
-
-        if (mode == NavigationBar.MODE_SEARCH) {
+        if (mMode == NavigationBar.MODE_SEARCH) {
             mListFragment.setQueryString(mNavigationBar.getQueryString());
         }
 
-        setupContactDetailFragment(mListFragment.getSelectedContactUri());
+        if (mHasActionBar) {
+            Bundle savedStateForMode = mNavigationBar.getSavedStateForMode(mMode);
+            if (savedStateForMode != null) {
+                mListFragment.restoreSavedState(savedStateForMode);
+            }
+        }
 
-        openFragmentTransaction()
-                .replace(R.id.two_pane_list, mListFragment)
-                .commit();
+        if (replaceList) {
+            openFragmentTransaction()
+                    .replace(R.id.list_container, mListFragment)
+                    .commit();
+        }
     }
 
     private void closeListFragment() {
         if (mListFragment != null) {
             mListFragment.setOnContactListActionListener(null);
 
-            if (mNavigationBar != null) {
+            if (mHasActionBar) {
                 Bundle state = new Bundle();
                 mListFragment.onSaveInstanceState(state);
                 mNavigationBar.saveStateForMode(mMode, state);
             }
+
+            mListFragment = null;
         }
     }
 
@@ -317,14 +276,14 @@
 
             // Nothing showing yet? Create (this happens during Activity-Startup)
             openFragmentTransaction()
-                    .replace(R.id.two_pane_right_view, mDetailFragment)
+                    .replace(R.id.detail_container, mDetailFragment)
                     .commit();
         } else {
             closeDetailFragment();
 
             mEmptyFragment = new ContactNoneFragment();
             openFragmentTransaction()
-                    .replace(R.id.two_pane_right_view, mEmptyFragment)
+                    .replace(R.id.detail_container, mEmptyFragment)
                     .commit();
         }
     }
@@ -341,7 +300,7 @@
 
         // Nothing showing yet? Create (this happens during Activity-Startup)
         openFragmentTransaction()
-                .replace(R.id.two_pane_right_view, mEditorFragment)
+                .replace(R.id.detail_container, mEditorFragment)
                 .commit();
     }
 
@@ -370,11 +329,9 @@
     }
 
     @Override
-    protected void onResume() {
-        super.onResume();
-        if (!mTwoPaneLayout && mRequest.isSearchMode()) {
-            mSearchEditText.requestFocus();
-        }
+    public void onNavigationBarChange() {
+        configureListFragment();
+        setupContactDetailFragment(mListFragment.getSelectedContactUri());
     }
 
     @Override
@@ -402,7 +359,7 @@
                 fragment.setDirectorySearchEnabled(
                         mRequest.isSearchMode() && mRequest.isDirectorySearchEnabled());
                 fragment.setAizyEnabled(!mRequest.isSearchMode());
-                fragment.setSelectionVisible(mTwoPaneLayout);
+                fragment.setSelectionVisible(mContactContentDisplayed);
                 return fragment;
             }
 
@@ -415,7 +372,7 @@
                 fragment.setOnContactListActionListener(new ContactBrowserActionListener());
                 fragment.setFrequentlyContactedContactsIncluded(false);
                 fragment.setStarredContactsIncluded(true);
-                fragment.setSelectionVisible(mTwoPaneLayout);
+                fragment.setSelectionVisible(mContactContentDisplayed);
                 return fragment;
             }
 
@@ -424,7 +381,7 @@
                 fragment.setOnContactListActionListener(new ContactBrowserActionListener());
                 fragment.setFrequentlyContactedContactsIncluded(true);
                 fragment.setStarredContactsIncluded(false);
-                fragment.setSelectionVisible(mTwoPaneLayout);
+                fragment.setSelectionVisible(mContactContentDisplayed);
                 return fragment;
             }
 
@@ -433,7 +390,7 @@
                 fragment.setOnContactListActionListener(new ContactBrowserActionListener());
                 fragment.setFrequentlyContactedContactsIncluded(true);
                 fragment.setStarredContactsIncluded(true);
-                fragment.setSelectionVisible(mTwoPaneLayout);
+                fragment.setSelectionVisible(mContactContentDisplayed);
                 return fragment;
             }
 
@@ -457,7 +414,7 @@
 
     private final class ContactBrowserActionListener implements OnContactBrowserActionListener {
         public void onViewContactAction(Uri contactLookupUri) {
-            if (mTwoPaneLayout) {
+            if (mContactContentDisplayed) {
                 mListFragment.setSelectedContactUri(contactLookupUri);
                 setupContactDetailFragment(contactLookupUri);
             } else {
@@ -594,7 +551,7 @@
         super.onCreateOptionsMenu(menu);
 
         MenuInflater inflater = getMenuInflater();
-        if (mTwoPaneLayout) {
+        if (mContactContentDisplayed) {
             inflater.inflate(R.menu.actions, menu);
             return true;
         } else if (mRequest.getActionCode() == ContactsRequest.ACTION_DEFAULT ||
@@ -783,7 +740,7 @@
 
                 if (unicodeChar != 0) {
                     String query = new String(new int[]{ unicodeChar }, 0, 1);
-                    if (mTwoPaneLayout) {
+                    if (mContactContentDisplayed) {
                         if (mNavigationBar.getMode() != NavigationBar.MODE_SEARCH) {
                             mNavigationBar.setQueryString(query);
                             mNavigationBar.setMode(NavigationBar.MODE_SEARCH);
diff --git a/src/com/android/contacts/activities/ContactSearchActivity.java b/src/com/android/contacts/activities/ContactSearchActivity.java
new file mode 100644
index 0000000..327ccfa
--- /dev/null
+++ b/src/com/android/contacts/activities/ContactSearchActivity.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.activities;
+
+import com.android.contacts.R;
+import com.android.contacts.interactions.ContactDeletionInteraction;
+import com.android.contacts.interactions.PhoneNumberInteraction;
+import com.android.contacts.list.ContactBrowseListContextMenuAdapter;
+import com.android.contacts.list.ContactBrowseListFragment;
+import com.android.contacts.list.ContactsIntentResolver;
+import com.android.contacts.list.ContactsRequest;
+import com.android.contacts.list.DefaultContactBrowseListFragment;
+import com.android.contacts.list.OnContactBrowserActionListener;
+import com.android.contacts.widget.SearchEditText;
+import com.android.contacts.widget.SearchEditText.OnFilterTextListener;
+
+import android.app.Activity;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract.Contacts;
+
+public class ContactSearchActivity extends Activity {
+
+    private ContactsIntentResolver mIntentResolver;
+    private ContactsRequest mRequest;
+    private ContactBrowseListFragment mListFragment;
+    private PhoneNumberInteraction mPhoneNumberCallInteraction;
+    private PhoneNumberInteraction mSendTextMessageInteraction;
+    private ContactDeletionInteraction mContactDeletionInteraction;
+    private SearchEditText mSearchEditText;
+
+    public ContactSearchActivity() {
+        mIntentResolver = new ContactsIntentResolver(this);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedState) {
+        super.onCreate(savedState);
+
+        // Extract relevant information from the intent
+        mRequest = mIntentResolver.resolveIntent(getIntent());
+        if (!mRequest.isValid()) {
+            setResult(RESULT_CANCELED);
+            finish();
+            return;
+        }
+
+        setTitle(mRequest.getActivityTitle());
+
+        setContentView(R.layout.contacts_search_content);
+
+        if (mListFragment == null) {
+            mListFragment = createContactSearchFragment();
+            openFragmentTransaction()
+                    .replace(R.id.list_container, mListFragment)
+                    .commit();
+        }
+
+        mSearchEditText = (SearchEditText)findViewById(R.id.search_src_text);
+        mSearchEditText.setText(mRequest.getQueryString());
+        mSearchEditText.setOnFilterTextListener(new OnFilterTextListener() {
+            public void onFilterChange(String queryString) {
+                mListFragment.setQueryString(queryString);
+            }
+
+            public void onCancelSearch() {
+                finish();
+            }
+        });
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mSearchEditText.requestFocus();
+    }
+
+
+    private ContactBrowseListFragment createContactSearchFragment() {
+        DefaultContactBrowseListFragment fragment = new DefaultContactBrowseListFragment();
+        fragment.setOnContactListActionListener(new ContactBrowserActionListener());
+        fragment.setDisplayWithPhonesOnlyOption(ContactsRequest.DISPLAY_ONLY_WITH_PHONES_DISABLED);
+        fragment.setVisibleContactsRestrictionEnabled(true);
+        fragment.setContextMenuAdapter(new ContactBrowseListContextMenuAdapter(fragment));
+        fragment.setSearchMode(true);
+        fragment.setDirectorySearchEnabled(true);
+        fragment.setAizyEnabled(false);
+        fragment.setSelectionVisible(true);
+        fragment.setEditMode(mRequest.getActionCode() ==
+                ContactsRequest.ACTION_INSERT_OR_EDIT_CONTACT);
+        return fragment;
+    }
+
+    private final class ContactBrowserActionListener implements OnContactBrowserActionListener {
+        public void onViewContactAction(Uri contactLookupUri) {
+            startActivity(new Intent(Intent.ACTION_VIEW, contactLookupUri));
+        }
+
+        public void onCreateNewContactAction() {
+        }
+
+        public void onEditContactAction(Uri contactLookupUri) {
+            Intent intent = new Intent(Intent.ACTION_EDIT, contactLookupUri);
+            Bundle extras = getIntent().getExtras();
+            if (extras != null) {
+                intent.putExtras(extras);
+            }
+            startActivity(intent);
+        }
+
+        public void onAddToFavoritesAction(Uri contactUri) {
+            ContentValues values = new ContentValues(1);
+            values.put(Contacts.STARRED, 1);
+            getContentResolver().update(contactUri, values, null, null);
+        }
+
+        public void onRemoveFromFavoritesAction(Uri contactUri) {
+            ContentValues values = new ContentValues(1);
+            values.put(Contacts.STARRED, 0);
+            getContentResolver().update(contactUri, values, null, null);
+        }
+
+        public void onCallContactAction(Uri contactUri) {
+            getPhoneNumberCallInteraction().startInteraction(contactUri);
+        }
+
+        public void onSmsContactAction(Uri contactUri) {
+            getSendTextMessageInteraction().startInteraction(contactUri);
+        }
+
+        public void onDeleteContactAction(Uri contactUri) {
+            getContactDeletionInteraction().deleteContact(contactUri);
+        }
+
+        public void onFinishAction() {
+            onBackPressed();
+        }
+    }
+
+    private PhoneNumberInteraction getPhoneNumberCallInteraction() {
+        if (mPhoneNumberCallInteraction == null) {
+            mPhoneNumberCallInteraction = new PhoneNumberInteraction(this, false, null);
+        }
+        return mPhoneNumberCallInteraction;
+    }
+
+    private PhoneNumberInteraction getSendTextMessageInteraction() {
+        if (mSendTextMessageInteraction == null) {
+            mSendTextMessageInteraction = new PhoneNumberInteraction(this, true, null);
+        }
+        return mSendTextMessageInteraction;
+    }
+
+    private ContactDeletionInteraction getContactDeletionInteraction() {
+        if (mContactDeletionInteraction == null) {
+            mContactDeletionInteraction = new ContactDeletionInteraction();
+            mContactDeletionInteraction.attachToActivity(this);
+        }
+        return mContactDeletionInteraction;
+    }
+}