From c4969ea3d2ac04f58f0caccef709bc95a182c378 Mon Sep 17 00:00:00 2001 From: Sai Cheemalapati Date: Wed, 4 Jun 2014 16:35:16 -0700 Subject: Moving FAB logic to ContactsCommon. Moved FAB to ContactsCommon. Cleaned up FAB Controller. Replaced implementation of FAB in InCallUI with controller. Prevented animations from happening again in InCallUI on orientaton change. FAB also repositions correctly on orientation change in InCallUI. Bug: 15386162 Change-Id: Ibc1739a54f236939db29cab350233275099a4446 --- res/values/dimens.xml | 1 - src/com/android/dialer/DialtactsActivity.java | 84 ++++++-- .../widget/FloatingActionButtonController.java | 212 --------------------- 3 files changed, 70 insertions(+), 227 deletions(-) delete mode 100644 src/com/android/dialer/widget/FloatingActionButtonController.java 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 @@ 74dp - 4dp 1dp 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); - } -} -- cgit v1.2.3