diff options
Diffstat (limited to 'java/com/android/dialer/calllog/ui')
9 files changed, 469 insertions, 178 deletions
diff --git a/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java b/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java index 13a801ac8..9f635439a 100644 --- a/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java +++ b/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java @@ -18,115 +18,37 @@ package com.android.dialer.calllog.ui; import android.content.Context; import android.database.Cursor; -import android.support.annotation.ColorInt; import android.support.v4.content.CursorLoader; +import com.android.dialer.DialerPhoneNumber; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.CoalescedAnnotatedCallLog; +import com.android.dialer.calllog.model.CoalescedRow; +import com.google.protobuf.InvalidProtocolBufferException; /** CursorLoader for the coalesced annotated call log. */ final class CoalescedAnnotatedCallLogCursorLoader extends CursorLoader { - /** Indexes for CoalescedAnnotatedCallLog.ALL_COLUMNS */ + // Indexes for CoalescedAnnotatedCallLog.ALL_COLUMNS private static final int ID = 0; - private static final int TIMESTAMP = 1; private static final int NAME = 2; - private static final int FORMATTED_NUMBER = 3; - private static final int PHOTO_URI = 4; - private static final int PHOTO_ID = 5; - private static final int LOOKUP_URI = 6; - private static final int NUMBER_TYPE_LABEL = 7; - private static final int IS_READ = 8; - private static final int NEW = 9; - private static final int GEOCODED_LOCATION = 10; - private static final int PHONE_ACCOUNT_LABEL = 11; - private static final int PHONE_ACCOUNT_COLOR = 12; - private static final int FEATURES = 13; - private static final int IS_BUSINESS = 14; - private static final int IS_VOICEMAIL = 15; - private static final int TYPE = 16; - private static final int NUMBER_CALLS = 17; - - /** Convenience class for accessing values using an abbreviated syntax. */ - static final class Row { - private final Cursor cursor; - - Row(Cursor cursor) { - this.cursor = cursor; - } - - long id() { - return cursor.getInt(ID); - } - - long timestamp() { - return cursor.getLong(TIMESTAMP); - } - - String name() { - return cursor.getString(NAME); - } - - String formattedNumber() { - return cursor.getString(FORMATTED_NUMBER); - } - - String photoUri() { - return cursor.getString(PHOTO_URI); - } - - long photoId() { - return cursor.getLong(PHOTO_ID); - } - - String lookupUri() { - return cursor.getString(LOOKUP_URI); - } - - String numberTypeLabel() { - return cursor.getString(NUMBER_TYPE_LABEL); - } - - boolean isRead() { - return cursor.getInt(IS_READ) == 1; - } - - boolean isNew() { - return cursor.getInt(NEW) == 1; - } - - String geocodedLocation() { - return cursor.getString(GEOCODED_LOCATION); - } - - String phoneAccountLabel() { - return cursor.getString(PHONE_ACCOUNT_LABEL); - } - - @ColorInt - int phoneAccountColor() { - return cursor.getInt(PHONE_ACCOUNT_COLOR); - } - - int features() { - return cursor.getInt(FEATURES); - } - - boolean isBusiness() { - return cursor.getInt(IS_BUSINESS) == 1; - } - - boolean isVoicemail() { - return cursor.getInt(IS_VOICEMAIL) == 1; - } - - int numberCalls() { - return cursor.getInt(NUMBER_CALLS); - } - - int callType() { - return cursor.getInt(TYPE); - } - } + private static final int NUMBER = 3; + private static final int FORMATTED_NUMBER = 4; + private static final int PHOTO_URI = 5; + private static final int PHOTO_ID = 6; + private static final int LOOKUP_URI = 7; + private static final int NUMBER_TYPE_LABEL = 8; + private static final int IS_READ = 9; + private static final int NEW = 10; + private static final int GEOCODED_LOCATION = 11; + private static final int PHONE_ACCOUNT_COMPONENT_NAME = 12; + private static final int PHONE_ACCOUNT_ID = 13; + private static final int PHONE_ACCOUNT_LABEL = 14; + private static final int PHONE_ACCOUNT_COLOR = 15; + private static final int FEATURES = 16; + private static final int IS_BUSINESS = 17; + private static final int IS_VOICEMAIL = 18; + private static final int CALL_TYPE = 19; + private static final int NUMBER_CALLS = 20; CoalescedAnnotatedCallLogCursorLoader(Context context) { // CoalescedAnnotatedCallLog requires that PROJECTION be ALL_COLUMNS and the following params be @@ -139,4 +61,42 @@ final class CoalescedAnnotatedCallLogCursorLoader extends CursorLoader { null, null); } + + /** Creates a new {@link CoalescedRow} from the provided cursor using the current position. */ + static CoalescedRow toRow(Cursor cursor) { + DialerPhoneNumber number; + try { + number = DialerPhoneNumber.parseFrom(cursor.getBlob(NUMBER)); + } catch (InvalidProtocolBufferException e) { + throw new IllegalStateException("Couldn't parse DialerPhoneNumber bytes"); + } + + return CoalescedRow.builder() + .setId(cursor.getInt(ID)) + .setTimestamp(cursor.getLong(TIMESTAMP)) + .setName(cursor.getString(NAME)) + .setNumber(number) + .setFormattedNumber(cursor.getString(FORMATTED_NUMBER)) + .setPhotoUri(cursor.getString(PHOTO_URI)) + .setPhotoId(cursor.getLong(PHOTO_ID)) + .setLookupUri(cursor.getString(LOOKUP_URI)) + .setNumberTypeLabel(cursor.getString(NUMBER_TYPE_LABEL)) + .setIsRead(cursor.getInt(IS_READ) == 1) + .setIsNew(cursor.getInt(NEW) == 1) + .setGeocodedLocation(cursor.getString(GEOCODED_LOCATION)) + .setPhoneAccountComponentName(cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME)) + .setPhoneAccountId(cursor.getString(PHONE_ACCOUNT_ID)) + .setPhoneAccountLabel(cursor.getString(PHONE_ACCOUNT_LABEL)) + .setPhoneAccountColor(cursor.getInt(PHONE_ACCOUNT_COLOR)) + .setFeatures(cursor.getInt(FEATURES)) + .setIsBusiness(cursor.getInt(IS_BUSINESS) == 1) + .setIsVoicemail(cursor.getInt(IS_VOICEMAIL) == 1) + .setCallType(cursor.getInt(CALL_TYPE)) + .setNumberCalls(cursor.getInt(NUMBER_CALLS)) + .build(); + } + + static long getTimestamp(Cursor cursor) { + return cursor.getLong(TIMESTAMP); + } } diff --git a/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java b/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java index b922a6e3b..d5cfb7e24 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java @@ -58,15 +58,14 @@ final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { // Calculate header adapter positions by reading cursor. long currentTimeMillis = clock.currentTimeMillis(); if (cursor.moveToNext()) { - CoalescedAnnotatedCallLogCursorLoader.Row firstRow = - new CoalescedAnnotatedCallLogCursorLoader.Row(cursor); - if (CallLogDates.isSameDay(currentTimeMillis, firstRow.timestamp())) { + long firstTimestamp = CoalescedAnnotatedCallLogCursorLoader.getTimestamp(cursor); + if (CallLogDates.isSameDay(currentTimeMillis, firstTimestamp)) { this.todayHeaderPosition = 0; int adapterPosition = 2; // Accounted for "Today" header and first row. while (cursor.moveToNext()) { - CoalescedAnnotatedCallLogCursorLoader.Row row = - new CoalescedAnnotatedCallLogCursorLoader.Row(cursor); - if (CallLogDates.isSameDay(currentTimeMillis, row.timestamp())) { + long timestamp = CoalescedAnnotatedCallLogCursorLoader.getTimestamp(cursor); + + if (CallLogDates.isSameDay(currentTimeMillis, timestamp)) { adapterPosition++; } else { this.olderHeaderPosition = adapterPosition; diff --git a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java index 8ac419e56..4e59301ce 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java @@ -16,16 +16,19 @@ package com.android.dialer.calllog.ui; import android.content.Context; +import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.provider.CallLog.Calls; import android.support.v7.widget.RecyclerView; -import android.text.TextUtils; import android.view.View; +import android.widget.ImageView; import android.widget.QuickContactBadge; import android.widget.TextView; -import com.android.dialer.calllog.ui.CoalescedAnnotatedCallLogCursorLoader.Row; -import com.android.dialer.calllogutils.CallLogDates; +import com.android.dialer.calllog.model.CoalescedRow; +import com.android.dialer.calllog.ui.menu.NewCallLogMenu; +import com.android.dialer.calllogutils.CallLogEntryText; +import com.android.dialer.calllogutils.CallLogIntents; import com.android.dialer.calllogutils.CallTypeIconsView; import com.android.dialer.contactphoto.ContactPhotoManager; import com.android.dialer.lettertile.LetterTileDrawable; @@ -43,6 +46,8 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { private final CallTypeIconsView primaryCallTypeIconsView; // Used for Wifi, HD icons private final CallTypeIconsView secondaryCallTypeIconsView; // Used for call types private final TextView phoneAccountView; + private final ImageView menuButton; + private final Clock clock; NewCallLogViewHolder(View view, Clock clock) { @@ -54,17 +59,18 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { primaryCallTypeIconsView = view.findViewById(R.id.primary_call_type_icons); secondaryCallTypeIconsView = view.findViewById(R.id.secondary_call_type_icons); phoneAccountView = view.findViewById(R.id.phone_account); + menuButton = view.findViewById(R.id.menu_button); + this.clock = clock; } /** @param cursor a cursor from {@link CoalescedAnnotatedCallLogCursorLoader}. */ void bind(Cursor cursor) { - CoalescedAnnotatedCallLogCursorLoader.Row row = - new CoalescedAnnotatedCallLogCursorLoader.Row(cursor); + CoalescedRow row = CoalescedAnnotatedCallLogCursorLoader.toRow(cursor); // TODO(zachh): Handle RTL properly. - primaryTextView.setText(buildPrimaryText(row)); - secondaryTextView.setText(buildSecondaryText(row)); + primaryTextView.setText(CallLogEntryText.buildPrimaryText(context, row)); + secondaryTextView.setText(CallLogEntryText.buildSecondaryTextForEntries(context, clock, row)); if (isNewMissedCall(row)) { primaryTextView.setTextAppearance(R.style.primary_textview_new_call); @@ -72,77 +78,29 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { secondaryTextView.setTextAppearance(R.style.secondary_textview_new_call); } + setNumberCalls(row); setPhoto(row); setPrimaryCallTypes(row); setSecondaryCallTypes(row); setPhoneAccounts(row); + setOnClickListenerForRow(row); + setOnClickListenerForMenuButon(row); } - private String buildPrimaryText(CoalescedAnnotatedCallLogCursorLoader.Row row) { - StringBuilder primaryText = new StringBuilder(); - if (!TextUtils.isEmpty(row.name())) { - primaryText.append(row.name()); - } else if (!TextUtils.isEmpty(row.formattedNumber())) { - primaryText.append(row.formattedNumber()); - } else { - // TODO(zachh): Handle CallLog.Calls.PRESENTATION_*, including Verizon restricted numbers. - primaryText.append(context.getText(R.string.new_call_log_unknown)); - } + private void setNumberCalls(CoalescedRow row) { + // TODO(zachh): Number of calls shouldn't be text, but a circle with a number inside. if (row.numberCalls() > 1) { - primaryText.append(String.format(Locale.getDefault(), " (%d)", row.numberCalls())); + primaryTextView.append(String.format(Locale.getDefault(), " (%d)", row.numberCalls())); } - return primaryText.toString(); } - private boolean isNewMissedCall(CoalescedAnnotatedCallLogCursorLoader.Row row) { + private boolean isNewMissedCall(CoalescedRow row) { // Show missed call styling if the most recent call in the group was missed and it is still // marked as NEW. It is not clear what IS_READ should be used for and it is currently not used. return row.callType() == Calls.MISSED_TYPE && row.isNew(); } - private String buildSecondaryText(CoalescedAnnotatedCallLogCursorLoader.Row row) { - /* - * Rules: (Duo video, )?$Label|$Location • Date - * - * Examples: - * Duo Video, Mobile • Now - * Duo Video • 11:45pm - * Mobile • 11:45pm - * Mobile • Sunday - * Brooklyn, NJ • Jan 15 - * - * Date rules: - * if < 1 minute ago: "Now"; else if today: HH:MM(am|pm); else if < 3 days: day; else: MON D - */ - StringBuilder secondaryText = new StringBuilder(); - if ((row.features() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) { - // TODO(zachh): Add "Duo" prefix? - secondaryText.append(context.getText(R.string.new_call_log_video)); - } - String numberTypeLabel = row.numberTypeLabel(); - if (!TextUtils.isEmpty(numberTypeLabel)) { - if (secondaryText.length() > 0) { - secondaryText.append(", "); - } - secondaryText.append(numberTypeLabel); - } else { // If there's a number type label, don't show the location. - String location = row.geocodedLocation(); - if (!TextUtils.isEmpty(location)) { - if (secondaryText.length() > 0) { - secondaryText.append(", "); - } - secondaryText.append(location); - } - } - if (secondaryText.length() > 0) { - secondaryText.append(" • "); - } - secondaryText.append( - CallLogDates.newCallLogTimestampLabel(context, clock.currentTimeMillis(), row.timestamp())); - return secondaryText.toString(); - } - - private void setPhoto(Row row) { + private void setPhoto(CoalescedRow row) { // TODO(zachh): Set the contact type. ContactPhotoManager.getInstance(context) .loadDialerThumbnailOrPhoto( @@ -154,7 +112,7 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { LetterTileDrawable.TYPE_DEFAULT); } - private void setPrimaryCallTypes(Row row) { + private void setPrimaryCallTypes(CoalescedRow row) { // Only HD and Wifi icons are shown following the primary text. primaryCallTypeIconsView.setShowHd( MotorolaUtils.shouldShowHdIconInCallLog(context, row.features())); @@ -162,18 +120,32 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { MotorolaUtils.shouldShowWifiIconInCallLog(context, row.features())); } - private void setSecondaryCallTypes(Row row) { + private void setSecondaryCallTypes(CoalescedRow row) { // Only call type icon is shown before the secondary text. secondaryCallTypeIconsView.add(row.callType()); // TODO(zachh): Per new mocks, may need to add method to CallTypeIconsView to disable coloring. } - private void setPhoneAccounts(Row row) { + private void setPhoneAccounts(CoalescedRow row) { if (row.phoneAccountLabel() != null) { phoneAccountView.setText(row.phoneAccountLabel()); phoneAccountView.setTextColor(row.phoneAccountColor()); phoneAccountView.setVisibility(View.VISIBLE); } } + + private void setOnClickListenerForRow(CoalescedRow row) { + itemView.setOnClickListener( + (view) -> { + Intent callbackIntent = CallLogIntents.getCallBackIntent(row); + if (callbackIntent != null) { + context.startActivity(callbackIntent); + } + }); + } + + private void setOnClickListenerForMenuButon(CoalescedRow row) { + menuButton.setOnClickListener(NewCallLogMenu.createOnClickListener(context, row)); + } } diff --git a/java/com/android/dialer/calllog/ui/menu/AndroidManifest.xml b/java/com/android/dialer/calllog/ui/menu/AndroidManifest.xml new file mode 100644 index 000000000..0d8274dff --- /dev/null +++ b/java/com/android/dialer/calllog/ui/menu/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.calllog.ui.menu"/> diff --git a/java/com/android/dialer/calllog/ui/menu/Modules.java b/java/com/android/dialer/calllog/ui/menu/Modules.java new file mode 100644 index 000000000..8de63518c --- /dev/null +++ b/java/com/android/dialer/calllog/ui/menu/Modules.java @@ -0,0 +1,234 @@ +/* + * 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.calllog.ui.menu; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.provider.CallLog.Calls; +import android.provider.ContactsContract; +import android.telecom.PhoneAccountHandle; +import android.text.TextUtils; +import com.android.dialer.calldetails.CallDetailsActivity; +import com.android.dialer.calldetails.CallDetailsEntries; +import com.android.dialer.callintent.CallInitiationType; +import com.android.dialer.calllog.model.CoalescedRow; +import com.android.dialer.calllogutils.PhoneAccountUtils; +import com.android.dialer.clipboard.ClipboardUtils; +import com.android.dialer.contactactions.ContactActionModule; +import com.android.dialer.contactactions.DividerModule; +import com.android.dialer.contactactions.IntentModule; +import com.android.dialer.dialercontact.DialerContact; +import com.android.dialer.lettertile.LetterTileDrawable; +import com.android.dialer.util.IntentUtil; +import com.android.dialer.util.UriUtils; +import java.util.ArrayList; +import java.util.List; + +/** + * Configures the modules for the bottom sheet; these are the rows below the top row (primary + * action) in the bottom sheet. + */ +final class Modules { + + static List<ContactActionModule> fromRow(Context context, CoalescedRow row) { + // Conditionally add each module, which are items in the bottom sheet's menu. + List<ContactActionModule> modules = new ArrayList<>(); + + maybeAddModuleForVideoOrAudioCall(context, row, modules); + maybeAddModuleForAddingToContacts(context, row, modules); + + String originalNumber = row.number().getRawInput().getNumber(); + maybeAddModuleForSendingTextMessage(context, originalNumber, modules); + + if (!modules.isEmpty()) { + modules.add(new DividerModule()); + } + + // TODO(zachh): Module for blocking/unblocking spam. + // TODO(zachh): Module for CallComposer. + maybeAddModuleForCopyingNumber(context, originalNumber, modules); + + // TODO(zachh): Revisit if DialerContact is the best thing to pass to CallDetails; could + // it use a ContactPrimaryActionInfo instead? + addModuleForAccessingCallDetails(context, createDialerContactFromRow(row), modules); + + return modules; + } + + private static void maybeAddModuleForVideoOrAudioCall( + Context context, CoalescedRow row, List<ContactActionModule> modules) { + String originalNumber = row.number().getRawInput().getNumber(); + if (TextUtils.isEmpty(originalNumber)) { + // Skip adding the menu item if the phone number is unknown. + return; + } + + PhoneAccountHandle phoneAccountHandle = + PhoneAccountUtils.getAccount(row.phoneAccountComponentName(), row.phoneAccountId()); + + if ((row.features() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) { + // Add an audio call item for video calls. Clicking the top entry on the bottom sheet will + // trigger a video call. + modules.add( + IntentModule.newCallModule( + context, originalNumber, phoneAccountHandle, CallInitiationType.Type.CALL_LOG)); + } else { + // Add a video call item for audio calls. Click the top entry on the bottom sheet will + // trigger an audio call. + // TODO(zachh): Only show video option if video capabilities present? + modules.add( + IntentModule.newVideoCallModule( + context, originalNumber, phoneAccountHandle, CallInitiationType.Type.CALL_LOG)); + } + } + + private static void maybeAddModuleForAddingToContacts( + Context context, CoalescedRow row, List<ContactActionModule> modules) { + // TODO(zachh): Only show this for non-spam/blocked numbers. + + // Skip showing the menu item for existing contacts. + if (isExistingContact(row)) { + return; + } + + // Skip showing the menu item if there is no number. + String originalNumber = row.number().getRawInput().getNumber(); + if (TextUtils.isEmpty(originalNumber)) { + return; + } + + Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT); + intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE); + intent.putExtra(ContactsContract.Intents.Insert.PHONE, originalNumber); + + if (!TextUtils.isEmpty(row.name())) { + intent.putExtra(ContactsContract.Intents.Insert.NAME, row.name()); + } + modules.add( + new IntentModule( + context, + intent, + R.string.add_to_contacts, + R.drawable.quantum_ic_person_add_vd_theme_24)); + } + + /** + * Lookup URIs are currently fetched from the cached column of the system call log. This URI + * contains encoded information for non-contacts for the purposes of populating contact cards. + * + * <p>We infer whether a contact is existing or not by checking if the lookup URI is "encoded" or + * not. + * + * <p>TODO(zachh): We should revisit this once the contact URI is no longer being read from the + * cached column in the system database, in case we decide not to overload the column. + */ + private static boolean isExistingContact(CoalescedRow row) { + return !TextUtils.isEmpty(row.lookupUri()) + && !UriUtils.isEncodedContactUri(Uri.parse(row.lookupUri())); + } + + private static void maybeAddModuleForSendingTextMessage( + Context context, String originalNumber, List<ContactActionModule> modules) { + // TODO(zachh): There are some conditions where this module should not be shown; consider + // voicemail, business numbers, blocked numbers, spam numbers, etc. + if (!TextUtils.isEmpty(originalNumber)) { + modules.add( + new IntentModule( + context, + IntentUtil.getSendSmsIntent(originalNumber), + R.string.send_a_message, + R.drawable.quantum_ic_message_vd_theme_24)); + } + } + + private static void maybeAddModuleForCopyingNumber( + Context context, String originalNumber, List<ContactActionModule> modules) { + if (TextUtils.isEmpty(originalNumber)) { + return; + } + modules.add( + new ContactActionModule() { + @Override + public int getStringId() { + return R.string.copy_number; + } + + @Override + public int getDrawableId() { + return R.drawable.quantum_ic_content_copy_vd_theme_24; + } + + @Override + public boolean onClick() { + ClipboardUtils.copyText(context, null, originalNumber, true); + return false; + } + }); + } + + private static void addModuleForAccessingCallDetails( + Context context, DialerContact dialerContact, List<ContactActionModule> modules) { + // TODO(zachh): Load CallDetailsEntries and canReportInaccurateNumber in + // CallDetailsActivity (see also isPeopleApiSource(sourceType)). + CallDetailsEntries callDetailsEntries = CallDetailsEntries.getDefaultInstance(); + boolean canReportInaccurateNumber = false; + boolean canSupportAssistedDialing = false; // TODO(zachh): Properly set value. + + modules.add( + new IntentModule( + context, + CallDetailsActivity.newInstance( + context, + callDetailsEntries, + dialerContact, + canReportInaccurateNumber, + canSupportAssistedDialing), + R.string.call_details, + R.drawable.quantum_ic_info_outline_vd_theme_24)); + } + + private static DialerContact createDialerContactFromRow(CoalescedRow row) { + // TODO(zachh): Do something with parsed values to make more dialable? + String originalNumber = row.number().getRawInput().getNumber(); + + DialerContact.Builder dialerContactBuilder = + DialerContact.newBuilder() + .setNumber(originalNumber) + .setContactType(LetterTileDrawable.TYPE_DEFAULT) // TODO(zachh): Use proper type. + .setPhotoId(row.photoId()); + + if (!TextUtils.isEmpty(row.name())) { + dialerContactBuilder.setNameOrNumber(row.name()); + } else if (!TextUtils.isEmpty(originalNumber)) { + dialerContactBuilder.setNameOrNumber(originalNumber); + } + if (row.numberTypeLabel() != null) { + dialerContactBuilder.setNumberLabel(row.numberTypeLabel()); + } + if (row.photoUri() != null) { + dialerContactBuilder.setPhotoUri(row.photoUri()); + } + if (row.lookupUri() != null) { + dialerContactBuilder.setContactUri(row.lookupUri()); + } + if (row.formattedNumber() != null) { + dialerContactBuilder.setDisplayNumber(row.formattedNumber()); + } + return dialerContactBuilder.build(); + } +} diff --git a/java/com/android/dialer/calllog/ui/menu/NewCallLogMenu.java b/java/com/android/dialer/calllog/ui/menu/NewCallLogMenu.java new file mode 100644 index 000000000..2ae823e7f --- /dev/null +++ b/java/com/android/dialer/calllog/ui/menu/NewCallLogMenu.java @@ -0,0 +1,33 @@ +/* + * 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.calllog.ui.menu; + +import android.content.Context; +import android.view.View; +import com.android.dialer.calllog.model.CoalescedRow; +import com.android.dialer.contactactions.ContactActionBottomSheet; + +/** Handles configuration of the bottom sheet menus for call log entries. */ +public final class NewCallLogMenu { + + /** Creates and returns the OnClickListener which opens the menu for the provided row. */ + public static View.OnClickListener createOnClickListener(Context context, CoalescedRow row) { + return (view) -> + ContactActionBottomSheet.show( + context, PrimaryAction.fromRow(context, row), Modules.fromRow(context, row)); + } +} diff --git a/java/com/android/dialer/calllog/ui/menu/PrimaryAction.java b/java/com/android/dialer/calllog/ui/menu/PrimaryAction.java new file mode 100644 index 000000000..7077d0231 --- /dev/null +++ b/java/com/android/dialer/calllog/ui/menu/PrimaryAction.java @@ -0,0 +1,48 @@ +/* + * 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.calllog.ui.menu; + +import android.content.Context; +import android.provider.CallLog.Calls; +import com.android.dialer.calllog.model.CoalescedRow; +import com.android.dialer.calllogutils.CallLogEntryText; +import com.android.dialer.calllogutils.CallLogIntents; +import com.android.dialer.contactactions.ContactPrimaryActionInfo; +import com.android.dialer.contactactions.ContactPrimaryActionInfo.PhotoInfo; +import com.android.dialer.lettertile.LetterTileDrawable; + +/** Configures the primary action row (top row) for the bottom sheet. */ +final class PrimaryAction { + + static ContactPrimaryActionInfo fromRow(Context context, CoalescedRow row) { + return ContactPrimaryActionInfo.builder() + .setNumber(row.number()) + .setPhotoInfo( + PhotoInfo.builder() + .setPhotoId(row.photoId()) + .setPhotoUri(row.photoUri()) + .setLookupUri(row.lookupUri()) + .setIsVideo((row.features() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) + .setContactType(LetterTileDrawable.TYPE_DEFAULT) // TODO(zachh): Use proper type. + .setDisplayName(row.name()) + .build()) + .setPrimaryText(CallLogEntryText.buildPrimaryText(context, row)) + .setSecondaryText(CallLogEntryText.buildSecondaryTextForBottomSheet(context, row)) + .setIntent(CallLogIntents.getCallBackIntent(row)) + .build(); + } +} diff --git a/java/com/android/dialer/calllog/ui/menu/res/values/strings.xml b/java/com/android/dialer/calllog/ui/menu/res/values/strings.xml new file mode 100644 index 000000000..aaa7da04a --- /dev/null +++ b/java/com/android/dialer/calllog/ui/menu/res/values/strings.xml @@ -0,0 +1,35 @@ +<?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> + + <!-- Option shown in call log menu to add the phone number from an entry to an existing contact + (also provides option to create a new contact from the number). [CHAR LIMIT=30] --> + <string name="add_to_contacts">Add to contacts</string> + + <!-- Option displayed in call log menu to copy phone number. [CHAR LIMIT=30] --> + <string name="copy_number">Copy number</string> + + <!-- Options shown in call log menu to send a SMS to the number represented by the call log entry. + [CHAR LIMIT=30] --> + <string name="send_a_message">Send a message</string> + + <!-- Option shown in call log menu to navigate the user to the call details screen where the user + can view details for the call log entry. [CHAR LIMIT=30] --> + <string name="call_details">Call details</string> + +</resources>
\ No newline at end of file diff --git a/java/com/android/dialer/calllog/ui/res/values/strings.xml b/java/com/android/dialer/calllog/ui/res/values/strings.xml index 9b044ca08..0ef0eaf26 100644 --- a/java/com/android/dialer/calllog/ui/res/values/strings.xml +++ b/java/com/android/dialer/calllog/ui/res/values/strings.xml @@ -17,12 +17,6 @@ <resources> - <!-- Text to show in call log for a video call. [CHAR LIMIT=16] --> - <string name="new_call_log_video">Video</string> - - <!-- String used to display calls from unknown numbers in the call log. [CHAR LIMIT=30] --> - <string name="new_call_log_unknown">Unknown</string> - <!-- Header in call log to group calls from the current day. [CHAR LIMIT=30] --> <string name="new_call_log_header_today">Today</string> |