summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/contactsfragment
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2017-05-03 10:27:13 -0700
committerEric Erfanian <erfanian@google.com>2017-05-03 12:01:21 -0700
commit8369df095a73a77b3715f8ae7ba06089cebca4ce (patch)
tree1a45d60921e293c6088efeaf4d9c408456f3e0e2 /java/com/android/dialer/contactsfragment
parentafa29d4a8659eeffc8d92a6216b154f594eeb895 (diff)
This change reflects the Dialer V10 RC00 branch.
RC00 is based on: branch: dialer-android_release_branch/153304843.1 synced to: 153304843 following the instructions at go/dialer-aosp-release. In this release: * Removes final apache sources. * Uses native lite compilation. More drops will follow with subsequent release candidates until we reach our final v10 release, in cadence with our prebuilt drops. Test: TreeHugger, on device Change-Id: Ic9684057230f9b579c777820c746cd21bf45ec0f
Diffstat (limited to 'java/com/android/dialer/contactsfragment')
-rw-r--r--java/com/android/dialer/contactsfragment/AndroidManifest.xml16
-rw-r--r--java/com/android/dialer/contactsfragment/ContactViewHolder.java82
-rw-r--r--java/com/android/dialer/contactsfragment/ContactsAdapter.java149
-rw-r--r--java/com/android/dialer/contactsfragment/ContactsCursorLoader.java53
-rw-r--r--java/com/android/dialer/contactsfragment/ContactsFragment.java112
-rw-r--r--java/com/android/dialer/contactsfragment/res/layout/contact_row.xml55
-rw-r--r--java/com/android/dialer/contactsfragment/res/layout/fragment_contacts.xml30
-rw-r--r--java/com/android/dialer/contactsfragment/res/layout/header.xml26
-rw-r--r--java/com/android/dialer/contactsfragment/res/values/dimens.xml28
9 files changed, 551 insertions, 0 deletions
diff --git a/java/com/android/dialer/contactsfragment/AndroidManifest.xml b/java/com/android/dialer/contactsfragment/AndroidManifest.xml
new file mode 100644
index 000000000..3c2750073
--- /dev/null
+++ b/java/com/android/dialer/contactsfragment/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<!--
+ ~ 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
+ -->
+<manifest package="com.android.dialer.contactsfragment"/>
diff --git a/java/com/android/dialer/contactsfragment/ContactViewHolder.java b/java/com/android/dialer/contactsfragment/ContactViewHolder.java
new file mode 100644
index 000000000..5df106dbc
--- /dev/null
+++ b/java/com/android/dialer/contactsfragment/ContactViewHolder.java
@@ -0,0 +1,82 @@
+/*
+ * 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.net.Uri;
+import android.provider.ContactsContract.QuickContact;
+import android.support.v7.widget.RecyclerView;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.QuickContactBadge;
+import android.widget.TextView;
+import com.android.dialer.common.Assert;
+
+/** View holder for a contact. */
+final class ContactViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
+
+ private final TextView header;
+ private final TextView name;
+ private final QuickContactBadge photo;
+
+ private String headerText;
+ private Uri contactUri;
+
+ public ContactViewHolder(View itemView) {
+ super(itemView);
+ itemView.findViewById(R.id.click_target).setOnClickListener(this);
+ header = (TextView) itemView.findViewById(R.id.header);
+ name = (TextView) itemView.findViewById(R.id.contact_name);
+ photo = (QuickContactBadge) itemView.findViewById(R.id.photo);
+ }
+
+ /**
+ * Binds the ViewHolder with relevant data.
+ *
+ * @param headerText populates the header view.
+ * @param displayName populates the name view.
+ * @param contactUri to be shown by the contact card on photo click.
+ * @param showHeader if header view should be shown {@code True}, {@code False} otherwise.
+ */
+ public void bind(String headerText, String displayName, Uri contactUri, boolean showHeader) {
+ Assert.checkArgument(!TextUtils.isEmpty(displayName));
+ this.contactUri = contactUri;
+ this.headerText = headerText;
+
+ name.setText(displayName);
+ header.setText(headerText);
+ header.setVisibility(showHeader ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ public QuickContactBadge getPhoto() {
+ return photo;
+ }
+
+ public String getHeader() {
+ return headerText;
+ }
+
+ public TextView getHeaderView() {
+ return header;
+ }
+
+ @Override
+ public void onClick(View v) {
+ 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
new file mode 100644
index 000000000..4692eff5d
--- /dev/null
+++ b/java/com/android/dialer/contactsfragment/ContactsAdapter.java
@@ -0,0 +1,149 @@
+/*
+ * 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.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
+import android.support.v4.util.ArrayMap;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.dialer.common.Assert;
+
+/** List adapter for the union of all contacts associated with every account on the device. */
+final class ContactsAdapter extends RecyclerView.Adapter<ContactViewHolder> {
+
+ private final ArrayMap<ContactViewHolder, Integer> holderMap = new ArrayMap<>();
+ private final Context context;
+ private final Cursor cursor;
+
+ // List of contact sublist headers
+ private final String[] headers;
+
+ // Number of contacts that correspond to each header in {@code headers}.
+ private final int[] counts;
+
+ public ContactsAdapter(Context context, Cursor cursor) {
+ this.context = context;
+ this.cursor = cursor;
+ headers = cursor.getExtras().getStringArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES);
+ counts = cursor.getExtras().getIntArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS);
+ }
+
+ @Override
+ public ContactViewHolder onCreateViewHolder(ViewGroup parent, int position) {
+ return new ContactViewHolder(
+ LayoutInflater.from(context).inflate(R.layout.contact_row, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(ContactViewHolder contactViewHolder, int position) {
+ holderMap.put(contactViewHolder, position);
+ cursor.moveToPosition(position);
+
+ String name = getDisplayName(cursor);
+ String header = getHeaderString(position);
+ Uri contactUri = getContactUri(cursor);
+
+ ContactPhotoManager.getInstance(context)
+ .loadDialerThumbnailOrPhoto(
+ contactViewHolder.getPhoto(),
+ contactUri,
+ getPhotoId(cursor),
+ getPhotoUri(cursor),
+ name,
+ 0);
+
+ String photoDescription =
+ context.getString(com.android.contacts.common.R.string.description_quick_contact_for, name);
+ contactViewHolder.getPhoto().setContentDescription(photoDescription);
+
+ // 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);
+ }
+ }
+
+ public void refreshHeaders() {
+ for (ContactViewHolder holder : holderMap.keySet()) {
+ onBindViewHolder(holder, holderMap.get(holder));
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ 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);
+ }
+
+ private static long getPhotoId(Cursor cursor) {
+ return cursor.getLong(ContactsCursorLoader.CONTACT_PHOTO_ID);
+ }
+
+ private static Uri getPhotoUri(Cursor cursor) {
+ String photoUri = cursor.getString(ContactsCursorLoader.CONTACT_PHOTO_URI);
+ return photoUri == null ? null : Uri.parse(photoUri);
+ }
+
+ private static Uri getContactUri(Cursor cursor) {
+ long contactId = cursor.getLong(ContactsCursorLoader.CONTACT_ID);
+ String lookupKey = cursor.getString(ContactsCursorLoader.CONTACT_LOOKUP_KEY);
+ return Contacts.getLookupUri(contactId, lookupKey);
+ }
+
+ private String getHeaderString(int position) {
+ int index = -1;
+ int sum = 0;
+ while (sum <= position) {
+ sum += counts[++index];
+ }
+ return headers[index];
+ }
+}
diff --git a/java/com/android/dialer/contactsfragment/ContactsCursorLoader.java b/java/com/android/dialer/contactsfragment/ContactsCursorLoader.java
new file mode 100644
index 000000000..6d4d21079
--- /dev/null
+++ b/java/com/android/dialer/contactsfragment/ContactsCursorLoader.java
@@ -0,0 +1,53 @@
+/*
+ * 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.content.CursorLoader;
+import android.provider.ContactsContract.Contacts;
+
+/** Cursor Loader for {@link ContactsFragment}. */
+final class ContactsCursorLoader extends CursorLoader {
+
+ public static final int CONTACT_ID = 0;
+ public static final int CONTACT_DISPLAY_NAME = 1;
+ public static final int CONTACT_PHOTO_ID = 2;
+ public static final int CONTACT_PHOTO_URI = 3;
+ public static final int CONTACT_LOOKUP_KEY = 4;
+
+ public static final String[] CONTACTS_PROJECTION =
+ new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_PRIMARY, // 1
+ Contacts.PHOTO_ID, // 2
+ Contacts.PHOTO_THUMBNAIL_URI, // 3
+ Contacts.LOOKUP_KEY, // 4
+ };
+
+ public ContactsCursorLoader(Context context) {
+ super(
+ context,
+ Contacts.CONTENT_URI
+ .buildUpon()
+ .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true")
+ .build(),
+ CONTACTS_PROJECTION,
+ null,
+ null,
+ Contacts.SORT_KEY_PRIMARY + " ASC");
+ }
+}
diff --git a/java/com/android/dialer/contactsfragment/ContactsFragment.java b/java/com/android/dialer/contactsfragment/ContactsFragment.java
new file mode 100644
index 000000000..18220601f
--- /dev/null
+++ b/java/com/android/dialer/contactsfragment/ContactsFragment.java
@@ -0,0 +1,112 @@
+/*
+ * 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.app.Fragment;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.Loader;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnScrollChangeListener;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/** Fragment containing a list of all contacts. */
+public class ContactsFragment extends Fragment
+ implements LoaderCallbacks<Cursor>, OnScrollChangeListener {
+
+ private TextView anchoredHeader;
+ private RecyclerView recyclerView;
+ private LinearLayoutManager manager;
+ private ContactsAdapter adapter;
+
+ @Nullable
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.fragment_contacts, container, false);
+ 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);
+ return view;
+ }
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ return new ContactsCursorLoader(getContext());
+ }
+
+ @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);
+ }
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ recyclerView.setAdapter(null);
+ recyclerView.setOnScrollChangeListener(null);
+ adapter = null;
+ }
+
+ /*
+ * When our recycler view updates, we need to ensure that our row headers and anchored header
+ * are in the correct state.
+ *
+ * The general rule is, when the row headers are shown, our anchored header is hidden. When the
+ * recycler view is scrolling through a sublist that has more than one element, we want to show
+ * out anchored header, to create the illusion that our row header has been anchored. In all
+ * other situations, we want to hide the anchor because that means we are transitioning between
+ * two sublists.
+ */
+ @Override
+ public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
+ int firstVisibleItem = manager.findFirstVisibleItemPosition();
+ int firstCompletelyVisible = manager.findFirstCompletelyVisibleItemPosition();
+
+ // 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.
+ // To overcome this, we refresh the headers to ensure they are correct.
+ if (firstVisibleItem == firstCompletelyVisible && firstVisibleItem == 0) {
+ adapter.refreshHeaders();
+ anchoredHeader.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);
+ }
+ }
+}
diff --git a/java/com/android/dialer/contactsfragment/res/layout/contact_row.xml b/java/com/android/dialer/contactsfragment/res/layout/contact_row.xml
new file mode 100644
index 000000000..af87c7f18
--- /dev/null
+++ b/java/com/android/dialer/contactsfragment/res/layout/contact_row.xml
@@ -0,0 +1,55 @@
+<?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
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/row_height">
+
+ <include layout="@layout/header"/>
+
+ <LinearLayout
+ android:id="@+id/click_target"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/header_width"
+ android:layout_marginEnd="@dimen/row_end_margin"
+ android:paddingTop="@dimen/row_top_bottom_padding"
+ android:paddingBottom="@dimen/row_top_bottom_padding"
+ android:paddingStart="@dimen/row_start_padding"
+ android:gravity="center_vertical"
+ android:background="?android:attr/selectableItemBackground">
+
+ <QuickContactBadge
+ android:id="@+id/photo"
+ android:layout_width="@dimen/photo_size"
+ android:layout_height="@dimen/photo_size"
+ android:clickable="false"/>
+
+ <TextView
+ android:id="@+id/contact_name"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingStart="@dimen/text_padding_start"
+ android:paddingEnd="@dimen/text_padding_end"
+ android:gravity="center_vertical|start"
+ android:textSize="@dimen/text_size"
+ android:textColor="@color/dialer_primary_text_color"
+ android:fontFamily="sans-serif"/>
+ </LinearLayout>
+</FrameLayout> \ No newline at end of file
diff --git a/java/com/android/dialer/contactsfragment/res/layout/fragment_contacts.xml b/java/com/android/dialer/contactsfragment/res/layout/fragment_contacts.xml
new file mode 100644
index 000000000..67b490f03
--- /dev/null
+++ b/java/com/android/dialer/contactsfragment/res/layout/fragment_contacts.xml
@@ -0,0 +1,30 @@
+<?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
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/recycler_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/background_dialer_white"/>
+
+ <!-- Anchored header view -->
+ <include layout="@layout/header"/>
+</FrameLayout>
diff --git a/java/com/android/dialer/contactsfragment/res/layout/header.xml b/java/com/android/dialer/contactsfragment/res/layout/header.xml
new file mode 100644
index 000000000..cb5e78a57
--- /dev/null
+++ b/java/com/android/dialer/contactsfragment/res/layout/header.xml
@@ -0,0 +1,26 @@
+<?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
+ -->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/header"
+ android:layout_width="@dimen/header_width"
+ android:layout_height="@dimen/row_height"
+ android:textColor="@color/dialer_theme_color"
+ android:gravity="center"
+ android:textSize="@dimen/text_size"
+ android:textStyle="bold"
+ android:fontFamily="sans-serif-medium"/> \ No newline at end of file
diff --git a/java/com/android/dialer/contactsfragment/res/values/dimens.xml b/java/com/android/dialer/contactsfragment/res/values/dimens.xml
new file mode 100644
index 000000000..e9d73e99b
--- /dev/null
+++ b/java/com/android/dialer/contactsfragment/res/values/dimens.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
+ -->
+<resources>
+ <dimen name="photo_size">40dp</dimen>
+ <dimen name="header_width">56dp</dimen>
+ <dimen name="row_height">56dp</dimen>
+ <dimen name="row_start_padding">16dp</dimen>
+ <dimen name="row_end_margin">16dp</dimen>
+ <dimen name="row_top_bottom_padding">8dp</dimen>
+
+ <dimen name="text_padding_start">16dp</dimen>
+ <dimen name="text_padding_end">8dp</dimen>
+ <dimen name="text_size">16sp</dimen>
+</resources> \ No newline at end of file