From c07d6bee10c8d50c41d1513e6b8c8e9f85d3107e Mon Sep 17 00:00:00 2001 From: calderwoodra Date: Tue, 9 Jan 2018 10:38:37 -0800 Subject: Implemented Bottom Nav in Dialer NUI. Bug: 64655802 Test: existing PiperOrigin-RevId: 181339724 Change-Id: I05c48d0a046010baf6b6593de3b934fdaf3e9f08 --- .../res/drawable/quantum_ic_people_vd_theme_24.xml | 25 ++++ .../res/drawable/quantum_ic_star_vd_theme_24.xml | 25 ++++ .../com/android/dialer/main/impl/BottomNavBar.java | 136 +++++++++++++++++++++ .../android/dialer/main/impl/BottomNavItem.java | 59 +++++++++ .../com/android/dialer/main/impl/MainActivity.java | 131 ++++++++++++++++++-- .../main/impl/res/layout/bottom_nav_bar_layout.xml | 52 ++++++++ .../main/impl/res/layout/bottom_nav_item.xml | 41 +++++++ .../dialer/main/impl/res/layout/main_activity.xml | 73 +++++------ .../dialer/main/impl/res/menu/main_menu.xml | 7 -- .../android/dialer/main/impl/res/values/colors.xml | 20 +++ .../dialer/main/impl/res/values/strings.xml | 2 + .../android/dialer/main/impl/res/values/styles.xml | 5 - .../speeddial/StrequentContactsCursorLoader.java | 4 +- .../speeddial/res/layout/fragment_speed_dial.xml | 3 +- 14 files changed, 514 insertions(+), 69 deletions(-) create mode 100644 assets/quantum/res/drawable/quantum_ic_people_vd_theme_24.xml create mode 100644 assets/quantum/res/drawable/quantum_ic_star_vd_theme_24.xml create mode 100644 java/com/android/dialer/main/impl/BottomNavBar.java create mode 100644 java/com/android/dialer/main/impl/BottomNavItem.java create mode 100644 java/com/android/dialer/main/impl/res/layout/bottom_nav_bar_layout.xml create mode 100644 java/com/android/dialer/main/impl/res/layout/bottom_nav_item.xml create mode 100644 java/com/android/dialer/main/impl/res/values/colors.xml diff --git a/assets/quantum/res/drawable/quantum_ic_people_vd_theme_24.xml b/assets/quantum/res/drawable/quantum_ic_people_vd_theme_24.xml new file mode 100644 index 000000000..c31e20dce --- /dev/null +++ b/assets/quantum/res/drawable/quantum_ic_people_vd_theme_24.xml @@ -0,0 +1,25 @@ + + + + \ No newline at end of file diff --git a/assets/quantum/res/drawable/quantum_ic_star_vd_theme_24.xml b/assets/quantum/res/drawable/quantum_ic_star_vd_theme_24.xml new file mode 100644 index 000000000..d937d291e --- /dev/null +++ b/assets/quantum/res/drawable/quantum_ic_star_vd_theme_24.xml @@ -0,0 +1,25 @@ + + + + diff --git a/java/com/android/dialer/main/impl/BottomNavBar.java b/java/com/android/dialer/main/impl/BottomNavBar.java new file mode 100644 index 000000000..9aaa988e8 --- /dev/null +++ b/java/com/android/dialer/main/impl/BottomNavBar.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2018 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.main.impl; + +import android.content.Context; +import android.support.annotation.IntDef; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** Dialer Bottom Nav Bar for {@link MainActivity}. */ +final class BottomNavBar extends LinearLayout { + + /** Index for each tab in the bottom nav. */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + TabIndex.SPEED_DIAL, + TabIndex.HISTORY, + TabIndex.CONTACTS, + TabIndex.VOICEMAIL, + }) + public @interface TabIndex { + int SPEED_DIAL = 0; + int HISTORY = 1; + int CONTACTS = 2; + int VOICEMAIL = 3; + } + + private BottomNavItem speedDial; + private BottomNavItem callLog; + private BottomNavItem contacts; + private BottomNavItem voicemail; + private OnBottomNavTabSelectedListener listener; + + public BottomNavBar(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + speedDial = findViewById(R.id.speed_dial_tab); + callLog = findViewById(R.id.call_log_tab); + contacts = findViewById(R.id.contacts_tab); + voicemail = findViewById(R.id.voicemail_tab); + + speedDial.setup(R.string.tab_title_speed_dial, R.drawable.quantum_ic_star_vd_theme_24); + callLog.setup(R.string.tab_title_call_history, R.drawable.quantum_ic_history_vd_theme_24); + contacts.setup(R.string.tab_title_contacts, R.drawable.quantum_ic_people_vd_theme_24); + voicemail.setup(R.string.tab_title_voicemail, R.drawable.quantum_ic_voicemail_vd_theme_24); + + speedDial.setOnClickListener( + v -> { + setSelected(speedDial); + listener.onSpeedDialSelected(); + }); + callLog.setOnClickListener( + v -> { + setSelected(callLog); + listener.onCallLogSelected(); + }); + contacts.setOnClickListener( + v -> { + setSelected(contacts); + listener.onContactsSelected(); + }); + voicemail.setOnClickListener( + v -> { + setSelected(voicemail); + listener.onVoicemailSelected(); + }); + } + + private void setSelected(View view) { + speedDial.setSelected(view == speedDial); + callLog.setSelected(view == callLog); + contacts.setSelected(view == contacts); + voicemail.setSelected(view == voicemail); + } + + /** + * Calls {@link View#performClick()} on the desired tab. + * + * @param tab {@link TabIndex} + */ + void selectTab(@TabIndex int tab) { + if (tab == TabIndex.SPEED_DIAL) { + speedDial.performClick(); + } else if (tab == TabIndex.HISTORY) { + callLog.performClick(); + } else if (tab == TabIndex.CONTACTS) { + contacts.performClick(); + } else if (tab == TabIndex.VOICEMAIL) { + voicemail.performClick(); + } else { + throw new IllegalStateException("Invalid tab: " + tab); + } + } + + void setOnTabSelectedListener(OnBottomNavTabSelectedListener listener) { + this.listener = listener; + } + + /** Listener for bottom nav tab's on click events. */ + public interface OnBottomNavTabSelectedListener { + + /** Speed dial tab was clicked. */ + void onSpeedDialSelected(); + + /** Call Log tab was clicked. */ + void onCallLogSelected(); + + /** Contacts tab was clicked. */ + void onContactsSelected(); + + /** Voicemail tab was clicked. */ + void onVoicemailSelected(); + } +} diff --git a/java/com/android/dialer/main/impl/BottomNavItem.java b/java/com/android/dialer/main/impl/BottomNavItem.java new file mode 100644 index 000000000..14706ab34 --- /dev/null +++ b/java/com/android/dialer/main/impl/BottomNavItem.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 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.main.impl; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.support.annotation.DrawableRes; +import android.support.annotation.Nullable; +import android.support.annotation.StringRes; +import android.util.AttributeSet; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +/** Navigation item in a bottom nav. */ +final class BottomNavItem extends LinearLayout { + + private ImageView image; + private TextView text; + + public BottomNavItem(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + image = findViewById(R.id.bottom_nav_item_image); + text = findViewById(R.id.bottom_nav_item_text); + } + + @Override + public void setSelected(boolean selected) { + super.setSelected(selected); + int colorId = selected ? R.color.bottom_nav_icon_selected : R.color.bottom_nav_icon_deselected; + int color = getContext().getColor(colorId); + image.setImageTintList(ColorStateList.valueOf(color)); + text.setTextColor(color); + } + + void setup(@StringRes int stringRes, @DrawableRes int drawableRes) { + text.setText(stringRes); + image.setImageResource(drawableRes); + } +} diff --git a/java/com/android/dialer/main/impl/MainActivity.java b/java/com/android/dialer/main/impl/MainActivity.java index 52b39f0e9..87bd8dd58 100644 --- a/java/com/android/dialer/main/impl/MainActivity.java +++ b/java/com/android/dialer/main/impl/MainActivity.java @@ -18,19 +18,29 @@ package com.android.dialer.main.impl; import android.content.Context; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; -import android.support.design.widget.TabLayout; -import android.support.v4.view.ViewPager; +import android.provider.ContactsContract.QuickContact; +import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.widget.ImageView; import android.widget.Toast; +import com.android.dialer.calllog.ui.NewCallLogFragment; 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.main.impl.BottomNavBar.OnBottomNavTabSelectedListener; +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 { +public final class MainActivity extends AppCompatActivity + implements View.OnClickListener, OnContactSelectedListener { /** * @param context Context of the application package implementing MainActivity class. @@ -53,12 +63,9 @@ public final class MainActivity extends AppCompatActivity implements View.OnClic private void initLayout() { findViewById(R.id.fab).setOnClickListener(this); - ViewPager pager = findViewById(R.id.pager); - MainPagerAdapter pagerAdapter = new MainPagerAdapter(this, getSupportFragmentManager()); - pager.setAdapter(pagerAdapter); - - TabLayout tabLayout = findViewById(R.id.tab_layout); - tabLayout.setupWithViewPager(pager); + BottomNavBar navBar = findViewById(R.id.bottom_nav_bar); + navBar.setOnTabSelectedListener(new MainBottomNavBarBottomNavTabListener()); + navBar.selectTab(BottomNavBar.TabIndex.SPEED_DIAL); Toolbar toolbar = findViewById(R.id.toolbar); toolbar.setPopupTheme(android.R.style.Theme_Material_Light); @@ -77,9 +84,6 @@ public final class MainActivity extends AppCompatActivity implements View.OnClic if (item.getItemId() == R.id.search) { // open search return true; - } else if (item.getItemId() == R.id.contacts) { - // open contacts - return true; } else { // TODO(calderwoodra) handle other menu items return super.onOptionsItemSelected(item); @@ -92,4 +96,107 @@ public final class MainActivity extends AppCompatActivity implements View.OnClic // 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 */); + } + + /** + * Implementation of {@link OnBottomNavTabSelectedListener} that handles logic for showing each of + * the main tabs. + */ + private final class MainBottomNavBarBottomNavTabListener + implements OnBottomNavTabSelectedListener { + + private static final String SPEED_DIAL_TAG = "speed_dial"; + private static final String CALL_LOG_TAG = "call_log"; + private static final String CONTACTS_TAG = "contacts"; + private static final String VOICEMAIL_TAG = "voicemail"; + + @Override + public void onSpeedDialSelected() { + hideAllFragments(); + SpeedDialFragment fragment = + (SpeedDialFragment) getFragmentManager().findFragmentByTag(SPEED_DIAL_TAG); + if (fragment == null) { + getFragmentManager() + .beginTransaction() + .add(R.id.fragment_container, SpeedDialFragment.newInstance(), SPEED_DIAL_TAG) + .commit(); + } else { + getFragmentManager().beginTransaction().show(fragment).commit(); + } + } + + @Override + public void onCallLogSelected() { + hideAllFragments(); + NewCallLogFragment fragment = + (NewCallLogFragment) getSupportFragmentManager().findFragmentByTag(CALL_LOG_TAG); + if (fragment == null) { + getSupportFragmentManager() + .beginTransaction() + .add(R.id.fragment_container, new NewCallLogFragment(), CALL_LOG_TAG) + .commit(); + } else { + getSupportFragmentManager().beginTransaction().show(fragment).commit(); + } + } + + @Override + public void onContactsSelected() { + hideAllFragments(); + ContactsFragment fragment = + (ContactsFragment) getFragmentManager().findFragmentByTag(CONTACTS_TAG); + if (fragment == null) { + getFragmentManager() + .beginTransaction() + .add( + R.id.fragment_container, + ContactsFragment.newInstance(Header.ADD_CONTACT), + CONTACTS_TAG) + .commit(); + } else { + getFragmentManager().beginTransaction().show(fragment).commit(); + } + } + + @Override + public void onVoicemailSelected() { + hideAllFragments(); + NewVoicemailFragment fragment = + (NewVoicemailFragment) getSupportFragmentManager().findFragmentByTag(VOICEMAIL_TAG); + if (fragment == null) { + getSupportFragmentManager() + .beginTransaction() + .add(R.id.fragment_container, new NewVoicemailFragment(), VOICEMAIL_TAG) + .commit(); + } else { + getSupportFragmentManager().beginTransaction().show(fragment).commit(); + } + } + + private void hideAllFragments() { + FragmentTransaction supportTransaction = getSupportFragmentManager().beginTransaction(); + if (getSupportFragmentManager().findFragmentByTag(CALL_LOG_TAG) != null) { + supportTransaction.hide(getSupportFragmentManager().findFragmentByTag(CALL_LOG_TAG)); + } + if (getSupportFragmentManager().findFragmentByTag(VOICEMAIL_TAG) != null) { + supportTransaction.hide(getSupportFragmentManager().findFragmentByTag(VOICEMAIL_TAG)); + } + supportTransaction.commit(); + + android.app.FragmentTransaction transaction = getFragmentManager().beginTransaction(); + if (getFragmentManager().findFragmentByTag(SPEED_DIAL_TAG) != null) { + transaction.hide(getFragmentManager().findFragmentByTag(SPEED_DIAL_TAG)); + } + if (getFragmentManager().findFragmentByTag(CONTACTS_TAG) != null) { + transaction.hide(getFragmentManager().findFragmentByTag(CONTACTS_TAG)); + } + transaction.commit(); + } + } } diff --git a/java/com/android/dialer/main/impl/res/layout/bottom_nav_bar_layout.xml b/java/com/android/dialer/main/impl/res/layout/bottom_nav_bar_layout.xml new file mode 100644 index 000000000..67c1a20df --- /dev/null +++ b/java/com/android/dialer/main/impl/res/layout/bottom_nav_bar_layout.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + \ No newline at end of file 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 new file mode 100644 index 000000000..28ad964dd --- /dev/null +++ b/java/com/android/dialer/main/impl/res/layout/bottom_nav_item.xml @@ -0,0 +1,41 @@ + + + + + + + + \ 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 73b2eae33..969bbe413 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 @@ -14,55 +14,44 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> - - + android:minHeight="?attr/actionBarSize" + android:background="@color/dialer_theme_color" + app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" + app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> - - - - - - - - + android:layout_height="match_parent" + android:layout_below="@+id/toolbar" + android:layout_above="@+id/bottom_nav_bar"/> - + - - - \ No newline at end of file + + \ No newline at end of file diff --git a/java/com/android/dialer/main/impl/res/menu/main_menu.xml b/java/com/android/dialer/main/impl/res/menu/main_menu.xml index 09bcbf823..08d711eb1 100644 --- a/java/com/android/dialer/main/impl/res/menu/main_menu.xml +++ b/java/com/android/dialer/main/impl/res/menu/main_menu.xml @@ -23,13 +23,6 @@ android:contentDescription="@string/description_search" app:showAsAction="always"/> - - + + + #FFFFFF + #B2FFFFFF + 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 d3eb6d73e..abf44ddae 100644 --- a/java/com/android/dialer/main/impl/res/values/strings.xml +++ b/java/com/android/dialer/main/impl/res/values/strings.xml @@ -41,6 +41,8 @@ Speed Dial Voicemail + + Contacts Settings 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 38c50081b..f94897a8b 100644 --- a/java/com/android/dialer/main/impl/res/values/styles.xml +++ b/java/com/android/dialer/main/impl/res/values/styles.xml @@ -20,9 +20,4 @@ @color/dialer_theme_color_dark @color/dialer_secondary_color - - diff --git a/java/com/android/dialer/speeddial/StrequentContactsCursorLoader.java b/java/com/android/dialer/speeddial/StrequentContactsCursorLoader.java index e9e3e32da..40d03846f 100644 --- a/java/com/android/dialer/speeddial/StrequentContactsCursorLoader.java +++ b/java/com/android/dialer/speeddial/StrequentContactsCursorLoader.java @@ -26,7 +26,7 @@ import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Contacts; /** Cursor Loader for strequent contacts. */ -final class StrequentContactsCursorLoader extends CursorLoader { +public final class StrequentContactsCursorLoader extends CursorLoader { static final int PHONE_ID = 0; static final int PHONE_DISPLAY_NAME = 1; @@ -41,7 +41,7 @@ final class StrequentContactsCursorLoader extends CursorLoader { static final int PHONE_PINNED = 10; static final int PHONE_CONTACT_ID = 11; - static final String[] PHONE_PROJECTION = + public static final String[] PHONE_PROJECTION = new String[] { Phone._ID, // 0 Phone.DISPLAY_NAME, // 1 diff --git a/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml b/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml index d432f097b..ecbb95193 100644 --- a/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml +++ b/java/com/android/dialer/speeddial/res/layout/fragment_speed_dial.xml @@ -21,4 +21,5 @@ android:layout_height="match_parent" android:paddingStart="16dp" android:paddingEnd="16dp" - android:clipToPadding="false"/> + android:clipToPadding="false" + android:background="@color/background_dialer_light"/> -- cgit v1.2.3