diff options
-rw-r--r-- | res/values/dimens.xml | 1 | ||||
-rw-r--r-- | src/com/android/dialer/DialtactsActivity.java | 84 | ||||
-rw-r--r-- | src/com/android/dialer/widget/FloatingActionButtonController.java | 212 |
3 files changed, 70 insertions, 227 deletions
diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 2869c62f4..5cf216c7e 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -38,7 +38,6 @@ <!-- Match call_button_height to Phone's dimens/in_call_end_button_height --> <dimen name="call_button_height">74dp</dimen> - <dimen name="floating_action_button_dialpad_margin_bottom_offset">4dp</dimen> <!-- Dimensions for speed dial tiles --> <dimen name="contact_tile_divider_width">1dp</dimen> diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java index 922b38351..309f12ac6 100644 --- a/src/com/android/dialer/DialtactsActivity.java +++ b/src/com/android/dialer/DialtactsActivity.java @@ -72,6 +72,7 @@ import com.android.contacts.common.dialog.ClearFrequentsDialog; import com.android.contacts.common.interactions.ImportExportDialogFragment; import com.android.contacts.common.list.OnPhoneNumberPickerActionListener; import com.android.contacts.common.util.ViewUtil; +import com.android.contacts.common.widget.FloatingActionButtonController; import com.android.dialer.calllog.CallLogActivity; import com.android.dialer.database.DialerDatabaseHelper; import com.android.dialer.dialpad.DialpadFragment; @@ -89,7 +90,6 @@ import com.android.dialer.list.RemoveView; import com.android.dialer.list.SearchFragment; import com.android.dialer.list.SmartDialSearchFragment; import com.android.dialer.widget.ActionBarController; -import com.android.dialer.widget.FloatingActionButtonController; import com.android.dialer.widget.SearchEditTextLayout; import com.android.dialer.widget.SearchEditTextLayout.OnBackButtonClickedListener; import com.android.dialerbind.DatabaseHelperManager; @@ -234,7 +234,15 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O private DialerDatabaseHelper mDialerDatabaseHelper; private DragDropController mDragDropController; private ActionBarController mActionBarController; + + private String mDescriptionDialButtonStr; + private String mActionMenuDialpadButtonStr; + private ImageButton mFloatingActionButton; private FloatingActionButtonController mFloatingActionButtonController; + /** + * Additional offset for FAB to be lowered when dialpad is open. + */ + private int mFloatingActionButtonDialpadMarginBottomOffset; private int mActionBarHeight; @@ -350,6 +358,8 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O final Resources resources = getResources(); mActionBarHeight = resources.getDimensionPixelSize(R.dimen.action_bar_height); + mDescriptionDialButtonStr = resources.getString(R.string.description_dial_button); + mActionMenuDialpadButtonStr = resources.getString(R.string.action_menu_dialpad_button); setContentView(R.layout.dialtacts_activity); getWindow().setBackgroundDrawable(null); @@ -377,13 +387,18 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O } }); - boolean mIsLandscape = getResources().getConfiguration().orientation + mIsLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; - View floatingActionButtonContainer = findViewById(R.id.floating_action_button_container); - ImageButton floatingActionButton = (ImageButton) findViewById(R.id.floating_action_button); - floatingActionButton.setOnClickListener(this); - mFloatingActionButtonController = new FloatingActionButtonController(this, mIsLandscape, + final View floatingActionButtonContainer = findViewById( + R.id.floating_action_button_container); + mFloatingActionButton = (ImageButton) findViewById(R.id.floating_action_button); + int floatingActionButtonWidth = resources.getDimensionPixelSize( + R.dimen.floating_action_button_width); + mFloatingActionButton.setOnClickListener(this); + mFloatingActionButtonController = new FloatingActionButtonController(this, floatingActionButtonContainer); + mFloatingActionButtonDialpadMarginBottomOffset = resources.getDimensionPixelOffset( + R.dimen.floating_action_button_dialpad_margin_bottom_offset); ImageButton optionsMenuButton = (ImageButton) mSearchEditTextLayout.findViewById( R.id.dialtacts_options_menu_button); @@ -405,7 +420,6 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O mFirstLaunch = savedInstanceState.getBoolean(KEY_FIRST_LAUNCH); mShowDialpadOnResume = savedInstanceState.getBoolean(KEY_IS_DIALPAD_SHOWN); mActionBarController.restoreInstanceState(savedInstanceState); - mFloatingActionButtonController.restoreInstanceState(savedInstanceState); } mSlideIn = AnimationUtils.loadAnimation(this, @@ -418,13 +432,19 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O parentLayout = (RelativeLayout) findViewById(R.id.dialtacts_mainlayout); parentLayout.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING); parentLayout.setOnDragListener(new LayoutOnDragListener()); - parentLayout.getViewTreeObserver().addOnGlobalLayoutListener( + floatingActionButtonContainer.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { + final ViewTreeObserver observer = floatingActionButtonContainer + .getViewTreeObserver(); + if (!observer.isAlive()) { + return; + } + observer.removeOnGlobalLayoutListener(this); int screenWidth = parentLayout.getWidth(); mFloatingActionButtonController.setScreenWidth(screenWidth); - parentLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); + updateFloatingActionButtonControllerAlignment(false /* animate */); } }); @@ -464,6 +484,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O mFirstLaunch = false; prepareVoiceSearchButton(); mDialerDatabaseHelper.startSmartDialUpdateThread(); + updateFloatingActionButtonControllerAlignment(false /* animate */); } @Override @@ -484,7 +505,6 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O outState.putBoolean(KEY_FIRST_LAUNCH, mFirstLaunch); outState.putBoolean(KEY_IS_DIALPAD_SHOWN, mIsDialpadShown); mActionBarController.saveInstanceState(outState); - mFloatingActionButtonController.saveInstanceState(outState); } @Override @@ -635,7 +655,9 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O * Callback from child DialpadFragment when the dialpad is shown. */ public void onDialpadShown() { - mFloatingActionButtonController.updateByDialpadVisibility(true); + mFloatingActionButton.setImageResource(R.drawable.fab_ic_call); + mFloatingActionButton.setContentDescription(mDescriptionDialButtonStr); + updateFloatingActionButtonControllerAlignment(mDialpadFragment.getAnimate()); if (mDialpadFragment.getAnimate()) { mDialpadFragment.getView().startAnimation(mSlideIn); } else { @@ -664,7 +686,10 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O mDialpadFragment.setAnimate(animate); updateSearchFragmentPosition(); - mFloatingActionButtonController.updateByDialpadVisibility(false); + mFloatingActionButton.setImageResource(R.drawable.fab_ic_dial); + mFloatingActionButton.setContentDescription(mActionMenuDialpadButtonStr); + + updateFloatingActionButtonControllerAlignment(animate); if (animate) { mDialpadFragment.getView().startAnimation(mSlideOut); } else { @@ -1096,13 +1121,23 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - mFloatingActionButtonController.onPageScrolled(position, positionOffset); + // Only scroll the button when the first tab is selected. The button should scroll from + // the middle to right position only on the transition from the first tab to the second + // tab. + if (position == ListsFragment.TAB_INDEX_SPEED_DIAL) { + mFloatingActionButtonController.onPageScrolled(positionOffset); + } } @Override public void onPageSelected(int position) { mCurrentTabPosition = position; - mFloatingActionButtonController.updateByTab(position); + // Prevents jittery movement when clicking on tabs. + if (mCurrentTabPosition != ListsFragment.TAB_INDEX_SPEED_DIAL) { + mFloatingActionButtonController.manuallyTranslate( + mFloatingActionButtonController.getTranslationXForAlignment( + FloatingActionButtonController.ALIGN_RIGHT), 0); + } } @Override @@ -1136,4 +1171,25 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O public void setActionBarHideOffset(int hideOffset) { getActionBar().setHideOffset(hideOffset); } + + /** + * Updates controller based on currently known information. + * + * @param animate Whether or not to animate the transition. + */ + private void updateFloatingActionButtonControllerAlignment(boolean animate) { + int align; + if (mIsDialpadShown) { + align = mIsLandscape ? FloatingActionButtonController.ALIGN_QUARTER_RIGHT + : FloatingActionButtonController.ALIGN_MIDDLE; + } else { + align = mCurrentTabPosition == ListsFragment.TAB_INDEX_SPEED_DIAL + ? FloatingActionButtonController.ALIGN_MIDDLE + : FloatingActionButtonController.ALIGN_RIGHT; + } + mFloatingActionButtonController.align(align, + 0 /* offsetX */, + mIsDialpadShown ? mFloatingActionButtonDialpadMarginBottomOffset : 0 /* offsetY */, + animate); + } } diff --git a/src/com/android/dialer/widget/FloatingActionButtonController.java b/src/com/android/dialer/widget/FloatingActionButtonController.java deleted file mode 100644 index 3f59153ef..000000000 --- a/src/com/android/dialer/widget/FloatingActionButtonController.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 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.app.Activity; -import android.content.res.Resources; -import android.os.Bundle; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; -import android.view.View; -import android.widget.ImageButton; - -import com.android.contacts.common.util.ViewUtil; -import com.android.dialer.R; -import com.android.dialer.list.ListsFragment; - -/** - * Controls the movement and appearance of the FAB. - */ -public class FloatingActionButtonController { - private static final String KEY_IS_DIALPAD_VISIBLE = "key_is_dialpad_visible"; - private static final String KEY_CURRENT_TAB_POSITION = "key_current_tab_position"; - private static final int ANIMATION_DURATION = 250; - - private int mScreenWidth; - - private int mCurrentTabPosition; - - private ImageButton mFloatingActionButton; - private View mFloatingActionButtonContainer; - - private boolean mIsLandscape; - private boolean mIsDialpadVisible; - private boolean mAnimateFloatingActionButton; - - private String mDescriptionDialButtonStr; - private String mActionMenuDialpadButtonStr; - - /** - * Interpolator for FAB animations. - */ - private Interpolator mFabInterpolator; - - /** - * Additional offset for FAB to be lowered when dialpad is open. - */ - private int mFloatingActionButtonDialpadMarginBottomOffset; - - public FloatingActionButtonController(Activity activity, boolean isLandscape, - View container) { - Resources resources = activity.getResources(); - mIsLandscape = isLandscape; - mFabInterpolator = AnimationUtils.loadInterpolator(activity, - android.R.interpolator.fast_out_slow_in); - mFloatingActionButtonDialpadMarginBottomOffset = resources.getDimensionPixelOffset( - R.dimen.floating_action_button_dialpad_margin_bottom_offset); - mFloatingActionButton = (ImageButton) activity. - findViewById(R.id.floating_action_button); - mDescriptionDialButtonStr = resources.getString(R.string.description_dial_button); - mActionMenuDialpadButtonStr = resources.getString(R.string.action_menu_dialpad_button); - mFloatingActionButtonContainer = container; - ViewUtil.setupFloatingActionButton(mFloatingActionButtonContainer, resources); - } - - /** - * Passes the screen width into the class. Necessary for translation calculations. - * - * @param screenWidth the width of the screen - */ - public void setScreenWidth(int screenWidth) { - mScreenWidth = screenWidth; - updateByDialpadVisibility(mIsDialpadVisible); - } - - public void setVisible(boolean visible) { - mFloatingActionButtonContainer.setVisibility(visible ? View.VISIBLE : View.GONE); - } - - /** - * Updates the FAB location (middle to right position) as the PageView scrolls. - * - * @param position tab position to align for - * @param positionOffset a fraction used to calculate position of the FAB during page scroll - */ - public void onPageScrolled(int position, float positionOffset) { - // As the page is scrolling, if we're on the first tab, update the FAB position so it - // moves along with it. - if (position == ListsFragment.TAB_INDEX_SPEED_DIAL) { - mFloatingActionButtonContainer.setTranslationX( - (int) (positionOffset * (mScreenWidth / 2f - - mFloatingActionButton.getWidth()))); - mFloatingActionButtonContainer.setTranslationY(0); - } - } - - /** - * Updates the FAB location given a tab position. - * - * @param position tab position to align for - */ - public void updateByTab(int position) { - // If the screen width hasn't been set yet, don't do anything. - if (mScreenWidth == 0 || mIsDialpadVisible) return; - alignFloatingActionButtonByTab(position, false); - mAnimateFloatingActionButton = true; - } - - /** - * Updates the FAB location to the proper location given whether or not the dialer is open. - * - * @param dialpadVisible whether or not the dialpad is currently open - */ - public void updateByDialpadVisibility(boolean dialpadVisible) { - // If the screen width hasn't been set yet, don't do anything. - if (mScreenWidth == 0) return; - mIsDialpadVisible = dialpadVisible; - - moveFloatingActionButton(mAnimateFloatingActionButton); - mAnimateFloatingActionButton = true; - } - - /** - * Moves the FAB to the best known location given what the class currently knows. - * - * @param animate whether or not to smoothly animate the button - */ - private void moveFloatingActionButton(boolean animate) { - if (mIsDialpadVisible) { - mFloatingActionButton.setImageResource(R.drawable.fab_ic_call); - mFloatingActionButton.setContentDescription(mDescriptionDialButtonStr); - alignFloatingActionButton(animate); - } else { - mFloatingActionButton.setImageResource(R.drawable.fab_ic_dial); - mFloatingActionButton.setContentDescription(mActionMenuDialpadButtonStr); - alignFloatingActionButtonByTab(mCurrentTabPosition, mAnimateFloatingActionButton); - } - } - - /** - * Aligns the FAB to the position for the indicated tab. - * - * @param position tab position to align for - * @param animate whether or not to smoothly animate the button - */ - private void alignFloatingActionButtonByTab(int position, boolean animate) { - mCurrentTabPosition = position; - alignFloatingActionButton(animate); - } - - /** - * Aligns the FAB to the correct position. - * - * @param animate whether or not to smoothly animate the button - */ - private void alignFloatingActionButton(boolean animate) { - int translationX = calculateTranslationX(); - int translationY = mIsDialpadVisible ? mFloatingActionButtonDialpadMarginBottomOffset : 0; - if (animate) { - mFloatingActionButtonContainer.animate() - .translationX(translationX) - .translationY(translationY) - .setInterpolator(mFabInterpolator) - .setDuration(ANIMATION_DURATION).start(); - } else { - mFloatingActionButtonContainer.setTranslationX(translationX); - mFloatingActionButtonContainer.setTranslationY(translationY); - } - } - - /** - * Calculates the translationX distance for the FAB. - */ - private int calculateTranslationX() { - if (mIsDialpadVisible) { - return mIsLandscape ? mScreenWidth / 4 : 0; - } - if (mCurrentTabPosition == ListsFragment.TAB_INDEX_SPEED_DIAL) { - return 0; - } - return mScreenWidth / 2 - mFloatingActionButton.getWidth(); - } - - /** - * Saves the current state of the floating action button into a provided {@link Bundle} - */ - public void saveInstanceState(Bundle outState) { - outState.putBoolean(KEY_IS_DIALPAD_VISIBLE, mIsDialpadVisible); - outState.putInt(KEY_CURRENT_TAB_POSITION, mCurrentTabPosition); - } - - /** - * Restores the floating action button state from a provided {@link Bundle} - */ - public void restoreInstanceState(Bundle inState) { - mIsDialpadVisible = inState.getBoolean(KEY_IS_DIALPAD_VISIBLE); - mCurrentTabPosition = inState.getInt(KEY_CURRENT_TAB_POSITION); - } -} |