From b19038436ce8e4683eb19af02255eda9969a6a94 Mon Sep 17 00:00:00 2001 From: Andrew Lee Date: Thu, 15 May 2014 16:11:24 -0700 Subject: Open search ui on touch, and handle related scenarios. - Add a touch listener to enter the search ui when the user touches the search bar. - Add a key listener to exit the search ui if the user closes the keyboard while the text input is empty. SearchEditTextLayout was added to facilitate this.. - Get rid of mFragmentsFrame, and control visibility of the favorites view by adjusting the alpha of the lists framgent instead, - Delete (hack) logic to change the background color. - Enter the search ui whenever the dialpad is shown, and exit if it is hidden and there is no query. - Handle showing/hiding the actionbar depending on whether the overlapping panel is displayed. This solution is a little hack, but what seems to be a weird frameowrk interaction prevents the desired solution of showing the action bar and then updating the hide offset. Bug: 14900155 Change-Id: I4e06e4ed8eae49ef48317c99a556c51ff2a206a5 --- src/com/android/dialer/DialtactsActivity.java | 128 +++++++++++++-------- src/com/android/dialer/list/ListsFragment.java | 17 +++ .../dialer/widget/SearchEditTextLayout.java | 45 ++++++++ 3 files changed, 140 insertions(+), 50 deletions(-) create mode 100644 src/com/android/dialer/widget/SearchEditTextLayout.java (limited to 'src') diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java index a3d7e5009..8fa4ae66c 100644 --- a/src/com/android/dialer/DialtactsActivity.java +++ b/src/com/android/dialer/DialtactsActivity.java @@ -40,12 +40,13 @@ import android.telephony.TelephonyManager; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; -import android.util.AttributeSet; import android.util.Log; import android.view.DragEvent; +import android.view.KeyEvent; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.View.OnDragListener; import android.view.animation.AccelerateInterpolator; @@ -84,6 +85,7 @@ import com.android.dialer.list.RegularSearchFragment; import com.android.dialer.list.RemoveView; import com.android.dialer.list.SearchFragment; import com.android.dialer.list.SmartDialSearchFragment; +import com.android.dialer.widget.SearchEditTextLayout; import com.android.dialerbind.DatabaseHelperManager; import com.android.internal.telephony.ITelephony; @@ -160,13 +162,12 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O private View mFloatingActionButtonContainer; private ImageButton mFloatingActionButton; - private View mFragmentsFrame; - private int mActionBarHeight; private boolean mInDialpadSearch; private boolean mInRegularSearch; private boolean mClearSearchOnPause; private boolean mIsDialpadShown; + private boolean mIsExitingSearch; /** * The position of the currently selected tab in the attached {@link ListsFragment}. @@ -206,9 +207,6 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O private DialerDatabaseHelper mDialerDatabaseHelper; private DragDropController mDragDropController; - private int mDialerBackgroundColor; - private int mContactListBackgroundColor; - private class OverflowPopupMenu extends PopupMenu { public OverflowPopupMenu(Context context, View anchor) { super(context, anchor); @@ -267,13 +265,13 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O if (!sameSearchMode) { // call enterSearchUi only if we are switching search modes, or entering // search ui for the first time - enterSearchUi(mIsDialpadShown, newText); + enterSearchUi(mIsDialpadShown, mSearchQuery); } if (mIsDialpadShown && mSmartDialSearchFragment != null) { - mSmartDialSearchFragment.setQueryString(newText, false /* delaySelection */); + mSmartDialSearchFragment.setQueryString(mSearchQuery, false /* delaySelection */); } else if (mRegularSearchFragment != null) { - mRegularSearchFragment.setQueryString(newText, false /* delaySelection */); + mRegularSearchFragment.setQueryString(mSearchQuery, false /* delaySelection */); } if (TextUtils.isEmpty(newText)) { @@ -290,6 +288,34 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O } }; + + /** + * Open the search UI when the user touches the search text view. + */ + private final View.OnTouchListener mSearchViewOnTouchListener = new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (!isInSearchUi()) { + enterSearchUi(false /* smartDialSearch */, mSearchView.getText().toString()); + } + return false; + } + }; + + /** + * If the search term is empty and the user closes the soft keyboard, close the search UI. + */ + private final View.OnKeyListener mSearchEditTextLayoutListener = new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN && + TextUtils.isEmpty(mSearchView.getText().toString())) { + onBackPressed(); + } + return false; + } + }; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -302,12 +328,15 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O actionBar.setCustomView(R.layout.search_edittext); actionBar.setDisplayShowCustomEnabled(true); - final View customView = actionBar.getCustomView(); + SearchEditTextLayout actionBarView = (SearchEditTextLayout) actionBar.getCustomView(); + actionBarView.setPreImeKeyListener(mSearchEditTextLayoutListener); - mSearchView = (EditText) customView.findViewById(R.id.search_view); + mSearchView = (EditText) actionBarView.findViewById(R.id.search_view); mSearchView.addTextChangedListener(mPhoneSearchQueryTextListener); + mSearchView.setOnTouchListener(mSearchViewOnTouchListener); + - mSearchViewCloseButton = customView.findViewById(R.id.search_close_button); + mSearchViewCloseButton = actionBarView.findViewById(R.id.search_close_button); mSearchViewCloseButton.setOnClickListener(this); final TypedArray styledAttributes = getTheme().obtainStyledAttributes( @@ -333,12 +362,6 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O parentLayout.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING); parentLayout.setOnDragListener(new LayoutOnDragListener()); - mDialerBackgroundColor = getResources().getColor(R.color.background_dialer_light); - mContactListBackgroundColor = - getResources().getColor(R.color.contact_list_background_color); - - mFragmentsFrame = findViewById(R.id.dialtacts_frame); - mFloatingActionButtonContainer = findViewById(R.id.floating_action_button_container); ViewUtil.setupFloatingActionButton(mFloatingActionButtonContainer, getResources()); @@ -393,17 +416,9 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O } else if (fragment instanceof SmartDialSearchFragment) { mSmartDialSearchFragment = (SmartDialSearchFragment) fragment; mSmartDialSearchFragment.setOnPhoneNumberPickerActionListener(this); - mSmartDialSearchFragment.setShowEmptyListForNullQuery(true); - if (mFragmentsFrame != null) { - mFragmentsFrame.setAlpha(1.0f); - } } else if (fragment instanceof SearchFragment) { mRegularSearchFragment = (RegularSearchFragment) fragment; mRegularSearchFragment.setOnPhoneNumberPickerActionListener(this); - mRegularSearchFragment.setShowEmptyListForNullQuery(true); - if (mFragmentsFrame != null) { - mFragmentsFrame.setAlpha(1.0f); - } } else if (fragment instanceof ListsFragment) { mListsFragment = (ListsFragment) fragment; mListsFragment.addOnPageChangeListener(this); @@ -524,6 +539,10 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O final FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.show(mDialpadFragment); ft.commit(); + + if (!isInSearchUi()) { + enterSearchUi(true /* isSmartDial */, mSearchQuery); + } } /** @@ -538,12 +557,6 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O mDialpadFragment.setYFraction(0); } - if (mListsFragment != null && mListsFragment.isResumed() && mListsFragment.isVisible()) { - // If the favorites fragment is showing, fade to blank. - mFragmentsFrame.animate().alpha(0.0f); - parentLayout.setBackgroundColor(mContactListBackgroundColor); - } - updateSearchFragmentPosition(); getActionBar().hide(); } @@ -580,13 +593,8 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O commitDialpadFragmentHide(); } - if (mListsFragment != null && mListsFragment.isVisible()) { - mFragmentsFrame.animate().alpha(1.0f); - parentLayout.setBackgroundColor(mDialerBackgroundColor); - } - updateSearchFragmentPosition(); - getActionBar().show(); + mListsFragment.maybeShowActionBar(); } /** @@ -612,7 +620,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O } } - private boolean getInSearchUi() { + private boolean isInSearchUi() { return mInDialpadSearch || mInRegularSearch; } @@ -745,7 +753,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O * Shows the search fragment */ private void enterSearchUi(boolean smartDialSearch, String query) { - if (getFragmentManager().isDestroyed()) { + if (getFragmentManager().isDestroyed() || mIsExitingSearch) { // Weird race condition where fragment is doing work after the activity is destroyed // due to talkback being on (b/10209937). Just return since we can't do any // constructive here. @@ -773,19 +781,25 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O mInRegularSearch = !smartDialSearch; SearchFragment fragment = (SearchFragment) getFragmentManager().findFragmentByTag(tag); + transaction.setCustomAnimations(android.R.animator.fade_in, 0); if (fragment == null) { if (smartDialSearch) { fragment = new SmartDialSearchFragment(); } else { fragment = new RegularSearchFragment(); } + transaction.add(R.id.dialtacts_frame, fragment, tag); + } else { + transaction.show(fragment); } + // DialtactsActivity will provide the options menu fragment.setHasOptionsMenu(false); - transaction.replace(R.id.dialtacts_frame, fragment, tag); - transaction.addToBackStack(null); + fragment.setShowEmptyListForNullQuery(true); fragment.setQueryString(query, false /* delaySelection */); transaction.commit(); + + mListsFragment.getView().animate().alpha(0).withLayer(); } /** @@ -796,14 +810,27 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O if (getFragmentManager().isDestroyed()) { return; } - // Go all the way back to the favorites fragment, regardless of how many times we - // transitioned between search fragments - getFragmentManager().popBackStack(0, FragmentManager.POP_BACK_STACK_INCLUSIVE); + + mIsExitingSearch = true; + + mSearchView.setText(null); + mDialpadFragment.clearDialpad(); setNotInSearchUi(); - if (mIsDialpadShown) { - mFragmentsFrame.setAlpha(0); + final FragmentTransaction transaction = getFragmentManager().beginTransaction(); + transaction.setCustomAnimations(0, android.R.animator.fade_out); + + if (mSmartDialSearchFragment != null) { + transaction.remove(mSmartDialSearchFragment); + } + if (mRegularSearchFragment != null) { + transaction.remove(mRegularSearchFragment); } + transaction.commit(); + + mListsFragment.getView().animate().alpha(1).withLayer(); + + mIsExitingSearch = false; } /** Returns an Intent to launch Call Settings screen */ @@ -817,10 +844,11 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O @Override public void onBackPressed() { if (mIsDialpadShown) { + if (TextUtils.isEmpty(mSearchQuery)) { + exitSearchUi(); + } hideDialpadFragment(true, false); - } else if (getInSearchUi()) { - mSearchView.setText(null); - mDialpadFragment.clearDialpad(); + } else if (isInSearchUi()) { exitSearchUi(); } else { super.onBackPressed(); diff --git a/src/com/android/dialer/list/ListsFragment.java b/src/com/android/dialer/list/ListsFragment.java index 18fa531c0..250706561 100644 --- a/src/com/android/dialer/list/ListsFragment.java +++ b/src/com/android/dialer/list/ListsFragment.java @@ -89,6 +89,8 @@ public class ListsFragment extends Fragment implements CallLogQueryHandler.Liste private CallLogAdapter mCallLogAdapter; private CallLogQueryHandler mCallLogQueryHandler; + private boolean mIsPanelOpen = true; + /** * Call shortcuts older than this date (persisted in shared preferences) will not show up in * at the top of the screen @@ -143,15 +145,21 @@ public class ListsFragment extends Fragment implements CallLogQueryHandler.Liste final int availableActionBarHeight = Math.min(mActionBar.getHeight(), topPaneHeight); mActionBar.setHideOffset(mActionBar.getHeight() - availableActionBarHeight); + + if (!mActionBar.isShowing()) { + mActionBar.show(); + } } } @Override public void onPanelOpened(View panel) { + mIsPanelOpen = true; } @Override public void onPanelClosed(View panel) { + mIsPanelOpen = false; } }; @@ -335,6 +343,15 @@ public class ListsFragment extends Fragment implements CallLogQueryHandler.Liste } } + public void maybeShowActionBar() { + // TODO: Try to show the action bar regardless of whether the panel is open, and then update + // the offset to show/hide the action bar, instead of updating the whether the action bar is + // shown in onPanelSlide. + if (mIsPanelOpen) { + mActionBar.show(); + } + } + private void setupPaneLayout(OverlappingPaneLayout paneLayout) { // TODO: Remove the notion of a capturable view. The entire view be slideable, once // the framework better supports nested scrolling. diff --git a/src/com/android/dialer/widget/SearchEditTextLayout.java b/src/com/android/dialer/widget/SearchEditTextLayout.java new file mode 100644 index 000000000..40a4e43b9 --- /dev/null +++ b/src/com/android/dialer/widget/SearchEditTextLayout.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014 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.dialer.widget; + + +import android.content.Context; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.widget.LinearLayout; + +public class SearchEditTextLayout extends LinearLayout { + private OnKeyListener mPreImeKeyListener; + + public SearchEditTextLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setPreImeKeyListener(OnKeyListener listener) { + mPreImeKeyListener = listener; + } + + @Override + public boolean dispatchKeyEventPreIme(KeyEvent event) { + if (mPreImeKeyListener != null) { + if (mPreImeKeyListener.onKey(this, event.getKeyCode(), event)) { + return true; + } + } + return super.dispatchKeyEventPreIme(event); + } +} \ No newline at end of file -- cgit v1.2.3