Home | History | Annotate | Download | only in calllogutils
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dialer.calllogutils;
     18 
     19 import android.content.Context;
     20 import android.provider.CallLog.Calls;
     21 import android.text.TextUtils;
     22 import com.android.dialer.calllog.model.CoalescedRow;
     23 import com.android.dialer.time.Clock;
     24 import com.google.common.base.Optional;
     25 import com.google.common.collect.Collections2;
     26 import java.util.ArrayList;
     27 import java.util.List;
     28 
     29 /**
     30  * Computes the primary text and secondary text for call log entries.
     31  *
     32  * <p>These text values are shown in the main call log list or in the top item of the bottom sheet
     33  * menu.
     34  */
     35 public final class CallLogEntryText {
     36 
     37   /**
     38    * The primary text for bottom sheets is the same as shown in the entry list.
     39    *
     40    * <p>(In the entry list, the number of calls and additional icons are displayed as images
     41    * following the primary text.)
     42    */
     43   public static CharSequence buildPrimaryText(Context context, CoalescedRow row) {
     44     // Always prefer the presentation name, like "Restricted".
     45     Optional<String> presentationName =
     46         PhoneNumberDisplayUtil.getNameForPresentation(context, row.numberPresentation());
     47     if (presentationName.isPresent()) {
     48       return presentationName.get();
     49     }
     50 
     51     // Otherwise prefer the name.
     52     if (!TextUtils.isEmpty(row.numberAttributes().getName())) {
     53       return row.numberAttributes().getName();
     54     }
     55 
     56     // Otherwise prefer the formatted number.
     57     if (!TextUtils.isEmpty(row.formattedNumber())) {
     58       return row.formattedNumber();
     59     }
     60 
     61     // If there's no formatted number, just return "Unknown".
     62     return context.getText(R.string.new_call_log_unknown);
     63   }
     64 
     65   /**
     66    * The secondary text to show in the main call log entry list.
     67    *
     68    * <p>Rules:
     69    *
     70    * <ul>
     71    *   <li>For numbers that are not spam or blocked: (Duo video, )?$Label|$Location  Date
     72    *   <li>For blocked non-spam numbers: Blocked  (Duo video, )?$Label|$Location  Date
     73    *   <li>For spam but not blocked numbers: Spam  (Duo video, )?$Label  Date
     74    *   <li>For blocked spam numbers: Blocked  Spam  (Duo video, )?$Label  Date
     75    * </ul>
     76    *
     77    * <p>Examples:
     78    *
     79    * <ul>
     80    *   <li>Duo Video, Mobile  Now
     81    *   <li>Duo Video  10 min ago
     82    *   <li>Mobile  11:45 PM
     83    *   <li>Mobile  Sun
     84    *   <li>Blocked  Duo Video, Mobile  Now
     85    *   <li>Blocked  Brooklyn, NJ  10 min ago
     86    *   <li>Spam  Mobile  Now
     87    *   <li>Spam  Now
     88    *   <li>Blocked  Spam  Mobile  Now
     89    *   <li>Brooklyn, NJ  Jan 15
     90    * </ul>
     91    *
     92    * <p>See {@link CallLogDates#newCallLogTimestampLabel(Context, long, long)} for date rules.
     93    */
     94   public static CharSequence buildSecondaryTextForEntries(
     95       Context context, Clock clock, CoalescedRow row) {
     96     List<CharSequence> components = new ArrayList<>();
     97 
     98     if (row.numberAttributes().getIsBlocked()) {
     99       components.add(context.getText(R.string.new_call_log_secondary_blocked));
    100     }
    101     if (row.numberAttributes().getIsSpam()) {
    102       components.add(context.getText(R.string.new_call_log_secondary_spam));
    103     }
    104 
    105     components.add(getNumberTypeLabel(context, row));
    106 
    107     components.add(
    108         CallLogDates.newCallLogTimestampLabel(context, clock.currentTimeMillis(), row.timestamp()));
    109     return joinSecondaryTextComponents(components);
    110   }
    111 
    112   /**
    113    * The secondary text to show in the top item of the bottom sheet.
    114    *
    115    * <p>This is basically the same as {@link #buildSecondaryTextForEntries(Context, Clock,
    116    * CoalescedRow)} except that instead of suffixing with the time of the call, we suffix with the
    117    * formatted number.
    118    */
    119   public static CharSequence buildSecondaryTextForBottomSheet(Context context, CoalescedRow row) {
    120     /*
    121      * Rules:
    122      *   For numbers that are not spam or blocked:
    123      *     (Duo video, )?$Label|$Location [ NumberIfNoName]?
    124      *   For blocked non-spam numbers:
    125      *     Blocked  (Duo video, )?$Label|$Location [ NumberIfNoName]?
    126      *   For spam but not blocked numbers:
    127      *     Spam  (Duo video, )?$Label [ NumberIfNoName]?
    128      *   For blocked spam numbers:
    129      *     Blocked  Spam  (Duo video, )?$Label [ NumberIfNoName]?
    130      *
    131      * The number is shown at the end if there is no name for the entry. (It is shown in primary
    132      * text otherwise.)
    133      *
    134      * Examples:
    135      *   Duo Video, Mobile  555-1234
    136      *   Duo Video  555-1234
    137      *   Mobile  555-1234
    138      *   Blocked  Mobile  555-1234
    139      *   Blocked  Brooklyn, NJ  555-1234
    140      *   Spam  Mobile  555-1234
    141      *   Mobile  555-1234
    142      *   Brooklyn, NJ
    143      */
    144     List<CharSequence> components = new ArrayList<>();
    145 
    146     if (row.numberAttributes().getIsBlocked()) {
    147       components.add(context.getText(R.string.new_call_log_secondary_blocked));
    148     }
    149     if (row.numberAttributes().getIsSpam()) {
    150       components.add(context.getText(R.string.new_call_log_secondary_spam));
    151     }
    152 
    153     components.add(getNumberTypeLabel(context, row));
    154 
    155     // If there's a presentation name, we showed it in the primary text and shouldn't show any name
    156     // or number here.
    157     Optional<String> presentationName =
    158         PhoneNumberDisplayUtil.getNameForPresentation(context, row.numberPresentation());
    159     if (presentationName.isPresent()) {
    160       return joinSecondaryTextComponents(components);
    161     }
    162 
    163     if (TextUtils.isEmpty(row.numberAttributes().getName())) {
    164       // If the name is empty the number is shown as the primary text and there's nothing to add.
    165       return joinSecondaryTextComponents(components);
    166     }
    167     if (TextUtils.isEmpty(row.formattedNumber())) {
    168       // If there's no number, don't append anything.
    169       return joinSecondaryTextComponents(components);
    170     }
    171     components.add(row.formattedNumber());
    172     return joinSecondaryTextComponents(components);
    173   }
    174 
    175   /**
    176    * Returns a value such as "Duo Video, Mobile" without the time of the call or formatted number
    177    * appended.
    178    *
    179    * <p>When the secondary text is shown in call log entry list, this prefix is suffixed with the
    180    * time of the call, and when it is shown in a bottom sheet, it is suffixed with the formatted
    181    * number.
    182    */
    183   private static CharSequence getNumberTypeLabel(Context context, CoalescedRow row) {
    184     StringBuilder secondaryText = new StringBuilder();
    185     if ((row.features() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) {
    186       // TODO(zachh): Add "Duo" prefix?
    187       secondaryText.append(context.getText(R.string.new_call_log_video));
    188     }
    189     String numberTypeLabel = row.numberAttributes().getNumberTypeLabel();
    190     if (!TextUtils.isEmpty(numberTypeLabel)) {
    191       if (secondaryText.length() > 0) {
    192         secondaryText.append(", ");
    193       }
    194       secondaryText.append(numberTypeLabel);
    195     } else if (!row.numberAttributes().getIsSpam()) {
    196       // Don't show the location if there's a number type label or the number is spam.
    197       String location = row.geocodedLocation();
    198       if (!TextUtils.isEmpty(location)) {
    199         if (secondaryText.length() > 0) {
    200           secondaryText.append(", ");
    201         }
    202         secondaryText.append(location);
    203       }
    204     }
    205     return secondaryText;
    206   }
    207 
    208   private static CharSequence joinSecondaryTextComponents(List<CharSequence> components) {
    209     return TextUtils.join(
    210         "  ", Collections2.filter(components, (text) -> !TextUtils.isEmpty(text)));
    211   }
    212 }
    213