summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--res/values/dimens.xml2
-rw-r--r--src/com/android/dialer/DialtactsActivity.java112
-rw-r--r--src/com/android/dialer/widget/FloatingActionButtonController.java212
3 files changed, 245 insertions, 81 deletions
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 416c3138d..b45e3b00b 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -38,7 +38,7 @@
<!-- 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">12dp</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 4ea9651d5..922b38351 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -48,6 +48,7 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewTreeObserver;
import android.view.View.OnDragListener;
import android.view.View.OnTouchListener;
import android.view.animation.AccelerateInterpolator;
@@ -88,6 +89,7 @@ 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;
@@ -180,18 +182,10 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
};
/**
- * Set to true if the device is in landscape orientation.
- */
- private boolean mIsLandscape;
-
- /**
* Fragment containing the speed dial list, recents list, and all contacts list.
*/
private ListsFragment mListsFragment;
- private View mFloatingActionButtonContainer;
- private ImageButton mFloatingActionButton;
-
private boolean mInDialpadSearch;
private boolean mInRegularSearch;
private boolean mClearSearchOnPause;
@@ -199,6 +193,11 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
private boolean mShowDialpadOnResume;
/**
+ * Whether or not the device is in landscape orientation.
+ */
+ private boolean mIsLandscape;
+
+ /**
* The position of the currently selected tab in the attached {@link ListsFragment}.
*/
private int mCurrentTabPosition = 0;
@@ -235,10 +234,9 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
private DialerDatabaseHelper mDialerDatabaseHelper;
private DragDropController mDragDropController;
private ActionBarController mActionBarController;
+ private FloatingActionButtonController mFloatingActionButtonController;
private int mActionBarHeight;
- private int mFloatingActionButtonMarginBottom;
- private int mFloatingActionButtonDialpadMarginBottom;
private class OptionsPopupMenu extends PopupMenu {
public OptionsPopupMenu(Context context, View anchor) {
@@ -352,10 +350,6 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
final Resources resources = getResources();
mActionBarHeight = resources.getDimensionPixelSize(R.dimen.action_bar_height);
- mFloatingActionButtonMarginBottom = resources.getDimensionPixelOffset(
- R.dimen.floating_action_button_margin_bottom);
- mFloatingActionButtonDialpadMarginBottom = resources.getDimensionPixelOffset(
- R.dimen.floating_action_button_dialpad_margin_bottom);
setContentView(R.layout.dialtacts_activity);
getWindow().setBackgroundDrawable(null);
@@ -383,6 +377,14 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
}
});
+ boolean 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,
+ floatingActionButtonContainer);
+
ImageButton optionsMenuButton = (ImageButton) mSearchEditTextLayout.findViewById(
R.id.dialtacts_options_menu_button);
optionsMenuButton.setOnClickListener(this);
@@ -403,9 +405,8 @@ 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);
}
- mIsLandscape = getResources().getConfiguration().orientation ==
- Configuration.ORIENTATION_LANDSCAPE;
mSlideIn = AnimationUtils.loadAnimation(this,
mIsLandscape ? R.anim.slide_in_right : R.anim.slide_in);
@@ -417,15 +418,18 @@ 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(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ int screenWidth = parentLayout.getWidth();
+ mFloatingActionButtonController.setScreenWidth(screenWidth);
+ parentLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ });
setupActivityOverlay();
- mFloatingActionButtonContainer = findViewById(R.id.floating_action_button_container);
- ViewUtil.setupFloatingActionButton(mFloatingActionButtonContainer, getResources());
-
- mFloatingActionButton = (ImageButton) findViewById(R.id.floating_action_button);
- mFloatingActionButton.setOnClickListener(this);
-
mRemoveViewContainer = findViewById(R.id.remove_view_container);
mDialerDatabaseHelper = DatabaseHelperManager.getDatabaseHelper(this);
@@ -480,6 +484,7 @@ 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
@@ -630,7 +635,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
* Callback from child DialpadFragment when the dialpad is shown.
*/
public void onDialpadShown() {
- updateFloatingActionButton();
+ mFloatingActionButtonController.updateByDialpadVisibility(true);
if (mDialpadFragment.getAnimate()) {
mDialpadFragment.getView().startAnimation(mSlideIn);
} else {
@@ -659,7 +664,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
mDialpadFragment.setAnimate(animate);
updateSearchFragmentPosition();
- updateFloatingActionButton();
+ mFloatingActionButtonController.updateByDialpadVisibility(false);
if (animate) {
mDialpadFragment.getView().startAnimation(mSlideOut);
} else {
@@ -993,7 +998,7 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
@Override
public void setFloatingActionButtonVisible(boolean visible) {
- mFloatingActionButtonContainer.setVisibility(visible ? View.VISIBLE : View.GONE);
+ mFloatingActionButtonController.setVisible(visible);
}
private boolean phoneIsInUse() {
@@ -1091,72 +1096,19 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
-
+ mFloatingActionButtonController.onPageScrolled(position, positionOffset);
}
@Override
public void onPageSelected(int position) {
mCurrentTabPosition = position;
- // If the dialpad is showing, the floating action button should always be middle aligned.
- if (!mIsDialpadShown) {
- alignFloatingActionButtonByTab(mCurrentTabPosition);
- }
+ mFloatingActionButtonController.updateByTab(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
- private void updateFloatingActionButton() {
- if (mIsDialpadShown) {
- mFloatingActionButton.setImageResource(R.drawable.fab_ic_call);
- mFloatingActionButton.setContentDescription(
- getResources().getString(R.string.description_dial_button));
- alignFloatingActionButtonMiddle();
- } else {
- mFloatingActionButton.setImageResource(R.drawable.fab_ic_dial);
- mFloatingActionButton.setContentDescription(
- getResources().getString(R.string.action_menu_dialpad_button));
- alignFloatingActionButtonByTab(mCurrentTabPosition);
- }
- }
-
- private void alignFloatingActionButtonByTab(int position) {
- if (position == ListsFragment.TAB_INDEX_SPEED_DIAL) {
- alignFloatingActionButtonMiddle();
- } else {
- alignFloatingActionButtonRight();
- }
- }
-
- private void alignFloatingActionButtonRight() {
- final RelativeLayout.LayoutParams params =
- (RelativeLayout.LayoutParams) mFloatingActionButtonContainer.getLayoutParams();
- params.removeRule(RelativeLayout.CENTER_HORIZONTAL);
- params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
- updateFloatingActionButtonMargin(params);
- mFloatingActionButtonContainer.setLayoutParams(params);
- }
-
- private void alignFloatingActionButtonMiddle() {
- final RelativeLayout.LayoutParams params =
- (RelativeLayout.LayoutParams) mFloatingActionButtonContainer.getLayoutParams();
- params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
- params.addRule(RelativeLayout.CENTER_HORIZONTAL);
- updateFloatingActionButtonMargin(params);
- mFloatingActionButtonContainer.setLayoutParams(params);
- }
-
- private void updateFloatingActionButtonMargin(RelativeLayout.LayoutParams params) {
- params.setMarginsRelative(
- params.getMarginStart(),
- params.topMargin,
- params.getMarginEnd(),
- mIsDialpadShown ?
- mFloatingActionButtonDialpadMarginBottom :
- mFloatingActionButtonMarginBottom);
- }
-
private TelephonyManager getTelephonyManager() {
return (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
}
diff --git a/src/com/android/dialer/widget/FloatingActionButtonController.java b/src/com/android/dialer/widget/FloatingActionButtonController.java
new file mode 100644
index 000000000..3f59153ef
--- /dev/null
+++ b/src/com/android/dialer/widget/FloatingActionButtonController.java
@@ -0,0 +1,212 @@
+/*
+ * 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);
+ }
+}