summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authorcalderwoodra <calderwoodra@google.com>2018-01-12 12:25:48 -0800
committerCopybara-Service <copybara-piper@google.com>2018-01-12 12:27:26 -0800
commit4d881e4b22e61913bd2439fba6901bf6cc0e98c5 (patch)
treec25ff019bf3b4ce6eb7b37483bde4bc6c63876a5 /java
parentaa280fa887ee877e6faff55ce3c1c406f113d559 (diff)
Added Dialpad to NUI.
This change adds the existing dialpad to the new UI and the animation logic required to show/hide it along with the toolbar. A follow up CL will come afterwards to combine these animations with the toolbar expanding/collapsing. known issue: bottom nav appears over the dialpad. Bug: 181512198 Test: MainActivityTest PiperOrigin-RevId: 181777370 Change-Id: Ief1591174ebca3a709df6d1d38c8b8ecbdc1878e
Diffstat (limited to 'java')
-rw-r--r--java/com/android/dialer/dialpadview/DialpadFragment.java56
-rw-r--r--java/com/android/dialer/main/impl/MainActivity.java172
-rw-r--r--java/com/android/dialer/main/impl/res/layout/bottom_nav_item.xml3
-rw-r--r--java/com/android/dialer/main/impl/res/layout/main_activity.xml19
-rw-r--r--java/com/android/dialer/main/impl/res/values/strings.xml3
-rw-r--r--java/com/android/dialer/main/impl/res/values/styles.xml3
-rw-r--r--java/com/android/dialer/main/impl/toolbar/MainToolbar.java39
7 files changed, 278 insertions, 17 deletions
diff --git a/java/com/android/dialer/dialpadview/DialpadFragment.java b/java/com/android/dialer/dialpadview/DialpadFragment.java
index 0418009d7..07e401cab 100644
--- a/java/com/android/dialer/dialpadview/DialpadFragment.java
+++ b/java/com/android/dialer/dialpadview/DialpadFragment.java
@@ -26,6 +26,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -60,6 +61,9 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.EditText;
@@ -74,6 +78,7 @@ import com.android.dialer.animation.AnimUtils;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.calllogutils.PhoneAccountUtils;
+import com.android.dialer.common.Assert;
import com.android.dialer.common.FragmentUtils;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutor;
@@ -89,6 +94,7 @@ import com.android.dialer.proguard.UsedByReflection;
import com.android.dialer.telecom.TelecomUtil;
import com.android.dialer.util.CallUtil;
import com.android.dialer.util.PermissionsUtil;
+import com.android.dialer.util.ViewUtil;
import com.android.dialer.widget.FloatingActionButtonController;
import com.google.common.base.Ascii;
import com.google.common.base.Optional;
@@ -177,7 +183,11 @@ public class DialpadFragment extends Fragment
private boolean firstLaunch = false;
private boolean animate = false;
+ private boolean isLayoutRtl;
+ private boolean isLandscape;
+
private DialerExecutor<String> initPhoneNumberFormattingTextWatcherExecutor;
+ private boolean isDialpadSlideUp;
/**
* Determines whether an add call operation is requested.
@@ -426,6 +436,14 @@ public class DialpadFragment extends Fragment
return fragmentView;
}
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ isLayoutRtl = ViewUtil.isRtl();
+ isLandscape =
+ getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
+ }
+
private String getCurrentCountryIso() {
if (currentCountryIsoForTesting.isPresent()) {
return currentCountryIsoForTesting.get();
@@ -1508,6 +1526,44 @@ public class DialpadFragment extends Fragment
}
}
+ /** Animate the dialpad down off the screen. */
+ public void slideDown(boolean animate, AnimationListener listener) {
+ Assert.checkArgument(isDialpadSlideUp);
+ isDialpadSlideUp = false;
+ int animation;
+ if (isLandscape) {
+ animation = isLayoutRtl ? R.anim.dialpad_slide_out_left : R.anim.dialpad_slide_out_right;
+ } else {
+ animation = R.anim.dialpad_slide_out_bottom;
+ }
+ Animation slideDown = AnimationUtils.loadAnimation(getContext(), animation);
+ slideDown.setInterpolator(AnimUtils.EASE_OUT);
+ slideDown.setAnimationListener(listener);
+ slideDown.setDuration(animate ? dialpadSlideInDuration : 0);
+ getView().startAnimation(slideDown);
+ }
+
+ /** Animate the dialpad up onto the screen. */
+ public void slideUp(boolean animate) {
+ Assert.checkArgument(!isDialpadSlideUp);
+ isDialpadSlideUp = true;
+ int animation;
+ if (isLandscape) {
+ animation = isLayoutRtl ? R.anim.dialpad_slide_in_left : R.anim.dialpad_slide_in_right;
+ } else {
+ animation = R.anim.dialpad_slide_in_bottom;
+ }
+ Animation slideUp = AnimationUtils.loadAnimation(getContext(), animation);
+ slideUp.setInterpolator(AnimUtils.EASE_IN);
+ slideUp.setDuration(animate ? dialpadSlideInDuration : 0);
+ getView().startAnimation(slideUp);
+ }
+
+ /** Returns the text in the dialpad */
+ public String getQuery() {
+ return digits.getText().toString();
+ }
+
public interface OnDialpadQueryChangedListener {
void onDialpadQueryChanged(String query);
diff --git a/java/com/android/dialer/main/impl/MainActivity.java b/java/com/android/dialer/main/impl/MainActivity.java
index fc7e670b0..8bdb295c7 100644
--- a/java/com/android/dialer/main/impl/MainActivity.java
+++ b/java/com/android/dialer/main/impl/MainActivity.java
@@ -21,24 +21,35 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.QuickContact;
+import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
-import android.view.View;
+import android.text.TextUtils;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
import android.widget.ImageView;
import com.android.dialer.calllog.ui.NewCallLogFragment;
+import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.contactsfragment.ContactsFragment;
import com.android.dialer.contactsfragment.ContactsFragment.Header;
import com.android.dialer.contactsfragment.ContactsFragment.OnContactSelectedListener;
+import com.android.dialer.dialpadview.DialpadFragment;
+import com.android.dialer.dialpadview.DialpadFragment.DialpadListener;
+import com.android.dialer.dialpadview.DialpadFragment.LastOutgoingCallCallback;
+import com.android.dialer.dialpadview.DialpadFragment.OnDialpadQueryChangedListener;
import com.android.dialer.main.impl.BottomNavBar.OnBottomNavTabSelectedListener;
import com.android.dialer.main.impl.toolbar.MainToolbar;
import com.android.dialer.main.impl.toolbar.SearchBarListener;
+import com.android.dialer.searchfragment.list.NewSearchFragment;
import com.android.dialer.speeddial.SpeedDialFragment;
import com.android.dialer.voicemail.listui.NewVoicemailFragment;
/** This is the main activity for dialer. It hosts favorites, call log, search, dialpad, etc... */
public final class MainActivity extends AppCompatActivity
- implements View.OnClickListener, OnContactSelectedListener {
+ implements OnContactSelectedListener, OnDialpadQueryChangedListener, DialpadListener {
+
+ private SearchController searchController;
/**
* @param context Context of the application package implementing MainActivity class.
@@ -59,29 +70,168 @@ public final class MainActivity extends AppCompatActivity
}
private void initLayout() {
- findViewById(R.id.fab).setOnClickListener(this);
+ FloatingActionButton fab = findViewById(R.id.fab);
+ fab.setOnClickListener(v -> searchController.showDialpad(true));
+
MainToolbar toolbar = findViewById(R.id.toolbar);
toolbar.setSearchBarListener(new MainSearchBarListener());
- setSupportActionBar(toolbar);
+ searchController = new SearchController(fab, toolbar);
+ setSupportActionBar(findViewById(R.id.toolbar));
+
BottomNavBar navBar = findViewById(R.id.bottom_nav_bar);
navBar.setOnTabSelectedListener(new MainBottomNavBarBottomNavTabListener());
+ // TODO(calderwoodra): Implement last tab
navBar.selectTab(BottomNavBar.TabIndex.SPEED_DIAL);
}
@Override
- public void onClick(View v) {
- if (v.getId() == R.id.fab) {
- // open dialpad search
- }
- }
-
- @Override
public void onContactSelected(ImageView photo, Uri contactUri, long contactId) {
// TODO(calderwoodra): Add impression logging
QuickContact.showQuickContact(
this, photo, contactUri, QuickContact.MODE_LARGE, null /* excludeMimes */);
}
+ @Override // OnDialpadQueryChangedListener
+ public void onDialpadQueryChanged(String query) {
+ // TODO(calderwoodra): update search fragment
+ }
+
+ @Override // DialpadListener
+ public void getLastOutgoingCall(LastOutgoingCallCallback callback) {
+ // TODO(calderwoodra): migrate CallLogAsync class outside of dialer/app and call it here.
+ }
+
+ @Override // DialpadListener
+ public void onDialpadShown() {
+ searchController.getDialpadFragment().slideUp(true);
+ }
+
+ @Override // DialpadListener
+ public void onCallPlacedFromDialpad() {
+ // TODO(calderwoodra): logging
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (searchController.onBackPressed()) {
+ return;
+ }
+ super.onBackPressed();
+ }
+
+ /** Search controller for handling all the logic related to hiding/showing search and dialpad. */
+ private final class SearchController {
+
+ private static final String DIALPAD_FRAGMENT_TAG = "dialpad_fragment_tag";
+ private static final String SEARCH_FRAGMENT_TAG = "search_fragment_tag";
+
+ private final FloatingActionButton fab;
+ private final MainToolbar toolbar;
+
+ private boolean isDialpadVisible;
+ private boolean isSearchVisible;
+
+ private SearchController(FloatingActionButton fab, MainToolbar toolbar) {
+ this.fab = fab;
+ this.toolbar = toolbar;
+ }
+
+ /** Shows the dialpad, hides the FAB and slides the toolbar off screen. */
+ public void showDialpad(boolean animate) {
+ Assert.checkArgument(!isDialpadVisible);
+ isDialpadVisible = true;
+ isSearchVisible = true;
+
+ fab.hide();
+ toolbar.slideUp(animate);
+ setTitle(R.string.dialpad_activity_title);
+
+ android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction();
+
+ // Show Search
+ if (getSearchFragment() == null) {
+ NewSearchFragment searchFragment = NewSearchFragment.newInstance(false);
+ transaction.add(R.id.search_fragment_container, searchFragment, SEARCH_FRAGMENT_TAG);
+ } else if (!isSearchVisible) {
+ transaction.show(getSearchFragment());
+ }
+
+ // Show Dialpad
+ if (getDialpadFragment() == null) {
+ DialpadFragment dialpadFragment = new DialpadFragment();
+ transaction.add(R.id.search_fragment_container, dialpadFragment, DIALPAD_FRAGMENT_TAG);
+ } else {
+ DialpadFragment dialpadFragment = getDialpadFragment();
+ transaction.show(dialpadFragment);
+ }
+ transaction.commit();
+ }
+
+ /** Hides the dialpad, reveals the FAB and slides the toolbar back onto the screen. */
+ public void hideDialpad(boolean animate) {
+ Assert.checkArgument(isDialpadVisible);
+ isDialpadVisible = false;
+
+ fab.show();
+ toolbar.slideDown(animate);
+ setTitle(R.string.main_activity_label);
+
+ DialpadFragment dialpadFragment = getDialpadFragment();
+ dialpadFragment.setAnimate(animate);
+ dialpadFragment.slideDown(
+ animate,
+ new AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {}
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ if (!(isFinishing() || isDestroyed())) {
+ getFragmentManager().beginTransaction().remove(dialpadFragment).commit();
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {}
+ });
+ }
+
+ /**
+ * Should be called when the user presses the back button.
+ *
+ * @return true if {@link #onBackPressed()} handled to action.
+ */
+ public boolean onBackPressed() {
+ if (isDialpadVisible && !TextUtils.isEmpty(getDialpadFragment().getQuery())) {
+ hideDialpad(true);
+ return true;
+ } else if (isSearchVisible) {
+ closeSearch(true);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /** Calls {@link #hideDialpad(boolean)} and removes the search fragment. */
+ private void closeSearch(boolean animate) {
+ Assert.checkArgument(isSearchVisible);
+ if (isDialpadVisible) {
+ hideDialpad(animate);
+ }
+ getFragmentManager().beginTransaction().remove(getSearchFragment()).commit();
+ isSearchVisible = false;
+ }
+
+ private DialpadFragment getDialpadFragment() {
+ return (DialpadFragment) getFragmentManager().findFragmentByTag(DIALPAD_FRAGMENT_TAG);
+ }
+
+ private NewSearchFragment getSearchFragment() {
+ return (NewSearchFragment) getFragmentManager().findFragmentByTag(SEARCH_FRAGMENT_TAG);
+ }
+ }
+
/**
* Implementation of {@link SearchBarListener} that holds the logic for how to handle search bar
* events.
diff --git a/java/com/android/dialer/main/impl/res/layout/bottom_nav_item.xml b/java/com/android/dialer/main/impl/res/layout/bottom_nav_item.xml
index 28ad964dd..f9f2b6102 100644
--- a/java/com/android/dialer/main/impl/res/layout/bottom_nav_item.xml
+++ b/java/com/android/dialer/main/impl/res/layout/bottom_nav_item.xml
@@ -37,5 +37,6 @@
android:id="@+id/bottom_nav_item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="12sp"/>
+ android:textSize="12sp"
+ android:gravity="center_horizontal"/>
</com.android.dialer.main.impl.BottomNavItem> \ No newline at end of file
diff --git a/java/com/android/dialer/main/impl/res/layout/main_activity.xml b/java/com/android/dialer/main/impl/res/layout/main_activity.xml
index 31ff19dd3..0b0652af5 100644
--- a/java/com/android/dialer/main/impl/res/layout/main_activity.xml
+++ b/java/com/android/dialer/main/impl/res/layout/main_activity.xml
@@ -21,10 +21,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <include
- android:id="@+id/toolbar"
- layout="@layout/toolbar_layout"/>
-
+ <!-- Holds SpeedDial, Call Log, Contacts and Voicemail fragments -->
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
@@ -32,14 +29,26 @@
android:layout_below="@+id/toolbar"
android:layout_above="@+id/bottom_nav_bar"/>
+ <!-- BottomNavBar -->
<include
android:id="@+id/bottom_nav_bar"
layout="@layout/bottom_nav_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="bottom"
android:layout_alignParentBottom="true"/>
+ <!-- Holds search and dialpad fragments -->
+ <FrameLayout
+ android:id="@+id/search_fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_below="@+id/toolbar"/>
+
+ <!-- MainToolbar -->
+ <include
+ android:id="@+id/toolbar"
+ layout="@layout/toolbar_layout"/>
+
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
diff --git a/java/com/android/dialer/main/impl/res/values/strings.xml b/java/com/android/dialer/main/impl/res/values/strings.xml
index ff136e877..f530fa2bf 100644
--- a/java/com/android/dialer/main/impl/res/values/strings.xml
+++ b/java/com/android/dialer/main/impl/res/values/strings.xml
@@ -22,6 +22,9 @@
TODO(38502365): Remove this once we're ready to launch the new UI. -->
<string name="nui_shortcut_name">Phone NUI</string>
+ <!-- Title for the activity that dials the phone, when launched directly into the dialpad -->
+ <string name="dialpad_activity_title">Phone Keypad</string>
+
<!-- The description text for the call log tab. -->
<string name="main_call_history_tab_description" tools:ignore="UnusedResources">Call history</string>
diff --git a/java/com/android/dialer/main/impl/res/values/styles.xml b/java/com/android/dialer/main/impl/res/values/styles.xml
index f94897a8b..26f880dc4 100644
--- a/java/com/android/dialer/main/impl/res/values/styles.xml
+++ b/java/com/android/dialer/main/impl/res/values/styles.xml
@@ -19,5 +19,8 @@
<item name="android:colorPrimary">@color/dialtacts_theme_color</item>
<item name="android:colorPrimaryDark">@color/dialer_theme_color_dark</item>
<item name="android:colorAccent">@color/dialer_secondary_color</item>
+
+ <!-- Theme needed for DialpadFragment -->
+ <item name="dialpad_style">@style/Dialpad.Light</item>
</style>
</resources>
diff --git a/java/com/android/dialer/main/impl/toolbar/MainToolbar.java b/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
index 6d9b7da6b..b32217230 100644
--- a/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
+++ b/java/com/android/dialer/main/impl/toolbar/MainToolbar.java
@@ -17,16 +17,24 @@
package com.android.dialer.main.impl.toolbar;
import android.content.Context;
+import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.PopupMenu.OnMenuItemClickListener;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.view.MenuItem;
+import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageButton;
+import com.android.dialer.common.Assert;
/** Toolbar for {@link com.android.dialer.main.impl.MainActivity}. */
public final class MainToolbar extends Toolbar implements OnMenuItemClickListener {
+ private static final int SLIDE_DURATION = 300;
+ private static final AccelerateDecelerateInterpolator SLIDE_INTERPOLATOR =
+ new AccelerateDecelerateInterpolator();
+
private SearchBarListener listener;
+ private boolean isSlideUp;
public MainToolbar(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -57,4 +65,35 @@ public final class MainToolbar extends Toolbar implements OnMenuItemClickListene
this.listener = listener;
((SearchBarView) findViewById(R.id.search_view_container)).setSearchBarListener(listener);
}
+
+ /** Slides the toolbar up and off the screen. */
+ public void slideUp(boolean animate) {
+ Assert.checkArgument(!isSlideUp);
+ isSlideUp = true;
+ animate()
+ .translationY(-getHeight())
+ .setDuration(animate ? SLIDE_DURATION : 0)
+ .setInterpolator(SLIDE_INTERPOLATOR)
+ .start();
+ }
+
+ /**
+ * Slides the toolbar down and back onto the screen.
+ *
+ * @param animate
+ */
+ public void slideDown(boolean animate) {
+ Assert.checkArgument(isSlideUp);
+ isSlideUp = false;
+ animate()
+ .translationY(0)
+ .setDuration(animate ? SLIDE_DURATION : 0)
+ .setInterpolator(SLIDE_INTERPOLATOR)
+ .start();
+ }
+
+ @VisibleForTesting
+ public boolean isSlideUp() {
+ return isSlideUp;
+ }
}