Add DialpadFragment on-demand instead at on startup

Add the DialpadFragment dynamically instead of everything at
startup. Once added, it is then shown/hidden instead of removed
for performance reasons.

Reduces startup time on a N5 from 603ms to 440ms.

Bug: 18431193

Change-Id: I0482bd8277896ed8a6956fc03b6afaf44b442eb3
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index beec280..21e613f 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -91,6 +91,8 @@
 import com.android.phone.common.animation.AnimUtils;
 import com.android.phone.common.animation.AnimationListenerAdapter;
 
+import junit.framework.Assert;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -406,12 +408,11 @@
         mOverflowMenu = buildOptionsMenu(searchEditTextLayout);
         optionsMenuButton.setOnTouchListener(mOverflowMenu.getDragToOpenListener());
 
-        // Add the favorites fragment, and the dialpad fragment, but only if savedInstanceState
-        // is null. Otherwise the fragment manager takes care of recreating these fragments.
+        // Add the favorites fragment but only if savedInstanceState is null. Otherwise the
+        // fragment manager is responsible for recreating it.
         if (savedInstanceState == null) {
             getFragmentManager().beginTransaction()
                     .add(R.id.dialtacts_frame, new ListsFragment(), TAG_FAVORITES_FRAGMENT)
-                    .add(R.id.dialtacts_container, new DialpadFragment(), TAG_DIALPAD_FRAGMENT)
                     .commit();
         } else {
             mSearchQuery = savedInstanceState.getString(KEY_SEARCH_QUERY);
@@ -554,7 +555,7 @@
     public void onAttachFragment(Fragment fragment) {
         if (fragment instanceof DialpadFragment) {
             mDialpadFragment = (DialpadFragment) fragment;
-            if (!mShowDialpadOnResume) {
+            if (!mIsDialpadShown && !mShowDialpadOnResume) {
                 final FragmentTransaction transaction = getFragmentManager().beginTransaction();
                 transaction.hide(mDialpadFragment);
                 transaction.commit();
@@ -667,12 +668,19 @@
             return;
         }
         mIsDialpadShown = true;
-        mDialpadFragment.setAnimate(animate);
+
         mListsFragment.setUserVisibleHint(false);
-        AnalyticsUtil.sendScreenView(mDialpadFragment);
 
         final FragmentTransaction ft = getFragmentManager().beginTransaction();
-        ft.show(mDialpadFragment);
+        if (mDialpadFragment == null) {
+            mDialpadFragment = new DialpadFragment();
+            ft.add(R.id.dialtacts_container, mDialpadFragment, TAG_DIALPAD_FRAGMENT);
+        } else {
+            ft.show(mDialpadFragment);
+        }
+
+        mDialpadFragment.setAnimate(animate);
+        AnalyticsUtil.sendScreenView(mDialpadFragment);
         ft.commit();
 
         if (animate) {
@@ -691,6 +699,7 @@
      * Callback from child DialpadFragment when the dialpad is shown.
      */
     public void onDialpadShown() {
+        Assert.assertNotNull(mDialpadFragment);
         if (mDialpadFragment.getAnimate()) {
             mDialpadFragment.getView().startAnimation(mSlideIn);
         } else {
@@ -742,7 +751,7 @@
      * Finishes hiding the dialpad fragment after any animations are completed.
      */
     private void commitDialpadFragmentHide() {
-        if (!mStateSaved && !mDialpadFragment.isHidden()) {
+        if (!mStateSaved && mDialpadFragment != null && !mDialpadFragment.isHidden()) {
             final FragmentTransaction ft = getFragmentManager().beginTransaction();
             ft.hide(mDialpadFragment);
             ft.commit();
@@ -850,14 +859,12 @@
             return;
         }
 
-        if (mDialpadFragment != null) {
-            final boolean phoneIsInUse = phoneIsInUse();
-            if (phoneIsInUse || (intent.getData() !=  null && isDialIntent(intent))) {
-                mDialpadFragment.setStartedFromNewIntent(true);
-                if (phoneIsInUse && !mDialpadFragment.isVisible()) {
-                    mInCallDialpadUp = true;
-                }
-                showDialpadFragment(false);
+        final boolean phoneIsInUse = phoneIsInUse();
+        if (phoneIsInUse || (intent.getData() !=  null && isDialIntent(intent))) {
+            showDialpadFragment(false);
+            mDialpadFragment.setStartedFromNewIntent(true);
+            if (phoneIsInUse && !mDialpadFragment.isVisible()) {
+                mInCallDialpadUp = true;
             }
         }
     }
@@ -959,7 +966,11 @@
         }
 
         mSearchView.setText(null);
-        mDialpadFragment.clearDialpad();
+
+        if (mDialpadFragment != null) {
+            mDialpadFragment.clearDialpad();
+        }
+
         setNotInSearchUi();
 
         final FragmentTransaction transaction = getFragmentManager().beginTransaction();
@@ -972,7 +983,8 @@
         transaction.commit();
 
         mListsFragment.getView().animate().alpha(1).withLayer();
-        if (!mDialpadFragment.isVisible()) {
+
+        if (mDialpadFragment == null || !mDialpadFragment.isVisible()) {
             // If the dialpad fragment wasn't previously visible, then send a screen view because
             // we are exiting regular search. Otherwise, the screen view will be sent by
             // {@link #hideDialpadFragment}.
diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java
index 71b9ae8..87501fb 100644
--- a/src/com/android/dialer/dialpad/DialpadFragment.java
+++ b/src/com/android/dialer/dialpad/DialpadFragment.java
@@ -45,13 +45,10 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.PhoneNumberUtils;
-import android.telephony.PhoneStateListener;
 import android.telephony.TelephonyManager;
 import android.text.Editable;
-import android.text.SpannableString;
 import android.text.TextUtils;
 import android.text.TextWatcher;
-import android.text.style.RelativeSizeSpan;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -318,7 +315,9 @@
     public void onCreate(Bundle state) {
         Trace.beginSection(TAG + " onCreate");
         super.onCreate(state);
-        mFirstLaunch = true;
+
+        mFirstLaunch = state == null;
+
         mCurrentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
 
         try {
@@ -358,7 +357,6 @@
         Trace.endSection();
 
         Trace.beginSection(TAG + " setup views");
-        Resources r = getResources();
 
         mDialpadView = (DialpadView) fragmentView.findViewById(R.id.dialpad_view);
         mDialpadView.setCanDigitsBeEdited(true);
@@ -654,8 +652,6 @@
             showDialpadChooser(false);
         }
 
-        mFirstLaunch = false;
-
         stopWatch.lap("hnt");
 
         updateDeleteButtonEnabledState();
@@ -674,6 +670,14 @@
         mOverflowMenuButton.setOnTouchListener(mOverflowPopupMenu.getDragToOpenListener());
         mOverflowMenuButton.setOnClickListener(this);
         mOverflowMenuButton.setVisibility(isDigitsEmpty() ? View.INVISIBLE : View.VISIBLE);
+
+        if (mFirstLaunch) {
+            // The onHiddenChanged callback does not get called the first time the fragment is
+            // attached, so call it ourselves here.
+            onHiddenChanged(false);
+        }
+
+        mFirstLaunch = false;
         Trace.endSection();
     }