diff options
author | Eric Erfanian <erfanian@google.com> | 2017-06-08 00:59:55 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2017-06-08 00:59:55 +0000 |
commit | c67d658e7daa453fe9ad9fd1a37f81eaf2048c44 (patch) | |
tree | b9bbc285430ffb5363a70eb27e382c38f5a85b7a /java/com/android/dialer/contactsfragment | |
parent | 75233ff03785f24789b32039ac2c208805b7e506 (diff) | |
parent | 274b6d320edb3c33e7b3a95c43a811829486a777 (diff) |
Update AOSP Dialer source from internal google3 repository at cl/158012278. am: 91ce7d2a47
am: 274b6d320e
Change-Id: Iecf4325f314bf6c3324187e6406c8aae4675dd63
Diffstat (limited to 'java/com/android/dialer/contactsfragment')
10 files changed, 408 insertions, 61 deletions
diff --git a/java/com/android/dialer/contactsfragment/ContactViewHolder.java b/java/com/android/dialer/contactsfragment/ContactViewHolder.java index 5df106dbc..586e22aab 100644 --- a/java/com/android/dialer/contactsfragment/ContactViewHolder.java +++ b/java/com/android/dialer/contactsfragment/ContactViewHolder.java @@ -16,6 +16,7 @@ package com.android.dialer.contactsfragment; +import android.content.Context; import android.net.Uri; import android.provider.ContactsContract.QuickContact; import android.support.v7.widget.RecyclerView; @@ -25,6 +26,8 @@ import android.view.View.OnClickListener; import android.widget.QuickContactBadge; import android.widget.TextView; import com.android.dialer.common.Assert; +import com.android.dialer.logging.InteractionEvent; +import com.android.dialer.logging.Logger; /** View holder for a contact. */ final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClickListener { @@ -32,12 +35,14 @@ final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClick private final TextView header; private final TextView name; private final QuickContactBadge photo; + private final Context context; private String headerText; private Uri contactUri; public ContactViewHolder(View itemView) { super(itemView); + context = itemView.getContext(); itemView.findViewById(R.id.click_target).setOnClickListener(this); header = (TextView) itemView.findViewById(R.id.header); name = (TextView) itemView.findViewById(R.id.contact_name); @@ -60,6 +65,10 @@ final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClick name.setText(displayName); header.setText(headerText); header.setVisibility(showHeader ? View.VISIBLE : View.INVISIBLE); + + Logger.get(context) + .logQuickContactOnTouch( + photo, InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_CONTACTS_FRAGMENT_BADGE, true); } public QuickContactBadge getPhoto() { @@ -76,6 +85,8 @@ final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClick @Override public void onClick(View v) { + Logger.get(context) + .logInteraction(InteractionEvent.Type.OPEN_QUICK_CONTACT_FROM_CONTACTS_FRAGMENT_ITEM); QuickContact.showQuickContact( photo.getContext(), photo, contactUri, QuickContact.MODE_LARGE, null /* excludeMimes */); } diff --git a/java/com/android/dialer/contactsfragment/ContactsAdapter.java b/java/com/android/dialer/contactsfragment/ContactsAdapter.java index 4692eff5d..309e034cc 100644 --- a/java/com/android/dialer/contactsfragment/ContactsAdapter.java +++ b/java/com/android/dialer/contactsfragment/ContactsAdapter.java @@ -23,10 +23,10 @@ import android.provider.ContactsContract.Contacts; import android.support.v4.util.ArrayMap; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; import com.android.contacts.common.ContactPhotoManager; -import com.android.dialer.common.Assert; +import com.android.contacts.common.lettertiles.LetterTileDrawable; /** List adapter for the union of all contacts associated with every account on the device. */ final class ContactsAdapter extends RecyclerView.Adapter<ContactViewHolder> { @@ -70,7 +70,7 @@ final class ContactsAdapter extends RecyclerView.Adapter<ContactViewHolder> { getPhotoId(cursor), getPhotoUri(cursor), name, - 0); + LetterTileDrawable.TYPE_DEFAULT); String photoDescription = context.getString(com.android.contacts.common.R.string.description_quick_contact_for, name); @@ -79,17 +79,23 @@ final class ContactsAdapter extends RecyclerView.Adapter<ContactViewHolder> { // Always show the view holder's header if it's the first item in the list. Otherwise, compare // it to the previous element and only show the anchored header if the row elements fall into // the same sublists. - if (position == 0) { - contactViewHolder.bind(header, name, contactUri, true); - } else { - boolean showHeader = !header.equals(getHeaderString(position - 1)); - contactViewHolder.bind(header, name, contactUri, showHeader); - } + boolean showHeader = position == 0 || !header.equals(getHeaderString(position - 1)); + contactViewHolder.bind(header, name, contactUri, showHeader); + } + + @Override + public void onViewRecycled(ContactViewHolder contactViewHolder) { + super.onViewRecycled(contactViewHolder); + holderMap.remove(contactViewHolder); } public void refreshHeaders() { for (ContactViewHolder holder : holderMap.keySet()) { - onBindViewHolder(holder, holderMap.get(holder)); + int position = holderMap.get(holder); + boolean showHeader = + position == 0 || !getHeaderString(position).equals(getHeaderString(position - 1)); + int visibility = showHeader ? View.VISIBLE : View.INVISIBLE; + holder.getHeaderView().setVisibility(visibility); } } @@ -98,27 +104,6 @@ final class ContactsAdapter extends RecyclerView.Adapter<ContactViewHolder> { return cursor == null ? 0 : cursor.getCount(); } - public String getHeader(int position) { - return getHolderAt(position).getHeader(); - } - - public TextView getHeaderView(int position) { - return getHolderAt(position).getHeaderView(); - } - - public void setHeaderVisibility(int position, int visibility) { - getHolderAt(position).getHeaderView().setVisibility(visibility); - } - - private ContactViewHolder getHolderAt(int position) { - for (ContactViewHolder holder : holderMap.keySet()) { - if (holderMap.get(holder) == position) { - return holder; - } - } - throw Assert.createIllegalStateFailException("No holder for position: " + position); - } - private static String getDisplayName(Cursor cursor) { return cursor.getString(ContactsCursorLoader.CONTACT_DISPLAY_NAME); } @@ -138,7 +123,7 @@ final class ContactsAdapter extends RecyclerView.Adapter<ContactViewHolder> { return Contacts.getLookupUri(contactId, lookupKey); } - private String getHeaderString(int position) { + public String getHeaderString(int position) { int index = -1; int sum = 0; while (sum <= position) { diff --git a/java/com/android/dialer/contactsfragment/ContactsCursorLoader.java b/java/com/android/dialer/contactsfragment/ContactsCursorLoader.java index 6d4d21079..2bb540ac0 100644 --- a/java/com/android/dialer/contactsfragment/ContactsCursorLoader.java +++ b/java/com/android/dialer/contactsfragment/ContactsCursorLoader.java @@ -29,7 +29,7 @@ final class ContactsCursorLoader extends CursorLoader { public static final int CONTACT_PHOTO_URI = 3; public static final int CONTACT_LOOKUP_KEY = 4; - public static final String[] CONTACTS_PROJECTION = + public static final String[] CONTACTS_PROJECTION_DISPLAY_NAME_PRIMARY = new String[] { Contacts._ID, // 0 Contacts.DISPLAY_NAME_PRIMARY, // 1 @@ -38,16 +38,35 @@ final class ContactsCursorLoader extends CursorLoader { Contacts.LOOKUP_KEY, // 4 }; - public ContactsCursorLoader(Context context) { + public static final String[] CONTACTS_PROJECTION_DISPLAY_NAME_ALTERNATIVE = + new String[] { + Contacts._ID, // 0 + Contacts.DISPLAY_NAME_ALTERNATIVE, // 1 + Contacts.PHOTO_ID, // 2 + Contacts.PHOTO_THUMBNAIL_URI, // 3 + Contacts.LOOKUP_KEY, // 4 + }; + + private ContactsCursorLoader(Context context, String[] contactProjection, String sortKey) { super( context, Contacts.CONTENT_URI .buildUpon() .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true") .build(), - CONTACTS_PROJECTION, + contactProjection, null, null, - Contacts.SORT_KEY_PRIMARY + " ASC"); + sortKey + " ASC"); + } + + public static ContactsCursorLoader createInstanceDisplayNamePrimary( + Context context, String sortKey) { + return new ContactsCursorLoader(context, CONTACTS_PROJECTION_DISPLAY_NAME_PRIMARY, sortKey); + } + + public static ContactsCursorLoader createInstanceDisplayNameAlternative( + Context context, String sortKey) { + return new ContactsCursorLoader(context, CONTACTS_PROJECTION_DISPLAY_NAME_ALTERNATIVE, sortKey); } } diff --git a/java/com/android/dialer/contactsfragment/ContactsFragment.java b/java/com/android/dialer/contactsfragment/ContactsFragment.java index ea662fc89..a996a4fad 100644 --- a/java/com/android/dialer/contactsfragment/ContactsFragment.java +++ b/java/com/android/dialer/contactsfragment/ContactsFragment.java @@ -16,63 +16,125 @@ package com.android.dialer.contactsfragment; +import android.Manifest.permission; import android.app.Fragment; import android.app.LoaderManager.LoaderCallbacks; import android.content.Loader; +import android.content.pm.PackageManager; import android.database.Cursor; import android.os.Bundle; +import android.provider.ContactsContract.Contacts; import android.support.annotation.Nullable; +import android.support.v13.app.FragmentCompat; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.Recycler; +import android.support.v7.widget.RecyclerView.State; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnScrollChangeListener; import android.view.ViewGroup; import android.widget.TextView; +import com.android.contacts.common.preference.ContactsPreferences; +import com.android.dialer.common.Assert; +import com.android.dialer.util.DialerUtils; +import com.android.dialer.util.IntentUtil; import com.android.dialer.util.PermissionsUtil; +import com.android.dialer.widget.EmptyContentView; +import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener; /** Fragment containing a list of all contacts. */ public class ContactsFragment extends Fragment - implements LoaderCallbacks<Cursor>, OnScrollChangeListener { + implements LoaderCallbacks<Cursor>, + OnScrollChangeListener, + OnEmptyViewActionButtonClickedListener { + public static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 1; + + private FastScroller fastScroller; private TextView anchoredHeader; private RecyclerView recyclerView; private LinearLayoutManager manager; private ContactsAdapter adapter; + private EmptyContentView emptyContentView; + + private ContactsPreferences contactsPrefs; + + private final ContactsPreferences.ChangeListener preferencesChangeListener = + () -> getLoaderManager().restartLoader(0, null, this); + + @Override + public void onCreate(Bundle savedState) { + super.onCreate(savedState); + contactsPrefs = new ContactsPreferences(getContext()); + contactsPrefs.registerChangeListener(preferencesChangeListener); + } @Nullable @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_contacts, container, false); + fastScroller = (FastScroller) view.findViewById(R.id.fast_scroller); anchoredHeader = (TextView) view.findViewById(R.id.header); - manager = new LinearLayoutManager(getContext()); - - // TODO: Handle contacts permission denied view - // TODO: Handle 0 contacts layout recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); - recyclerView.setLayoutManager(manager); - getLoaderManager().initLoader(0, null, this); + + emptyContentView = (EmptyContentView) view.findViewById(R.id.empty_list_view); + emptyContentView.setImage(R.drawable.empty_contacts); + emptyContentView.setActionClickedListener(this); if (PermissionsUtil.hasContactsReadPermissions(getContext())) { getLoaderManager().initLoader(0, null, this); + } else { + emptyContentView.setDescription(R.string.permission_no_contacts); + emptyContentView.setActionLabel(R.string.permission_single_turn_on); + emptyContentView.setVisibility(View.VISIBLE); } return view; } + /** @return a loader according to sort order and display order. */ @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { - return new ContactsCursorLoader(getContext()); + boolean sortOrderPrimary = + (contactsPrefs.getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY); + boolean displayOrderPrimary = + (contactsPrefs.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY); + + String sortKey = sortOrderPrimary ? Contacts.SORT_KEY_PRIMARY : Contacts.SORT_KEY_ALTERNATIVE; + return displayOrderPrimary + ? ContactsCursorLoader.createInstanceDisplayNamePrimary(getContext(), sortKey) + : ContactsCursorLoader.createInstanceDisplayNameAlternative(getContext(), sortKey); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { - // TODO setup fast scroller. - adapter = new ContactsAdapter(getContext(), cursor); - recyclerView.setAdapter(adapter); - if (adapter.getItemCount() > 1) { - recyclerView.setOnScrollChangeListener(this); + if (cursor.getCount() == 0) { + emptyContentView.setDescription(R.string.all_contacts_empty); + emptyContentView.setActionLabel(R.string.all_contacts_empty_add_contact_action); + emptyContentView.setVisibility(View.VISIBLE); + } else { + emptyContentView.setVisibility(View.GONE); + adapter = new ContactsAdapter(getContext(), cursor); + manager = + new LinearLayoutManager(getContext()) { + @Override + public void onLayoutChildren(Recycler recycler, State state) { + super.onLayoutChildren(recycler, state); + int itemsShown = findLastVisibleItemPosition() - findFirstVisibleItemPosition() + 1; + if (adapter.getItemCount() > itemsShown) { + fastScroller.setVisibility(View.VISIBLE); + recyclerView.setOnScrollChangeListener(ContactsFragment.this); + } else { + fastScroller.setVisibility(View.GONE); + } + } + }; + + recyclerView.setLayoutManager(manager); + recyclerView.setAdapter(adapter); + fastScroller.setup(adapter, manager); } } @@ -81,6 +143,7 @@ public class ContactsFragment extends Fragment recyclerView.setAdapter(null); recyclerView.setOnScrollChangeListener(null); adapter = null; + contactsPrefs.unregisterChangeListener(); } /* @@ -95,8 +158,10 @@ public class ContactsFragment extends Fragment */ @Override public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { + fastScroller.updateContainerAndScrollBarPosition(recyclerView); int firstVisibleItem = manager.findFirstVisibleItemPosition(); int firstCompletelyVisible = manager.findFirstCompletelyVisibleItemPosition(); + String anchoredHeaderString = adapter.getHeaderString(firstCompletelyVisible); // If the user swipes to the top of the list very quickly, there is some strange behavior // between this method updating headers and adapter#onBindViewHolder updating headers. @@ -104,15 +169,46 @@ public class ContactsFragment extends Fragment if (firstVisibleItem == firstCompletelyVisible && firstVisibleItem == 0) { adapter.refreshHeaders(); anchoredHeader.setVisibility(View.INVISIBLE); + } else if (adapter.getHeaderString(firstVisibleItem).equals(anchoredHeaderString)) { + anchoredHeader.setText(anchoredHeaderString); + anchoredHeader.setVisibility(View.VISIBLE); + getContactHolder(firstVisibleItem).getHeaderView().setVisibility(View.INVISIBLE); + getContactHolder(firstCompletelyVisible).getHeaderView().setVisibility(View.INVISIBLE); } else { - boolean showAnchor = - adapter.getHeader(firstVisibleItem).equals(adapter.getHeader(firstCompletelyVisible)); - anchoredHeader.setText(adapter.getHeader(firstCompletelyVisible)); - anchoredHeader.setVisibility(showAnchor ? View.VISIBLE : View.INVISIBLE); - - int rowHeaderVisibility = showAnchor ? View.INVISIBLE : View.VISIBLE; - adapter.setHeaderVisibility(firstVisibleItem, rowHeaderVisibility); - adapter.setHeaderVisibility(firstCompletelyVisible, rowHeaderVisibility); + anchoredHeader.setVisibility(View.INVISIBLE); + getContactHolder(firstVisibleItem).getHeaderView().setVisibility(View.VISIBLE); + getContactHolder(firstCompletelyVisible).getHeaderView().setVisibility(View.VISIBLE); + } + } + + private ContactViewHolder getContactHolder(int position) { + return ((ContactViewHolder) recyclerView.findViewHolderForAdapterPosition(position)); + } + + @Override + public void onEmptyViewActionButtonClicked() { + if (emptyContentView.getActionLabel() == R.string.permission_single_turn_on) { + FragmentCompat.requestPermissions( + this, new String[] {permission.READ_CONTACTS}, READ_CONTACTS_PERMISSION_REQUEST_CODE); + } else if (emptyContentView.getActionLabel() + == R.string.all_contacts_empty_add_contact_action) { + // Add new contact + DialerUtils.startActivityWithErrorToast( + getContext(), IntentUtil.getNewContactIntent(), R.string.add_contact_not_available); + } else { + throw Assert.createIllegalStateFailException("Invalid empty content view action label."); + } + } + + @Override + public void onRequestPermissionsResult( + int requestCode, String[] permissions, int[] grantResults) { + if (requestCode == READ_CONTACTS_PERMISSION_REQUEST_CODE) { + if (grantResults.length >= 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) { + // Force a refresh of the data since we were missing the permission before this. + emptyContentView.setVisibility(View.GONE); + getLoaderManager().initLoader(0, null, this); + } } } } diff --git a/java/com/android/dialer/contactsfragment/FastScroller.java b/java/com/android/dialer/contactsfragment/FastScroller.java new file mode 100644 index 000000000..980032cb5 --- /dev/null +++ b/java/com/android/dialer/contactsfragment/FastScroller.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2017 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.contactsfragment; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.RelativeLayout; +import android.widget.TextView; + +/** Widget to add fast scrolling to {@link ContactsFragment}. */ +public class FastScroller extends RelativeLayout { + + private final int touchTargetWidth; + + private ContactsAdapter adapter; + private LinearLayoutManager layoutManager; + + private TextView container; + private View scrollBar; + + private boolean dragStarted; + + public FastScroller(Context context, AttributeSet attrs) { + super(context, attrs); + touchTargetWidth = + context.getResources().getDimensionPixelSize(R.dimen.fast_scroller_touch_target_width); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + container = (TextView) findViewById(R.id.fast_scroller_container); + scrollBar = findViewById(R.id.fast_scroller_scroll_bar); + } + + void setup(ContactsAdapter adapter, LinearLayoutManager layoutManager) { + this.adapter = adapter; + this.layoutManager = layoutManager; + } + + @Override + public boolean onTouchEvent(@NonNull MotionEvent event) { + // Don't override if touch event isn't within desired touch target and dragging hasn't started. + if (!dragStarted && getWidth() - touchTargetWidth - event.getX() > 0) { + return super.onTouchEvent(event); + } + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + dragStarted = true; + container.setVisibility(VISIBLE); + scrollBar.setSelected(true); + // fall through + case MotionEvent.ACTION_MOVE: + setContainerAndScrollBarPosition(event.getY()); + setRecyclerViewPosition(event.getY()); + return true; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + dragStarted = false; + container.setVisibility(INVISIBLE); + scrollBar.setSelected(false); + return true; + } + return super.onTouchEvent(event); + } + + private void setRecyclerViewPosition(float y) { + final int itemCount = adapter.getItemCount(); + float scrolledPosition = getScrolledPercentage(y) * (float) itemCount; + int targetPos = getValueInRange(0, itemCount - 1, (int) scrolledPosition); + layoutManager.scrollToPositionWithOffset(targetPos, 0); + container.setText(adapter.getHeaderString(targetPos)); + } + + // Returns a float in range [0, 1] which represents the position of the scroller. + private float getScrolledPercentage(float y) { + if (scrollBar.getY() == 0) { + return 0f; + } else if (scrollBar.getY() + scrollBar.getHeight() >= getHeight()) { + return 1f; + } else { + return y / (float) getHeight(); + } + } + + private int getValueInRange(int min, int max, int value) { + int minimum = Math.max(min, value); + return Math.min(minimum, max); + } + + void updateContainerAndScrollBarPosition(RecyclerView recyclerView) { + if (!scrollBar.isSelected()) { + int verticalScrollOffset = recyclerView.computeVerticalScrollOffset(); + int verticalScrollRange = recyclerView.computeVerticalScrollRange(); + float proportion = (float) verticalScrollOffset / ((float) verticalScrollRange - getHeight()); + setContainerAndScrollBarPosition(getHeight() * proportion); + } + } + + private void setContainerAndScrollBarPosition(float y) { + int scrollBarHeight = scrollBar.getHeight(); + int containerHeight = container.getHeight(); + scrollBar.setY( + getValueInRange(0, getHeight() - scrollBarHeight, (int) (y - scrollBarHeight / 2))); + container.setY( + getValueInRange( + 0, getHeight() - containerHeight - scrollBarHeight / 2, (int) (y - containerHeight))); + } +} diff --git a/java/com/android/dialer/contactsfragment/res/drawable/fast_scroller_container_background.xml b/java/com/android/dialer/contactsfragment/res/drawable/fast_scroller_container_background.xml new file mode 100644 index 000000000..a7b227799 --- /dev/null +++ b/java/com/android/dialer/contactsfragment/res/drawable/fast_scroller_container_background.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@color/dialer_theme_color"/> + <size + android:height="@dimen/fast_scroller_container_size" + android:width="@dimen/fast_scroller_container_size"/> + <corners + android:topLeftRadius="@dimen/fast_scroller_container_corner_radius" + android:topRightRadius="@dimen/fast_scroller_container_corner_radius" + android:bottomLeftRadius="@dimen/fast_scroller_bottom_left_corner_radius" + android:bottomRightRadius="@dimen/fast_scroller_bottom_right_corner_radius"/> +</shape>
\ No newline at end of file diff --git a/java/com/android/dialer/contactsfragment/res/drawable/fast_scroller_scroll_bar.xml b/java/com/android/dialer/contactsfragment/res/drawable/fast_scroller_scroll_bar.xml new file mode 100644 index 000000000..a3e0c25c7 --- /dev/null +++ b/java/com/android/dialer/contactsfragment/res/drawable/fast_scroller_scroll_bar.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2017 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 + --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true"> + <shape android:shape="rectangle"> + <solid android:color="@color/dialer_theme_color"/> + <size android:height="32dp" android:width="4dp"/> + <corners android:radius="2dp"/> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <solid android:color="@color/dialer_secondary_text_color"/> + <size android:height="32dp" android:width="4dp"/> + <corners android:radius="2dp"/> + </shape> + </item> +</selector>
\ No newline at end of file diff --git a/java/com/android/dialer/contactsfragment/res/layout/contact_row.xml b/java/com/android/dialer/contactsfragment/res/layout/contact_row.xml index af87c7f18..9e829fee4 100644 --- a/java/com/android/dialer/contactsfragment/res/layout/contact_row.xml +++ b/java/com/android/dialer/contactsfragment/res/layout/contact_row.xml @@ -43,11 +43,13 @@ <TextView android:id="@+id/contact_name" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="match_parent" android:paddingStart="@dimen/text_padding_start" android:paddingEnd="@dimen/text_padding_end" - android:gravity="center_vertical|start" + android:maxLines="1" + android:ellipsize="end" + android:gravity="center_vertical" android:textSize="@dimen/text_size" android:textColor="@color/dialer_primary_text_color" android:fontFamily="sans-serif"/> diff --git a/java/com/android/dialer/contactsfragment/res/layout/fragment_contacts.xml b/java/com/android/dialer/contactsfragment/res/layout/fragment_contacts.xml index 67b490f03..7cbc4f0e6 100644 --- a/java/com/android/dialer/contactsfragment/res/layout/fragment_contacts.xml +++ b/java/com/android/dialer/contactsfragment/res/layout/fragment_contacts.xml @@ -23,8 +23,46 @@ android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/background_dialer_white"/> + android:background="@color/background_dialer_light"/> + + <!-- Scrollbars are always on the right side of the screen. Layouts should use Rights/Left instead + of Start/End --> + <com.android.dialer.contactsfragment.FastScroller + android:id="@+id/fast_scroller" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginTop="8dp" + android:layout_marginBottom="8dp" + android:clipChildren="false"> + + <TextView + android:id="@+id/fast_scroller_container" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toLeftOf="@+id/fast_scroller_scroll_bar" + android:gravity="center" + android:textSize="48sp" + android:textColor="@color/background_dialer_white" + android:visibility="gone" + android:background="@drawable/fast_scroller_container_background"/> + + <ImageView + android:id="@+id/fast_scroller_scroll_bar" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="8dp" + android:layout_alignParentRight="true" + android:paddingRight="16dp" + android:src="@drawable/fast_scroller_scroll_bar" /> + </com.android.dialer.contactsfragment.FastScroller> <!-- Anchored header view --> <include layout="@layout/header"/> + + <com.android.dialer.widget.EmptyContentView + android:id="@+id/empty_list_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:visibility="gone"/> </FrameLayout> diff --git a/java/com/android/dialer/contactsfragment/res/values/dimens.xml b/java/com/android/dialer/contactsfragment/res/values/dimens.xml index 00d7c6d7e..f120014e2 100644 --- a/java/com/android/dialer/contactsfragment/res/values/dimens.xml +++ b/java/com/android/dialer/contactsfragment/res/values/dimens.xml @@ -25,4 +25,11 @@ <dimen name="text_padding_start">16dp</dimen> <dimen name="text_padding_end">8dp</dimen> <dimen name="text_size">16sp</dimen> -</resources> + + <dimen name="fast_scroller_touch_target_width">20dp</dimen> + + <dimen name="fast_scroller_container_size">88dp</dimen> + <dimen name="fast_scroller_container_corner_radius">44dp</dimen> + <dimen name="fast_scroller_bottom_right_corner_radius">0px</dimen> + <dimen name="fast_scroller_bottom_left_corner_radius">44dp</dimen> +</resources>
\ No newline at end of file |