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
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index 922b383..309f12a 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -72,6 +72,7 @@
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.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 @@
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 @@
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 @@
}
});
- 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 @@
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 @@
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 @@
mFirstLaunch = false;
prepareVoiceSearchButton();
mDialerDatabaseHelper.startSmartDialUpdateThread();
+ updateFloatingActionButtonControllerAlignment(false /* animate */);
}
@Override
@@ -484,7 +505,6 @@
outState.putBoolean(KEY_FIRST_LAUNCH, mFirstLaunch);
outState.putBoolean(KEY_IS_DIALPAD_SHOWN, mIsDialpadShown);
mActionBarController.saveInstanceState(outState);
- mFloatingActionButtonController.saveInstanceState(outState);
}
@Override
@@ -635,7 +655,9 @@
* 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 @@
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 @@
@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 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 3f59153..0000000
--- 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);
- }
-}