summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/calldetails
diff options
context:
space:
mode:
authorEric Erfanian <erfanian@google.com>2017-03-15 14:41:07 -0700
committerEric Erfanian <erfanian@google.com>2017-03-15 16:24:23 -0700
commitd5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9 (patch)
treeb54abbb51fb7d66e7755a1fbb5db023ff601090b /java/com/android/dialer/calldetails
parent30436e7e6d3f2c8755a91b2b6222b74d465a9e87 (diff)
Update Dialer source from latest green build.
* Refactor voicemail component * Add new enriched calling components Test: treehugger, manual aosp testing Change-Id: I521a0f86327d4b42e14d93927c7d613044ed5942
Diffstat (limited to 'java/com/android/dialer/calldetails')
-rw-r--r--java/com/android/dialer/calldetails/AndroidManifest.xml31
-rw-r--r--java/com/android/dialer/calldetails/CallDetailsActivity.java130
-rw-r--r--java/com/android/dialer/calldetails/CallDetailsAdapter.java97
-rw-r--r--java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java195
-rw-r--r--java/com/android/dialer/calldetails/CallDetailsFooterViewHolder.java67
-rw-r--r--java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java125
-rw-r--r--java/com/android/dialer/calldetails/nano/CallDetailsEntries.java440
-rw-r--r--java/com/android/dialer/calldetails/res/drawable/multimedia_image_background.xml20
-rw-r--r--java/com/android/dialer/calldetails/res/layout/call_details_activity.xml37
-rw-r--r--java/com/android/dialer/calldetails/res/layout/call_details_entry.xml73
-rw-r--r--java/com/android/dialer/calldetails/res/layout/call_details_footer.xml43
-rw-r--r--java/com/android/dialer/calldetails/res/layout/contact_container.xml60
-rw-r--r--java/com/android/dialer/calldetails/res/layout/ec_data_container.xml42
-rw-r--r--java/com/android/dialer/calldetails/res/menu/call_details_menu.xml23
-rw-r--r--java/com/android/dialer/calldetails/res/values/dimens.xml40
-rw-r--r--java/com/android/dialer/calldetails/res/values/strings.xml42
-rw-r--r--java/com/android/dialer/calldetails/res/values/styles.xml48
17 files changed, 1513 insertions, 0 deletions
diff --git a/java/com/android/dialer/calldetails/AndroidManifest.xml b/java/com/android/dialer/calldetails/AndroidManifest.xml
new file mode 100644
index 000000000..b71207ba2
--- /dev/null
+++ b/java/com/android/dialer/calldetails/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ 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
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.dialer.calldetails">
+ <application>
+ <activity
+ android:label="@string/call_details"
+ android:name="com.android.dialer.calldetails.CallDetailsActivity"
+ android:theme="@style/Theme.AppCompat.NoActionBar">
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:mimeType="vnd.android.cursor.item/calls"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/java/com/android/dialer/calldetails/CallDetailsActivity.java b/java/com/android/dialer/calldetails/CallDetailsActivity.java
new file mode 100644
index 000000000..6070640a0
--- /dev/null
+++ b/java/com/android/dialer/calldetails/CallDetailsActivity.java
@@ -0,0 +1,130 @@
+/*
+ * 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.calldetails;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.CallLog;
+import android.provider.CallLog.Calls;
+import android.support.annotation.NonNull;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.MenuItem;
+import android.widget.Toolbar;
+import com.android.dialer.callcomposer.nano.CallComposerContact;
+import com.android.dialer.calldetails.nano.CallDetailsEntries;
+import com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.AsyncTaskExecutors;
+import com.android.dialer.logging.Logger;
+import com.android.dialer.logging.nano.DialerImpression;
+import com.android.dialer.protos.ProtoParsers;
+
+/** Displays the details of a specific call log entry. */
+public class CallDetailsActivity extends AppCompatActivity {
+
+ private static final String EXTRA_CALL_DETAILS_ENTRIES = "call_details_entries";
+ private static final String EXTRA_CONTACT = "contact";
+ private static final String TASK_DELETE = "task_delete";
+
+ private CallDetailsEntry[] entries;
+
+ public static Intent newInstance(
+ Context context, @NonNull CallDetailsEntries details, @NonNull CallComposerContact contact) {
+ Assert.isNotNull(details);
+ Assert.isNotNull(contact);
+
+ Intent intent = new Intent(context, CallDetailsActivity.class);
+ ProtoParsers.put(intent, EXTRA_CONTACT, contact);
+ ProtoParsers.put(intent, EXTRA_CALL_DETAILS_ENTRIES, details);
+ return intent;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.call_details_activity);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setActionBar(toolbar);
+ toolbar.inflateMenu(R.menu.call_details_menu);
+ toolbar.setNavigationOnClickListener(v -> finish());
+ onHandleIntent(getIntent());
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ onHandleIntent(intent);
+ }
+
+ private void onHandleIntent(Intent intent) {
+ Bundle arguments = intent.getExtras();
+ CallComposerContact contact =
+ ProtoParsers.getFromInstanceState(arguments, EXTRA_CONTACT, new CallComposerContact());
+ entries =
+ ProtoParsers.getFromInstanceState(
+ arguments, EXTRA_CALL_DETAILS_ENTRIES, new CallDetailsEntries())
+ .entries;
+ RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
+ recyclerView.setLayoutManager(new LinearLayoutManager(this));
+ recyclerView.setAdapter(new CallDetailsAdapter(this, contact, entries));
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.call_detail_delete_menu_item) {
+ Logger.get(this).logImpression(DialerImpression.Type.USER_DELETED_CALL_LOG_ITEM);
+ AsyncTaskExecutors.createAsyncTaskExecutor().submit(TASK_DELETE, new DeleteCallsTask());
+ item.setEnabled(false);
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Delete specified calls from the call log. */
+ private class DeleteCallsTask extends AsyncTask<Void, Void, Void> {
+
+ private final String callIds;
+
+ DeleteCallsTask() {
+ StringBuilder callIds = new StringBuilder();
+ for (CallDetailsEntry entry : entries) {
+ if (callIds.length() != 0) {
+ callIds.append(",");
+ }
+ callIds.append(entry.callId);
+ }
+ this.callIds = callIds.toString();
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ getContentResolver()
+ .delete(Calls.CONTENT_URI, CallLog.Calls._ID + " IN (" + callIds + ")", null);
+ return null;
+ }
+
+ @Override
+ public void onPostExecute(Void result) {
+ finish();
+ }
+ }
+}
diff --git a/java/com/android/dialer/calldetails/CallDetailsAdapter.java b/java/com/android/dialer/calldetails/CallDetailsAdapter.java
new file mode 100644
index 000000000..954583077
--- /dev/null
+++ b/java/com/android/dialer/calldetails/CallDetailsAdapter.java
@@ -0,0 +1,97 @@
+/*
+ * 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.calldetails;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import com.android.dialer.callcomposer.nano.CallComposerContact;
+import com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry;
+import com.android.dialer.calllogutils.CallTypeHelper;
+import com.android.dialer.common.Assert;
+
+/** Adapter for RecyclerView in {@link CallDetailsActivity}. */
+public class CallDetailsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+
+ private static final int HEADER_VIEW_TYPE = 1;
+ private static final int CALL_ENTRY_VIEW_TYPE = 2;
+ private static final int FOOTER_VIEW_TYPE = 3;
+
+ private final CallComposerContact contact;
+ private final CallDetailsEntry[] callDetailsEntries;
+ private final CallTypeHelper callTypeHelper;
+
+ public CallDetailsAdapter(
+ Context context, CallComposerContact contact, CallDetailsEntry[] callDetailsEntries) {
+ this.contact = Assert.isNotNull(contact);
+ this.callDetailsEntries = Assert.isNotNull(callDetailsEntries);
+ callTypeHelper = new CallTypeHelper(context.getResources());
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ switch (viewType) {
+ case HEADER_VIEW_TYPE:
+ return new CallDetailsHeaderViewHolder(
+ inflater.inflate(R.layout.contact_container, parent, false));
+ case CALL_ENTRY_VIEW_TYPE:
+ return new CallDetailsEntryViewHolder(
+ inflater.inflate(R.layout.call_details_entry, parent, false));
+ case FOOTER_VIEW_TYPE:
+ return new CallDetailsFooterViewHolder(
+ inflater.inflate(R.layout.call_details_footer, parent, false));
+ default:
+ Assert.fail("No ViewHolder available for viewType: " + viewType);
+ return null;
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ if (position == 0) { // Header
+ ((CallDetailsHeaderViewHolder) holder).updateContactInfo(contact);
+ } else if (position == getItemCount() - 1) {
+ ((CallDetailsFooterViewHolder) holder).setPhoneNumber(contact.number);
+ } else {
+ CallDetailsEntryViewHolder viewHolder = (CallDetailsEntryViewHolder) holder;
+ viewHolder.setCallDetails(
+ contact.number,
+ callDetailsEntries[position - 1],
+ callTypeHelper,
+ position != getItemCount() - 2);
+ }
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (position == 0) { // Header
+ return HEADER_VIEW_TYPE;
+ } else if (position == getItemCount() - 1) {
+ return FOOTER_VIEW_TYPE;
+ } else {
+ return CALL_ENTRY_VIEW_TYPE;
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return callDetailsEntries.length + 2; // Header + footer
+ }
+}
diff --git a/java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java b/java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java
new file mode 100644
index 000000000..b1a70af0c
--- /dev/null
+++ b/java/com/android/dialer/calldetails/CallDetailsEntryViewHolder.java
@@ -0,0 +1,195 @@
+/*
+ * 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.calldetails;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.CallLog.Calls;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry;
+import com.android.dialer.calllogutils.CallEntryFormatter;
+import com.android.dialer.calllogutils.CallTypeHelper;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.compat.AppCompatConstants;
+import com.android.dialer.enrichedcall.historyquery.proto.nano.HistoryResult;
+import com.android.dialer.enrichedcall.historyquery.proto.nano.HistoryResult.Type;
+import com.android.dialer.util.CallUtil;
+import com.android.dialer.util.DialerUtils;
+import com.android.dialer.util.IntentUtil;
+
+/** ViewHolder for call entries in {@link CallDetailsActivity}. */
+public class CallDetailsEntryViewHolder extends ViewHolder {
+
+ private final ImageView callTypeIcon;
+ private final TextView callTypeText;
+ private final TextView callTime;
+ private final TextView callDuration;
+
+ private final View multimediaImageContainer;
+ private final View multimediaDetailsContainer;
+ private final View multimediaDivider;
+
+ private final TextView multimediaDetails;
+
+ private final ImageView multimediaImage;
+
+ // TODO: Display this when location is stored - b/36160042
+ @SuppressWarnings("unused")
+ private final TextView multimediaAttachmentsNumber;
+
+ private final Context context;
+
+ public CallDetailsEntryViewHolder(View container) {
+ super(container);
+ context = container.getContext();
+
+ callTypeIcon = (ImageView) container.findViewById(R.id.call_direction);
+ callTypeText = (TextView) container.findViewById(R.id.call_type);
+ callTime = (TextView) container.findViewById(R.id.call_time);
+ callDuration = (TextView) container.findViewById(R.id.call_duration);
+
+ multimediaImageContainer = container.findViewById(R.id.multimedia_image_container);
+ multimediaDetailsContainer = container.findViewById(R.id.ec_container);
+ multimediaDivider = container.findViewById(R.id.divider);
+ multimediaDetails = (TextView) container.findViewById(R.id.multimedia_details);
+ multimediaImage = (ImageView) container.findViewById(R.id.multimedia_image);
+ multimediaAttachmentsNumber =
+ (TextView) container.findViewById(R.id.multimedia_attachments_number);
+ }
+
+ void setCallDetails(
+ String number,
+ CallDetailsEntry entry,
+ CallTypeHelper callTypeHelper,
+ boolean showMultimediaDivider) {
+ int callType = entry.callType;
+ boolean isVideoCall =
+ (entry.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO
+ && CallUtil.isVideoEnabled(context);
+ boolean isPulledCall =
+ (entry.features & Calls.FEATURES_PULLED_EXTERNALLY) == Calls.FEATURES_PULLED_EXTERNALLY;
+
+ Drawable callIcon = getIconForCallType(context.getResources(), callType);
+ int color = getColorForCallType(context, callType);
+ callIcon.setColorFilter(color, PorterDuff.Mode.MULTIPLY);
+ callTime.setTextColor(color);
+ callTypeIcon.setImageDrawable(callIcon);
+
+ callTypeText.setText(callTypeHelper.getCallTypeText(callType, isVideoCall, isPulledCall));
+ callTime.setText(CallEntryFormatter.formatDate(context, entry.date));
+ if (CallTypeHelper.isMissedCallType(callType)) {
+ callDuration.setVisibility(View.GONE);
+ } else {
+ callDuration.setVisibility(View.VISIBLE);
+ callDuration.setText(
+ CallEntryFormatter.formatDurationAndDataUsage(context, entry.duration, entry.dataUsage));
+ }
+ setMultimediaDetails(number, entry, showMultimediaDivider);
+ }
+
+ private void setMultimediaDetails(String number, CallDetailsEntry entry, boolean showDivider) {
+ multimediaDivider.setVisibility(showDivider ? View.VISIBLE : View.GONE);
+ if (entry.historyResults == null || entry.historyResults.length <= 0) {
+ LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "no data, hiding UI");
+ multimediaDetailsContainer.setVisibility(View.GONE);
+ } else {
+
+ // TODO: b/36158891 Add room for 2 pieces of enriched call data. It's possible
+ // to have both call composer data and post call data for a single call.
+ HistoryResult historyResult = entry.historyResults[0];
+ multimediaDetailsContainer.setVisibility(View.VISIBLE);
+ multimediaDetailsContainer.setOnClickListener(
+ (v) -> {
+ DialerUtils.startActivityWithErrorToast(context, IntentUtil.getSendSmsIntent(number));
+ });
+ multimediaImageContainer.setClipToOutline(true);
+
+ if (!TextUtils.isEmpty(historyResult.imageUri)) {
+ LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "setting image");
+ multimediaImageContainer.setVisibility(View.VISIBLE);
+ multimediaImage.setImageURI(Uri.parse(historyResult.imageUri));
+ multimediaDetails.setText(
+ isIncoming(historyResult) ? R.string.received_a_photo : R.string.sent_a_photo);
+ } else {
+ LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "no image");
+ }
+
+ // Set text after image to overwrite the received/sent a photo text
+ if (!TextUtils.isEmpty(historyResult.text)) {
+ LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "showing text");
+ multimediaDetails.setText(
+ context.getString(R.string.message_in_quotes, historyResult.text));
+ } else {
+ LogUtil.i("CallDetailsEntryViewHolder.setMultimediaDetails", "no text");
+ }
+ }
+ }
+
+ private static boolean isIncoming(@NonNull HistoryResult historyResult) {
+ return historyResult.type == Type.INCOMING_POST_CALL
+ || historyResult.type == Type.INCOMING_CALL_COMPOSER;
+ }
+
+ private static Drawable getIconForCallType(Resources resources, int callType) {
+ switch (callType) {
+ case AppCompatConstants.CALLS_OUTGOING_TYPE:
+ return resources.getDrawable(R.drawable.quantum_ic_call_made_white_24);
+ case AppCompatConstants.CALLS_BLOCKED_TYPE:
+ return resources.getDrawable(R.drawable.quantum_ic_block_white_24);
+ case AppCompatConstants.CALLS_INCOMING_TYPE:
+ case AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE:
+ case AppCompatConstants.CALLS_REJECTED_TYPE:
+ return resources.getDrawable(R.drawable.quantum_ic_call_received_white_24);
+ case AppCompatConstants.CALLS_MISSED_TYPE:
+ default:
+ // It is possible for users to end up with calls with unknown call types in their
+ // call history, possibly due to 3rd party call log implementations (e.g. to
+ // distinguish between rejected and missed calls). Instead of crashing, just
+ // assume that all unknown call types are missed calls.
+ return resources.getDrawable(R.drawable.quantum_ic_call_missed_white_24);
+ }
+ }
+
+ private static @ColorInt int getColorForCallType(Context context, int callType) {
+ switch (callType) {
+ case AppCompatConstants.CALLS_OUTGOING_TYPE:
+ case AppCompatConstants.CALLS_VOICEMAIL_TYPE:
+ case AppCompatConstants.CALLS_BLOCKED_TYPE:
+ case AppCompatConstants.CALLS_INCOMING_TYPE:
+ case AppCompatConstants.CALLS_ANSWERED_EXTERNALLY_TYPE:
+ case AppCompatConstants.CALLS_REJECTED_TYPE:
+ return ContextCompat.getColor(context, R.color.dialer_secondary_text_color);
+ case AppCompatConstants.CALLS_MISSED_TYPE:
+ default:
+ // It is possible for users to end up with calls with unknown call types in their
+ // call history, possibly due to 3rd party call log implementations (e.g. to
+ // distinguish between rejected and missed calls). Instead of crashing, just
+ // assume that all unknown call types are missed calls.
+ return ContextCompat.getColor(context, R.color.missed_call);
+ }
+ }
+}
diff --git a/java/com/android/dialer/calldetails/CallDetailsFooterViewHolder.java b/java/com/android/dialer/calldetails/CallDetailsFooterViewHolder.java
new file mode 100644
index 000000000..36662bab9
--- /dev/null
+++ b/java/com/android/dialer/calldetails/CallDetailsFooterViewHolder.java
@@ -0,0 +1,67 @@
+/*
+ * 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.calldetails;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.view.View.OnClickListener;
+import com.android.contacts.common.ClipboardUtils;
+import com.android.dialer.common.Assert;
+import com.android.dialer.logging.Logger;
+import com.android.dialer.logging.nano.DialerImpression;
+import com.android.dialer.util.CallUtil;
+import com.android.dialer.util.DialerUtils;
+
+/** ViewHolder container for {@link CallDetailsActivity} footer. */
+public class CallDetailsFooterViewHolder extends RecyclerView.ViewHolder
+ implements OnClickListener {
+
+ private final View copy;
+ private final View edit;
+
+ private String number;
+
+ public CallDetailsFooterViewHolder(View view) {
+ super(view);
+ copy = view.findViewById(R.id.call_detail_action_copy);
+ edit = view.findViewById(R.id.call_detail_action_edit_before_call);
+
+ copy.setOnClickListener(this);
+ edit.setOnClickListener(this);
+ }
+
+ public void setPhoneNumber(String number) {
+ this.number = number;
+ }
+
+ @Override
+ public void onClick(View view) {
+ Context context = view.getContext();
+ if (view == copy) {
+ Logger.get(context).logImpression(DialerImpression.Type.CALL_DETAILS_COPY_NUMBER);
+ ClipboardUtils.copyText(context, null, number, true);
+ } else if (view == edit) {
+ Logger.get(context).logImpression(DialerImpression.Type.CALL_DETAILS_EDIT_BEFORE_CALL);
+ Intent dialIntent = new Intent(Intent.ACTION_DIAL, CallUtil.getCallUri(number));
+ DialerUtils.startActivityWithErrorToast(context, dialIntent);
+ } else {
+ Assert.fail("View on click not implemented: " + view);
+ }
+ }
+}
diff --git a/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java b/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java
new file mode 100644
index 000000000..1679c2baf
--- /dev/null
+++ b/java/com/android/dialer/calldetails/CallDetailsHeaderViewHolder.java
@@ -0,0 +1,125 @@
+/*
+ * 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.calldetails;
+
+import android.content.Context;
+import android.net.Uri;
+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.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.util.UriUtils;
+import com.android.dialer.callcomposer.nano.CallComposerContact;
+import com.android.dialer.callintent.CallIntentBuilder;
+import com.android.dialer.callintent.nano.CallInitiationType;
+import com.android.dialer.common.Assert;
+import com.android.dialer.logging.Logger;
+import com.android.dialer.logging.nano.DialerImpression;
+import com.android.dialer.util.DialerUtils;
+
+/** ViewHolder for Header/Contact in {@link CallDetailsActivity}. */
+public class CallDetailsHeaderViewHolder extends RecyclerView.ViewHolder
+ implements OnClickListener {
+
+ private final View callBackButton;
+ private final TextView nameView;
+ private final TextView numberView;
+ private final QuickContactBadge contactPhoto;
+ private final Context context;
+
+ private CallComposerContact contact;
+
+ CallDetailsHeaderViewHolder(View container) {
+ super(container);
+ context = container.getContext();
+ callBackButton = container.findViewById(R.id.call_back_button);
+ nameView = (TextView) container.findViewById(R.id.contact_name);
+ numberView = (TextView) container.findViewById(R.id.phone_number);
+ contactPhoto = (QuickContactBadge) container.findViewById(R.id.quick_contact_photo);
+ callBackButton.setOnClickListener(this);
+ }
+
+ /**
+ * Populates the contact info fields based on the current contact information. Copied from {@link
+ * com.android.contacts.common.dialog.CallSubjectDialog}.
+ */
+ public void updateContactInfo(CallComposerContact contact) {
+ this.contact = contact;
+ setPhoto(
+ contact.photoId,
+ Uri.parse(contact.photoUri),
+ Uri.parse(contact.contactUri),
+ contact.nameOrNumber,
+ contact.isBusiness);
+
+ nameView.setText(contact.nameOrNumber);
+ if (!TextUtils.isEmpty(contact.numberLabel) && !TextUtils.isEmpty(contact.displayNumber)) {
+ numberView.setVisibility(View.VISIBLE);
+ String secondaryInfo =
+ context.getString(
+ com.android.contacts.common.R.string.call_subject_type_and_number,
+ contact.numberLabel,
+ contact.displayNumber);
+ numberView.setText(secondaryInfo);
+ } else {
+ numberView.setVisibility(View.GONE);
+ numberView.setText(null);
+ }
+ }
+
+ /**
+ * Sets the photo on the quick contact galleryIcon. Copied from {@link
+ * com.android.contacts.common.dialog.CallSubjectDialog}.
+ */
+ private void setPhoto(
+ long photoId, Uri photoUri, Uri contactUri, String displayName, boolean isBusiness) {
+ contactPhoto.assignContactUri(contactUri);
+ contactPhoto.setOverlay(null);
+
+ int contactType =
+ isBusiness ? ContactPhotoManager.TYPE_BUSINESS : ContactPhotoManager.TYPE_DEFAULT;
+ String lookupKey = contactUri == null ? null : UriUtils.getLookupKeyFromUri(contactUri);
+
+ ContactPhotoManager.DefaultImageRequest request =
+ new ContactPhotoManager.DefaultImageRequest(
+ displayName, lookupKey, contactType, true /* isCircular */);
+
+ if (photoId == 0 && photoUri != null) {
+ contactPhoto.setImageDrawable(
+ context.getDrawable(R.drawable.product_logo_avatar_anonymous_color_120));
+ } else {
+ ContactPhotoManager.getInstance(context)
+ .loadThumbnail(
+ contactPhoto, photoId, false /* darkTheme */, true /* isCircular */, request);
+ }
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view == callBackButton) {
+ Logger.get(view.getContext()).logImpression(DialerImpression.Type.CALL_DETAILS_CALL_BACK);
+ DialerUtils.startActivityWithErrorToast(
+ view.getContext(),
+ new CallIntentBuilder(contact.number, CallInitiationType.Type.CALL_DETAILS).build());
+ } else {
+ Assert.fail("View OnClickListener not implemented: " + view);
+ }
+ }
+}
diff --git a/java/com/android/dialer/calldetails/nano/CallDetailsEntries.java b/java/com/android/dialer/calldetails/nano/CallDetailsEntries.java
new file mode 100644
index 000000000..aee8f3652
--- /dev/null
+++ b/java/com/android/dialer/calldetails/nano/CallDetailsEntries.java
@@ -0,0 +1,440 @@
+/*
+ * 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.
+ */
+
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+package com.android.dialer.calldetails.nano;
+
+/** This file is autogenerated, but javadoc required. */
+@SuppressWarnings("hiding")
+public final class CallDetailsEntries
+ extends com.google.protobuf.nano.ExtendableMessageNano<CallDetailsEntries> {
+
+ /** This file is autogenerated, but javadoc required. */
+ public static final class CallDetailsEntry
+ extends com.google.protobuf.nano.ExtendableMessageNano<CallDetailsEntry> {
+
+ private static volatile CallDetailsEntry[] _emptyArray;
+ public static CallDetailsEntry[] emptyArray() {
+ // Lazily initializes the empty array
+ if (_emptyArray == null) {
+ synchronized (com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {
+ if (_emptyArray == null) {
+ _emptyArray = new CallDetailsEntry[0];
+ }
+ }
+ }
+ return _emptyArray;
+ }
+
+ // optional int64 call_id = 1;
+ public long callId;
+
+ // optional int32 call_type = 2;
+ public int callType;
+
+ // optional int32 features = 3;
+ public int features;
+
+ // optional int64 date = 4;
+ public long date;
+
+ // optional int64 duration = 5;
+ public long duration;
+
+ // optional int64 data_usage = 6;
+ public long dataUsage;
+
+ // repeated .com.android.dialer.enrichedcall.historyquery.proto.
+ // HistoryResult history_results = 7;
+ public com.android.dialer.enrichedcall.historyquery.proto.nano.HistoryResult[] historyResults;
+
+ // @@protoc_insertion_point(class_scope:com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry)
+
+ public CallDetailsEntry() {
+ clear();
+ }
+
+ public CallDetailsEntry clear() {
+ callId = 0L;
+ callType = 0;
+ features = 0;
+ date = 0L;
+ duration = 0L;
+ dataUsage = 0L;
+ historyResults =
+ com.android.dialer.enrichedcall.historyquery.proto.nano.HistoryResult.emptyArray();
+ unknownFieldData = null;
+ cachedSize = -1;
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof CallDetailsEntry)) {
+ return false;
+ }
+ CallDetailsEntry other = (CallDetailsEntry) o;
+ if (this.callId != other.callId) {
+ return false;
+ }
+ if (this.callType != other.callType) {
+ return false;
+ }
+ if (this.features != other.features) {
+ return false;
+ }
+ if (this.date != other.date) {
+ return false;
+ }
+ if (this.duration != other.duration) {
+ return false;
+ }
+ if (this.dataUsage != other.dataUsage) {
+ return false;
+ }
+ if (!com.google.protobuf.nano.InternalNano.equals(
+ this.historyResults, other.historyResults)) {
+ return false;
+ }
+ if (unknownFieldData == null || unknownFieldData.isEmpty()) {
+ return other.unknownFieldData == null || other.unknownFieldData.isEmpty();
+ } else {
+ return unknownFieldData.equals(other.unknownFieldData);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + getClass().getName().hashCode();
+ result = 31 * result + (int) (this.callId ^ (this.callId >>> 32));
+ result = 31 * result + this.callType;
+ result = 31 * result + this.features;
+ result = 31 * result + (int) (this.date ^ (this.date >>> 32));
+ result = 31 * result + (int) (this.duration ^ (this.duration >>> 32));
+ result = 31 * result + (int) (this.dataUsage ^ (this.dataUsage >>> 32));
+ result = 31 * result + com.google.protobuf.nano.InternalNano.hashCode(this.historyResults);
+ result =
+ 31 * result
+ + (unknownFieldData == null || unknownFieldData.isEmpty()
+ ? 0
+ : unknownFieldData.hashCode());
+ return result;
+ }
+
+ @Override
+ public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)
+ throws java.io.IOException {
+ if (this.callId != 0L) {
+ output.writeInt64(1, this.callId);
+ }
+ if (this.callType != 0) {
+ output.writeInt32(2, this.callType);
+ }
+ if (this.features != 0) {
+ output.writeInt32(3, this.features);
+ }
+ if (this.date != 0L) {
+ output.writeInt64(4, this.date);
+ }
+ if (this.duration != 0L) {
+ output.writeInt64(5, this.duration);
+ }
+ if (this.dataUsage != 0L) {
+ output.writeInt64(6, this.dataUsage);
+ }
+ if (this.historyResults != null && this.historyResults.length > 0) {
+ for (int i = 0; i < this.historyResults.length; i++) {
+ com.android.dialer.enrichedcall.historyquery.proto.nano.HistoryResult element =
+ this.historyResults[i];
+ if (element != null) {
+ output.writeMessage(7, element);
+ }
+ }
+ }
+ super.writeTo(output);
+ }
+
+ @Override
+ protected int computeSerializedSize() {
+ int size = super.computeSerializedSize();
+ if (this.callId != 0L) {
+ size += com.google.protobuf.nano.CodedOutputByteBufferNano.computeInt64Size(1, this.callId);
+ }
+ if (this.callType != 0) {
+ size +=
+ com.google.protobuf.nano.CodedOutputByteBufferNano.computeInt32Size(2, this.callType);
+ }
+ if (this.features != 0) {
+ size +=
+ com.google.protobuf.nano.CodedOutputByteBufferNano.computeInt32Size(3, this.features);
+ }
+ if (this.date != 0L) {
+ size += com.google.protobuf.nano.CodedOutputByteBufferNano.computeInt64Size(4, this.date);
+ }
+ if (this.duration != 0L) {
+ size +=
+ com.google.protobuf.nano.CodedOutputByteBufferNano.computeInt64Size(5, this.duration);
+ }
+ if (this.dataUsage != 0L) {
+ size +=
+ com.google.protobuf.nano.CodedOutputByteBufferNano.computeInt64Size(6, this.dataUsage);
+ }
+ if (this.historyResults != null && this.historyResults.length > 0) {
+ for (int i = 0; i < this.historyResults.length; i++) {
+ com.android.dialer.enrichedcall.historyquery.proto.nano.HistoryResult element =
+ this.historyResults[i];
+ if (element != null) {
+ size +=
+ com.google.protobuf.nano.CodedOutputByteBufferNano.computeMessageSize(7, element);
+ }
+ }
+ }
+ return size;
+ }
+
+ @Override
+ public CallDetailsEntry mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano input)
+ throws java.io.IOException {
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ return this;
+ default:
+ {
+ if (!super.storeUnknownField(input, tag)) {
+ return this;
+ }
+ break;
+ }
+ case 8:
+ {
+ this.callId = input.readInt64();
+ break;
+ }
+ case 16:
+ {
+ this.callType = input.readInt32();
+ break;
+ }
+ case 24:
+ {
+ this.features = input.readInt32();
+ break;
+ }
+ case 32:
+ {
+ this.date = input.readInt64();
+ break;
+ }
+ case 40:
+ {
+ this.duration = input.readInt64();
+ break;
+ }
+ case 48:
+ {
+ this.dataUsage = input.readInt64();
+ break;
+ }
+ case 58:
+ {
+ int arrayLength =
+ com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, 58);
+ int i = this.historyResults == null ? 0 : this.historyResults.length;
+ com.android.dialer.enrichedcall.historyquery.proto.nano.HistoryResult[] newArray =
+ new com.android.dialer.enrichedcall.historyquery.proto.nano.HistoryResult
+ [i + arrayLength];
+ if (i != 0) {
+ java.lang.System.arraycopy(this.historyResults, 0, newArray, 0, i);
+ }
+ for (; i < newArray.length - 1; i++) {
+ newArray[i] =
+ new com.android.dialer.enrichedcall.historyquery.proto.nano.HistoryResult();
+ input.readMessage(newArray[i]);
+ input.readTag();
+ }
+ // Last one without readTag.
+ newArray[i] =
+ new com.android.dialer.enrichedcall.historyquery.proto.nano.HistoryResult();
+ input.readMessage(newArray[i]);
+ this.historyResults = newArray;
+ break;
+ }
+ }
+ }
+ }
+
+ public static CallDetailsEntry parseFrom(byte[] data)
+ throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {
+ return com.google.protobuf.nano.MessageNano.mergeFrom(new CallDetailsEntry(), data);
+ }
+
+ public static CallDetailsEntry parseFrom(
+ com.google.protobuf.nano.CodedInputByteBufferNano input) throws java.io.IOException {
+ return new CallDetailsEntry().mergeFrom(input);
+ }
+ }
+
+ private static volatile CallDetailsEntries[] _emptyArray;
+ public static CallDetailsEntries[] emptyArray() {
+ // Lazily initializes the empty array
+ if (_emptyArray == null) {
+ synchronized (com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {
+ if (_emptyArray == null) {
+ _emptyArray = new CallDetailsEntries[0];
+ }
+ }
+ }
+ return _emptyArray;
+ }
+
+ // repeated .com.android.dialer.calldetails.CallDetailsEntries.CallDetailsEntry entries = 1;
+ public com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry[] entries;
+
+ // @@protoc_insertion_point(class_scope:com.android.dialer.calldetails.CallDetailsEntries)
+
+ public CallDetailsEntries() {
+ clear();
+ }
+
+ public CallDetailsEntries clear() {
+ entries = com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry.emptyArray();
+ unknownFieldData = null;
+ cachedSize = -1;
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof CallDetailsEntries)) {
+ return false;
+ }
+ CallDetailsEntries other = (CallDetailsEntries) o;
+ if (!com.google.protobuf.nano.InternalNano.equals(this.entries, other.entries)) {
+ return false;
+ }
+ if (unknownFieldData == null || unknownFieldData.isEmpty()) {
+ return other.unknownFieldData == null || other.unknownFieldData.isEmpty();
+ } else {
+ return unknownFieldData.equals(other.unknownFieldData);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + getClass().getName().hashCode();
+ result = 31 * result + com.google.protobuf.nano.InternalNano.hashCode(this.entries);
+ result =
+ 31 * result
+ + (unknownFieldData == null || unknownFieldData.isEmpty()
+ ? 0
+ : unknownFieldData.hashCode());
+ return result;
+ }
+
+ @Override
+ public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)
+ throws java.io.IOException {
+ if (this.entries != null && this.entries.length > 0) {
+ for (int i = 0; i < this.entries.length; i++) {
+ com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry element =
+ this.entries[i];
+ if (element != null) {
+ output.writeMessage(1, element);
+ }
+ }
+ }
+ super.writeTo(output);
+ }
+
+ @Override
+ protected int computeSerializedSize() {
+ int size = super.computeSerializedSize();
+ if (this.entries != null && this.entries.length > 0) {
+ for (int i = 0; i < this.entries.length; i++) {
+ com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry element =
+ this.entries[i];
+ if (element != null) {
+ size += com.google.protobuf.nano.CodedOutputByteBufferNano.computeMessageSize(1, element);
+ }
+ }
+ }
+ return size;
+ }
+
+ @Override
+ public CallDetailsEntries mergeFrom(com.google.protobuf.nano.CodedInputByteBufferNano input)
+ throws java.io.IOException {
+ while (true) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ return this;
+ default:
+ {
+ if (!super.storeUnknownField(input, tag)) {
+ return this;
+ }
+ break;
+ }
+ case 10:
+ {
+ int arrayLength =
+ com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, 10);
+ int i = this.entries == null ? 0 : this.entries.length;
+ com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry[] newArray =
+ new com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry
+ [i + arrayLength];
+ if (i != 0) {
+ java.lang.System.arraycopy(this.entries, 0, newArray, 0, i);
+ }
+ for (; i < newArray.length - 1; i++) {
+ newArray[i] =
+ new com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry();
+ input.readMessage(newArray[i]);
+ input.readTag();
+ }
+ // Last one without readTag.
+ newArray[i] =
+ new com.android.dialer.calldetails.nano.CallDetailsEntries.CallDetailsEntry();
+ input.readMessage(newArray[i]);
+ this.entries = newArray;
+ break;
+ }
+ }
+ }
+ }
+
+ public static CallDetailsEntries parseFrom(byte[] data)
+ throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {
+ return com.google.protobuf.nano.MessageNano.mergeFrom(new CallDetailsEntries(), data);
+ }
+
+ public static CallDetailsEntries parseFrom(
+ com.google.protobuf.nano.CodedInputByteBufferNano input) throws java.io.IOException {
+ return new CallDetailsEntries().mergeFrom(input);
+ }
+}
diff --git a/java/com/android/dialer/calldetails/res/drawable/multimedia_image_background.xml b/java/com/android/dialer/calldetails/res/drawable/multimedia_image_background.xml
new file mode 100644
index 000000000..421bdbfee
--- /dev/null
+++ b/java/com/android/dialer/calldetails/res/drawable/multimedia_image_background.xml
@@ -0,0 +1,20 @@
+<?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">
+ <corners android:radius="2dp"/>
+</shape>
diff --git a/java/com/android/dialer/calldetails/res/layout/call_details_activity.xml b/java/com/android/dialer/calldetails/res/layout/call_details_activity.xml
new file mode 100644
index 000000000..038a8745e
--- /dev/null
+++ b/java/com/android/dialer/calldetails/res/layout/call_details_activity.xml
@@ -0,0 +1,37 @@
+<?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
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="@color/dialer_theme_color"
+ android:elevation="4dp"
+ android:titleTextAppearance="@style/toolbar_title_text"
+ android:title="@string/call_details"
+ android:navigationIcon="@drawable/quantum_ic_arrow_back_white_24"/>
+
+ <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"/>
+</LinearLayout> \ No newline at end of file
diff --git a/java/com/android/dialer/calldetails/res/layout/call_details_entry.xml b/java/com/android/dialer/calldetails/res/layout/call_details_entry.xml
new file mode 100644
index 000000000..7f8bb8087
--- /dev/null
+++ b/java/com/android/dialer/calldetails/res/layout/call_details_entry.xml
@@ -0,0 +1,73 @@
+<?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
+ -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/call_entry_padding">
+
+ <ImageView
+ android:id="@+id/call_direction"
+ android:layout_width="@dimen/call_entry_icon_size"
+ android:layout_height="@dimen/call_entry_icon_size"
+ android:layout_marginStart="@dimen/call_entry_padding"
+ android:layout_marginEnd="@dimen/call_entry_left_margin"/>
+
+ <TextView
+ android:id="@+id/call_type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toEndOf="@+id/call_direction"
+ style="@style/PrimaryText"/>
+
+ <TextView
+ android:id="@+id/call_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toEndOf="@id/call_direction"
+ android:layout_below="@+id/call_type"
+ android:layout_marginBottom="@dimen/call_entry_bottom_padding"
+ style="@style/SecondaryText"/>
+
+ <TextView
+ android:id="@+id/call_duration"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_marginEnd="@dimen/call_entry_padding"
+ style="@style/PrimaryText"/>
+
+ <include
+ layout="@layout/ec_data_container"
+ android:id="@+id/ec_container"
+ android:layout_height="@dimen/ec_container_height"
+ android:layout_width="match_parent"
+ android:layout_marginStart="@dimen/ec_text_left_margin"
+ android:layout_below="@+id/call_time"
+ android:visibility="gone"/>
+
+ <View
+ android:id="@+id/divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_below="@id/ec_container"
+ android:layout_marginTop="@dimen/ec_divider_top_bottom_margin"
+ android:layout_marginBottom="@dimen/ec_divider_top_bottom_margin"
+ android:layout_marginStart="@dimen/ec_text_left_margin"
+ android:background="#12000000"
+ android:visibility="gone"/>
+</RelativeLayout> \ No newline at end of file
diff --git a/java/com/android/dialer/calldetails/res/layout/call_details_footer.xml b/java/com/android/dialer/calldetails/res/layout/call_details_footer.xml
new file mode 100644
index 000000000..885cb0989
--- /dev/null
+++ b/java/com/android/dialer/calldetails/res/layout/call_details_footer.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_marginTop="@dimen/ec_divider_top_bottom_margin"
+ android:layout_marginBottom="@dimen/ec_divider_top_bottom_margin"
+ android:background="#12000000"/>
+
+ <TextView
+ android:id="@+id/call_detail_action_copy"
+ style="@style/CallDetailsActionItemStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:drawableStart="@drawable/quantum_ic_content_copy_grey600_24"
+ android:text="@string/call_details_copy_number"/>
+
+ <TextView
+ android:id="@+id/call_detail_action_edit_before_call"
+ style="@style/CallDetailsActionItemStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:drawableStart="@drawable/quantum_ic_edit_grey600_24"
+ android:text="@string/call_details_edit_number"/>
+</LinearLayout>
diff --git a/java/com/android/dialer/calldetails/res/layout/contact_container.xml b/java/com/android/dialer/calldetails/res/layout/contact_container.xml
new file mode 100644
index 000000000..95fe189b2
--- /dev/null
+++ b/java/com/android/dialer/calldetails/res/layout/contact_container.xml
@@ -0,0 +1,60 @@
+<?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
+ -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:padding="@dimen/contact_container_padding">
+
+ <QuickContactBadge
+ android:id="@+id/quick_contact_photo"
+ android:layout_width="@dimen/call_details_contact_photo_size"
+ android:layout_height="@dimen/call_details_contact_photo_size"
+ android:focusable="true"/>
+
+ <TextView
+ android:id="@+id/contact_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/text_bottom_margin"
+ android:layout_marginStart="@dimen/photo_text_margin"
+ android:layout_toEndOf="@+id/quick_contact_photo"
+ android:layout_toStartOf="@+id/call_back_button"
+ style="@style/PrimaryText"/>
+
+ <TextView
+ android:id="@+id/phone_number"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/photo_text_margin"
+ android:layout_toEndOf="@+id/quick_contact_photo"
+ android:layout_toStartOf="@+id/call_back_button"
+ android:layout_below="@+id/contact_name"
+ style="@style/SecondaryText"/>
+
+ <ImageView
+ android:id="@+id/call_back_button"
+ android:layout_width="@dimen/call_back_button_size"
+ android:layout_height="@dimen/call_back_button_size"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/description_call_log_call_action"
+ android:src="@drawable/quantum_ic_call_white_24"
+ android:tint="@color/secondary_text_color"/>
+</RelativeLayout> \ No newline at end of file
diff --git a/java/com/android/dialer/calldetails/res/layout/ec_data_container.xml b/java/com/android/dialer/calldetails/res/layout/ec_data_container.xml
new file mode 100644
index 000000000..5ad7912fa
--- /dev/null
+++ b/java/com/android/dialer/calldetails/res/layout/ec_data_container.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/ec_container_height">
+
+ <TextView
+ android:id="@+id/multimedia_details"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:maxLines="2"
+ style="@style/SecondaryText"/>
+
+ <FrameLayout
+ android:id="@+id/multimedia_image_container"
+ android:layout_width="@dimen/ec_photo_size"
+ android:layout_height="@dimen/ec_photo_size"
+ android:layout_alignParentEnd="true"
+ android:layout_marginEnd="@dimen/call_entry_padding"
+ android:layout_centerVertical="true"
+ android:background="@drawable/multimedia_image_background"
+ android:outlineProvider="background"
+ android:visibility="gone">
+
+ <ImageView
+ android:id="@+id/multimedia_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop"/>
+
+ <com.android.incallui.autoresizetext.AutoResizeTextView
+ android:id="@+id/multimedia_attachments_number"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="4dp"
+ android:gravity="center"
+ android:textColor="@color/background_dialer_white"
+ android:textSize="100sp"
+ android:background="#80000000"
+ android:visibility="gone"/>
+ </FrameLayout>
+</RelativeLayout> \ No newline at end of file
diff --git a/java/com/android/dialer/calldetails/res/menu/call_details_menu.xml b/java/com/android/dialer/calldetails/res/menu/call_details_menu.xml
new file mode 100644
index 000000000..c2d1032da
--- /dev/null
+++ b/java/com/android/dialer/calldetails/res/menu/call_details_menu.xml
@@ -0,0 +1,23 @@
+<?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
+ -->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/call_detail_delete_menu_item"
+ android:icon="@drawable/quantum_ic_delete_white_24"
+ android:title="@string/delete"
+ android:showAsAction="ifRoom"/>
+</menu> \ No newline at end of file
diff --git a/java/com/android/dialer/calldetails/res/values/dimens.xml b/java/com/android/dialer/calldetails/res/values/dimens.xml
new file mode 100644
index 000000000..b1a8f1c8e
--- /dev/null
+++ b/java/com/android/dialer/calldetails/res/values/dimens.xml
@@ -0,0 +1,40 @@
+<?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="text_bottom_margin">2dp</dimen>
+ <dimen name="call_details_primary_text_size">16sp</dimen>
+ <dimen name="call_details_secondary_text_size">14sp</dimen>
+
+ <!-- contact container -->
+ <dimen name="contact_container_padding">16dp</dimen>
+ <dimen name="call_details_contact_photo_size">40dp</dimen>
+ <dimen name="photo_text_margin">16dp</dimen>
+ <dimen name="call_back_button_size">24dp</dimen>
+
+ <!-- call entry container -->
+ <dimen name="call_entry_icon_size">24dp</dimen>
+ <dimen name="call_entry_padding">16dp</dimen>
+ <dimen name="call_entry_bottom_padding">14dp</dimen>
+ <dimen name="call_entry_left_margin">32dp</dimen>
+
+ <!-- EC container -->
+ <dimen name="call_details_ec_text_size">12sp</dimen>
+ <dimen name="ec_container_height">48dp</dimen>
+ <dimen name="ec_text_left_margin">72dp</dimen>
+ <dimen name="ec_photo_size">40dp</dimen>
+ <dimen name="ec_divider_top_bottom_margin">8dp</dimen>
+</resources> \ No newline at end of file
diff --git a/java/com/android/dialer/calldetails/res/values/strings.xml b/java/com/android/dialer/calldetails/res/values/strings.xml
new file mode 100644
index 000000000..8a7cc4cfc
--- /dev/null
+++ b/java/com/android/dialer/calldetails/res/values/strings.xml
@@ -0,0 +1,42 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Title bar for call detail screen -->
+ <string name="call_details">Call details</string>
+
+ <!-- Menu item in call details used to remove a call or voicemail from the call log. -->
+ <string name="delete">Delete</string>
+
+ <!-- Option displayed in context menu to copy long pressed phone number. [CHAR LIMIT=48] -->
+ <string name="call_details_copy_number">Copy number</string>
+
+ <!-- Label for action to edit a number before calling it. [CHAR LIMIT=48] -->
+ <string name="call_details_edit_number">Edit number before call</string>
+
+ <!-- String describing the phone icon on a call log list item. When tapped, it will place a
+ call to the number represented by that call log entry. [CHAR LIMIT=NONE]-->
+ <string name="description_call_log_call_action">Call</string>
+
+ <!-- String shown when the call details show a image that was sent -->
+ <string name="sent_a_photo">Sent a photo</string>
+
+ <!-- String shown when the call details show a image that was received -->
+ <string name="received_a_photo">Received a photo</string>
+
+ <!-- Messages shown to the user are wrapped in quotes, e.g. the user would see "Some text" -->
+ <string name="message_in_quotes">\"<xliff:g id="message">%1$s</xliff:g>\"</string>
+</resources>
diff --git a/java/com/android/dialer/calldetails/res/values/styles.xml b/java/com/android/dialer/calldetails/res/values/styles.xml
new file mode 100644
index 000000000..4fffe1afb
--- /dev/null
+++ b/java/com/android/dialer/calldetails/res/values/styles.xml
@@ -0,0 +1,48 @@
+<?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>
+ <style name="PrimaryText">
+ <item name="android:textColor">#DE000000</item>
+ <item name="android:textSize">@dimen/call_details_primary_text_size</item>
+ <item name="android:maxLines">1</item>
+ </style>
+
+ <style name="SecondaryText">
+ <item name="android:textColor">#8A000000</item>
+ <item name="android:textSize">@dimen/call_details_secondary_text_size</item>
+ <item name="android:maxLines">1</item>
+ </style>
+
+ <style name="ECText">
+ <item name="android:textColor">#8A000000</item>
+ <item name="android:textSize">@dimen/call_details_ec_text_size</item>
+ <item name="android:maxLines">1</item>
+ </style>
+
+ <style name="CallDetailsActionItemStyle">
+ <item name="android:foreground">?android:attr/selectableItemBackground</item>
+ <item name="android:clickable">true</item>
+ <item name="android:drawablePadding">28dp</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:paddingStart">28dp</item>
+ <item name="android:paddingEnd">28dp</item>
+ <item name="android:paddingTop">16dp</item>
+ <item name="android:paddingBottom">16dp</item>
+ <item name="android:textColor">#8A000000</item>
+ <item name="android:textSize">14sp</item>
+ </style>
+</resources> \ No newline at end of file