summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorke Lee <yorkelee@google.com>2013-08-09 17:39:25 -0700
committerYorke Lee <yorkelee@google.com>2013-08-11 15:22:31 -0700
commitef2b7388569a94432278a617b528f628385fbb8c (patch)
tree2a17f308421912390b12fd29b3320d9af01e32e4
parentc87896cd74290eba75d3ba3ee8a3f5bfe36b63fb (diff)
Improve fragment handling
* SmartDialSearchFragment now extends SearchFragment to avoid code duplication * Load search fragments dynamically instead of all at once on startup * Don't always return the user to the favorites screen on resume * Activity and fragment state persist across activity recreation Bug: 10248520 Change-Id: I6bce83e22a8eced9783805ea5a924f34bae78a14
-rw-r--r--src/com/android/dialer/DialtactsActivity.java182
-rw-r--r--src/com/android/dialer/SearchFragment.java9
-rw-r--r--src/com/android/dialer/list/SmartDialSearchFragment.java51
3 files changed, 115 insertions, 127 deletions
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index 8381c8dd4..316465e74 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -102,11 +102,14 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
private static final String CALL_ORIGIN_DIALTACTS =
"com.android.dialer.DialtactsActivity";
+ private static final String KEY_IN_SEARCH_UI = "in_search_ui";
+ private static final String KEY_SEARCH_QUERY = "search_query";
+ private static final String KEY_FIRST_LAUNCH = "first_launch";
+
private static final String TAG_DIALPAD_FRAGMENT = "dialpad";
private static final String TAG_REGULAR_SEARCH_FRAGMENT = "search";
private static final String TAG_SMARTDIAL_SEARCH_FRAGMENT = "smartdial";
private static final String TAG_FAVORITES_FRAGMENT = "favorites";
- private static final String TAG_SHOW_ALL_CONTACTS_FRAGMENT = "show_all_contacts";
/**
* Just for backward compatibility. Should behave as same as {@link Intent#ACTION_DIAL}.
@@ -151,12 +154,17 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
* {@link PhoneNumberPickerFragment}).
*/
private boolean mInSearchUi;
+ /**
+ * True when this activity has been launched for the first time.
+ */
private boolean mFirstLaunch;
private View mSearchViewContainer;
private View mSearchViewCloseButton;
private View mVoiceSearchButton;
private EditText mSearchView;
+ private String mSearchQuery;
+
/**
* Listener used when one of phone numbers in search UI is selected. This will initiate a
* phone call using the phone number.
@@ -198,26 +206,31 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
- // TODO krelease: populate the search fragments with the correct
- // search query at the correct point in time of the fragment lifecycle.
- // The current behavior is to simply return to the favorites screen
- // (when docked), or returning to the Dialer after it has been
- // swapped out of memory.
- if (mDialpadFragment == null) return;
- final boolean smartDialSearch = isDialpadShowing();
final String newText = s.toString();
+ if (newText.equals(mSearchQuery)) {
+ // If the query hasn't changed (perhaps due to activity being destroyed
+ // and restored, or user launching the same DIAL intent twice), then there is
+ // no need to do anything here.
+ return;
+ }
+ mSearchQuery = newText;
+ if (DEBUG) {
+ Log.d(TAG, "onTextChange for mSearchView called with new query: " + s);
+ }
+ final boolean smartDialSearch = isDialpadShowing();
+
// Show search result with non-empty text. Show a bare list otherwise.
if (TextUtils.isEmpty(newText) && mInSearchUi) {
exitSearchUi();
mSearchViewCloseButton.setVisibility(View.GONE);
return;
} else if (!TextUtils.isEmpty(newText) && !mInSearchUi) {
- enterSearchUi(smartDialSearch);
+ enterSearchUi(smartDialSearch, newText);
}
- if (smartDialSearch) {
- mSmartDialSearchFragment.setQueryString(newText, false);
- } else {
+ if (smartDialSearch && mSmartDialSearchFragment != null) {
+ mSmartDialSearchFragment.setQueryString(newText, false);
+ } else if (mRegularSearchFragment != null) {
mRegularSearchFragment.setQueryString(newText, false);
}
mSearchViewCloseButton.setVisibility(View.VISIBLE);
@@ -236,7 +249,6 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
mFirstLaunch = true;
final Intent intent = getIntent();
@@ -246,21 +258,20 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
getActionBar().hide();
+ // Add the favorites fragment, and the dialpad fragment, but only if savedInstanceState
+ // is null. Otherwise the fragment manager takes care of recreating these fragments.
if (savedInstanceState == null) {
- mPhoneFavoriteFragment = new PhoneFavoriteFragment();
- mPhoneFavoriteFragment.setListener(mPhoneFavoriteListener);
-
- mRegularSearchFragment = new SearchFragment();
- mSmartDialSearchFragment = new SmartDialSearchFragment();
- mDialpadFragment = new DialpadFragment();
+ final PhoneFavoriteFragment phoneFavoriteFragment = new PhoneFavoriteFragment();
+ phoneFavoriteFragment.setListener(mPhoneFavoriteListener);
- // TODO krelease: load fragments on demand instead of creating all of them at run time
final FragmentTransaction ft = getFragmentManager().beginTransaction();
- ft.add(R.id.dialtacts_frame, mPhoneFavoriteFragment, TAG_FAVORITES_FRAGMENT);
- ft.add(R.id.dialtacts_frame, mRegularSearchFragment, TAG_REGULAR_SEARCH_FRAGMENT);
- ft.add(R.id.dialtacts_frame, mSmartDialSearchFragment, TAG_SMARTDIAL_SEARCH_FRAGMENT);
- ft.add(R.id.dialtacts_container, mDialpadFragment, TAG_DIALPAD_FRAGMENT);
+ ft.add(R.id.dialtacts_frame, phoneFavoriteFragment, TAG_FAVORITES_FRAGMENT);
+ ft.add(R.id.dialtacts_container, new DialpadFragment(), TAG_DIALPAD_FRAGMENT);
ft.commit();
+ } else {
+ mSearchQuery = savedInstanceState.getString(KEY_SEARCH_QUERY);
+ mInSearchUi = savedInstanceState.getBoolean(KEY_IN_SEARCH_UI);
+ mFirstLaunch = savedInstanceState.getBoolean(KEY_FIRST_LAUNCH);
}
mBottomPaddingView = findViewById(R.id.dialtacts_bottom_padding);
@@ -275,21 +286,6 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
@Override
protected void onResume() {
super.onResume();
- final FragmentManager fm = getFragmentManager();
- mPhoneFavoriteFragment = (PhoneFavoriteFragment) fm.findFragmentByTag(
- TAG_FAVORITES_FRAGMENT);
- mDialpadFragment = (DialpadFragment) fm.findFragmentByTag(TAG_DIALPAD_FRAGMENT);
-
- mRegularSearchFragment = (SearchFragment) fm.findFragmentByTag(
- TAG_REGULAR_SEARCH_FRAGMENT);
- mRegularSearchFragment.setOnPhoneNumberPickerActionListener(
- mPhoneNumberPickerActionListener);
-
- mSmartDialSearchFragment = (SmartDialSearchFragment) fm.findFragmentByTag(
- TAG_SMARTDIAL_SEARCH_FRAGMENT);
- mSmartDialSearchFragment.setOnPhoneNumberPickerActionListener(
- mPhoneNumberPickerActionListener);
-
if (mFirstLaunch) {
displayFragment(getIntent());
}
@@ -297,15 +293,27 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
}
@Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString(KEY_SEARCH_QUERY, mSearchQuery);
+ outState.putBoolean(KEY_IN_SEARCH_UI, mInSearchUi);
+ outState.putBoolean(KEY_FIRST_LAUNCH, mFirstLaunch);
+ }
+
+ @Override
public void onAttachFragment(Fragment fragment) {
- if (fragment instanceof DialpadFragment || fragment instanceof SearchFragment
- || fragment instanceof SmartDialSearchFragment) {
+ if (fragment instanceof DialpadFragment) {
+ mDialpadFragment = (DialpadFragment) fragment;
final FragmentTransaction transaction = getFragmentManager().beginTransaction();
- transaction.hide(fragment);
+ transaction.hide(mDialpadFragment);
transaction.commit();
+ } else if (fragment instanceof SmartDialSearchFragment) {
+ mSmartDialSearchFragment = (SmartDialSearchFragment) fragment;
+ } else if (fragment instanceof SearchFragment) {
+ mRegularSearchFragment = (SearchFragment) fragment;
+ } else if (fragment instanceof PhoneFavoriteFragment) {
+ mPhoneFavoriteFragment = (PhoneFavoriteFragment) fragment;
}
- // TODO krelease: Save some kind of state here to show the appropriate fragment
- // based on the state of the dialer when it was last paused
}
@Override
@@ -440,7 +448,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
}
private void hideDialpadFragmentIfNecessary() {
- if (mDialpadFragment.isVisible()) {
+ if (mDialpadFragment != null && mDialpadFragment.isVisible()) {
hideDialpadFragment(true);
}
}
@@ -464,13 +472,20 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
mSearchViewContainer.animate().withLayer().alpha(0).translationY(-mSearchView.getHeight())
.setDuration(200).setListener(mHideListener);
+ if (mPhoneFavoriteFragment == null || mPhoneFavoriteFragment.getView() == null) {
+ mBottomPaddingView.setVisibility(View.VISIBLE);
+ return;
+ }
+
mPhoneFavoriteFragment.getView().animate().withLayer()
.translationY(-mSearchViewContainer.getHeight()).setDuration(200).setListener(
new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mBottomPaddingView.setVisibility(View.VISIBLE);
- mPhoneFavoriteFragment.getView().setTranslationY(0);
+ if (mPhoneFavoriteFragment.getView() != null) {
+ mPhoneFavoriteFragment.getView().setTranslationY(0);
+ }
}
});
} else {
@@ -479,11 +494,8 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
}
public void showSearchBar() {
- // If the favorites fragment hasn't been fully created before the dialpad fragment
- // is hidden (i.e. onResume), don't bother animating
- if (mPhoneFavoriteFragment == null || mPhoneFavoriteFragment.getView() == null) {
- return;
- }
+
+
mSearchViewContainer.animate().cancel();
mSearchViewContainer.setAlpha(0);
mSearchViewContainer.setTranslationY(-mSearchViewContainer.getHeight());
@@ -495,6 +507,12 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
}
});
+ // If the favorites fragment hasn't been fully created before the dialpad fragment
+ // is hidden (i.e. onResume), don't bother animating
+ if (mPhoneFavoriteFragment == null || mPhoneFavoriteFragment.getView() == null) {
+ mBottomPaddingView.setVisibility(View.GONE);
+ return;
+ }
mPhoneFavoriteFragment.getView().setTranslationY(-mSearchViewContainer.getHeight());
mPhoneFavoriteFragment.getView().animate().withLayer().translationY(0).setDuration(200)
.setListener(
@@ -591,19 +609,6 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
displayFragment(newIntent);
final String action = newIntent.getAction();
- if (mInSearchUi || (mRegularSearchFragment != null && mRegularSearchFragment.isVisible())) {
- exitSearchUi();
- }
-
- // TODO krelease: Handle onNewIntent for all other fragments
- /*
- *if (mViewPager.getCurrentItem() == TAB_INDEX_DIALER) { if (mDialpadFragment != null) {
- * mDialpadFragment.setStartedFromNewIntent(true); } else { Log.e(TAG,
- * "DialpadFragment isn't ready yet when the tab is already selected."); } } else if
- * (mViewPager.getCurrentItem() == TAB_INDEX_CALL_LOG) { if (mCallLogFragment != null) {
- * mCallLogFragment.configureScreenFromIntent(newIntent); } else { Log.e(TAG,
- * "CallLogFragment isn't ready yet when the tab is already selected."); } }
- */
invalidateOptionsMenu();
}
@@ -719,17 +724,34 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
/**
* Shows the search fragment
*/
- private void enterSearchUi(boolean smartDialSearch) {
+ private void enterSearchUi(boolean smartDialSearch, String query) {
+ if (DEBUG) {
+ Log.d(TAG, "Entering search UI - smart dial " + smartDialSearch);
+ }
+ final String tag = smartDialSearch ? TAG_SMARTDIAL_SEARCH_FRAGMENT :
+ TAG_REGULAR_SEARCH_FRAGMENT;
+
final FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
- transaction.hide(mPhoneFavoriteFragment);
- if (smartDialSearch) {
- transaction.show(mSmartDialSearchFragment);
+
+ SearchFragment fragment;
+
+ transaction.remove(mPhoneFavoriteFragment);
+ fragment = (SearchFragment) getFragmentManager().findFragmentByTag(tag);
+ if (fragment == null) {
+ if (smartDialSearch) {
+ fragment = new SmartDialSearchFragment();
+ } else {
+ fragment = new SearchFragment();
+ }
+ transaction.replace(R.id.dialtacts_frame, fragment, tag);
} else {
- transaction.show(mRegularSearchFragment);
+ transaction.attach(fragment);
}
- transaction.commit();
+ transaction.addToBackStack(null);
+ fragment.setQueryString(query, false);
+ transaction.commit();
mInSearchUi = true;
}
@@ -737,12 +759,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
* Hides the search fragment
*/
private void exitSearchUi() {
- final FragmentTransaction transaction = getFragmentManager().beginTransaction();
- transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
- transaction.hide(mRegularSearchFragment);
- transaction.hide(mSmartDialSearchFragment);
- transaction.show(mPhoneFavoriteFragment);
- transaction.commit();
+ getFragmentManager().popBackStack();
mInSearchUi = false;
}
@@ -756,7 +773,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
@Override
public void onBackPressed() {
- if (mDialpadFragment.isVisible()) {
+ if (mDialpadFragment != null && mDialpadFragment.isVisible()) {
hideDialpadFragment(true);
} else if (mInSearchUi) {
mSearchView.setText(null);
@@ -776,6 +793,17 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
final String normalizedQuery = SmartDialNameMatcher.normalizeNumber(query,
SmartDialNameMatcher.LATIN_SMART_DIAL_MAP);
if (!TextUtils.equals(mSearchView.getText(), normalizedQuery)) {
+ if (DEBUG) {
+ Log.d(TAG, "onDialpadQueryChanged - new query: " + query);
+ }
+ if (mDialpadFragment == null || !mDialpadFragment.isVisible()) {
+ // This callback can happen if the dialpad fragment is recreated because of
+ // activity destruction. In that case, don't update the search view because
+ // that would bring the user back to the search fragment regardless of the
+ // previous state of the application. Instead, just return here and let the
+ // fragment manager correctly figure out whatever fragment was last displayed.
+ return;
+ }
mSearchView.setText(normalizedQuery);
}
}
diff --git a/src/com/android/dialer/SearchFragment.java b/src/com/android/dialer/SearchFragment.java
index 54d29d43f..86cd87323 100644
--- a/src/com/android/dialer/SearchFragment.java
+++ b/src/com/android/dialer/SearchFragment.java
@@ -22,6 +22,7 @@ import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import com.android.contacts.common.list.ContactListItemView;
+import com.android.contacts.common.list.ContactEntryListAdapter;
import com.android.contacts.common.list.PhoneNumberPickerFragment;
import com.android.dialer.list.OnListFragmentScrolledListener;
@@ -53,6 +54,9 @@ public class SearchFragment extends PhoneNumberPickerFragment {
@Override
public void onStart() {
super.onStart();
+ if (isSearchMode()) {
+ getAdapter().setHasHeader(0, false);
+ }
getListView().setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
@@ -70,6 +74,9 @@ public class SearchFragment extends PhoneNumberPickerFragment {
protected void setSearchMode(boolean flag) {
super.setSearchMode(flag);
// This hides the "All contacts with phone numbers" header in the search fragment
- getAdapter().setHasHeader(0, false);
+ final ContactEntryListAdapter adapter = getAdapter();
+ if (adapter != null) {
+ adapter.setHasHeader(0, false);
+ }
}
}
diff --git a/src/com/android/dialer/list/SmartDialSearchFragment.java b/src/com/android/dialer/list/SmartDialSearchFragment.java
index 3c1e51343..492073fb5 100644
--- a/src/com/android/dialer/list/SmartDialSearchFragment.java
+++ b/src/com/android/dialer/list/SmartDialSearchFragment.java
@@ -15,62 +15,22 @@
*/
package com.android.dialer.list;
-import android.app.Activity;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
-import android.provider.ContactsContract.Directory;
import android.util.Log;
-import android.widget.AbsListView;
-import android.widget.AbsListView.OnScrollListener;
import com.android.contacts.common.list.ContactEntryListAdapter;
-import com.android.contacts.common.list.ContactListItemView;
-import com.android.contacts.common.list.PhoneNumberPickerFragment;
+import com.android.dialer.SearchFragment;
import com.android.dialer.dialpad.SmartDialCursorLoader;
/**
* Implements a fragment to load and display SmartDial search results.
*/
-public class SmartDialSearchFragment extends PhoneNumberPickerFragment {
+public class SmartDialSearchFragment extends SearchFragment {
private static final String TAG = SmartDialSearchFragment.class.getSimpleName();
- private OnListFragmentScrolledListener mActivityScrollListener;
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- setQuickContactEnabled(true);
- setDarkTheme(false);
- setPhotoPosition(ContactListItemView.getDefaultPhotoPosition(true /* opposite */));
- setUseCallableUri(true);
-
- try {
- mActivityScrollListener = (OnListFragmentScrolledListener) activity;
- } catch (ClassCastException e) {
- throw new ClassCastException(activity.toString()
- + " must implement OnListFragmentScrolledListener");
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- getListView().setOnScrollListener(new OnScrollListener() {
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- mActivityScrollListener.onListFragmentScrollStateChange(scrollState);
- }
-
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
- int totalItemCount) {
- }
- });
- }
-
/**
* Creates a SmartDialListAdapter to display and operate on search results.
*/
@@ -110,11 +70,4 @@ public class SmartDialSearchFragment extends PhoneNumberPickerFragment {
final SmartDialNumberListAdapter adapter = (SmartDialNumberListAdapter) getAdapter();
return adapter.getDataUri(position);
}
-
- @Override
- protected void setSearchMode(boolean flag) {
- super.setSearchMode(flag);
- // This hides the "All contacts with phone numbers" header in the search fragment
- getAdapter().setHasHeader(0, false);
- }
}