| /* |
| * Copyright (C) 2011 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.app.calllog; |
| |
| import android.content.Context; |
| import android.icu.lang.UCharacter; |
| import android.icu.text.BreakIterator; |
| import android.os.Build.VERSION; |
| import android.os.Build.VERSION_CODES; |
| import android.provider.CallLog.Calls; |
| import android.text.format.DateUtils; |
| import android.text.format.Formatter; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.widget.BaseAdapter; |
| import android.widget.TextView; |
| import com.android.dialer.app.PhoneCallDetails; |
| import com.android.dialer.app.R; |
| import com.android.dialer.util.CallUtil; |
| import com.android.dialer.util.DialerUtils; |
| import java.util.ArrayList; |
| import java.util.Locale; |
| |
| /** Adapter for a ListView containing history items from the details of a call. */ |
| public class CallDetailHistoryAdapter extends BaseAdapter { |
| |
| /** Each history item shows the detail of a call. */ |
| private static final int VIEW_TYPE_HISTORY_ITEM = 1; |
| |
| private final Context mContext; |
| private final LayoutInflater mLayoutInflater; |
| private final CallTypeHelper mCallTypeHelper; |
| private final PhoneCallDetails[] mPhoneCallDetails; |
| |
| /** List of items to be concatenated together for duration strings. */ |
| private ArrayList<CharSequence> mDurationItems = new ArrayList<>(); |
| |
| public CallDetailHistoryAdapter( |
| Context context, |
| LayoutInflater layoutInflater, |
| CallTypeHelper callTypeHelper, |
| PhoneCallDetails[] phoneCallDetails) { |
| mContext = context; |
| mLayoutInflater = layoutInflater; |
| mCallTypeHelper = callTypeHelper; |
| mPhoneCallDetails = phoneCallDetails; |
| } |
| |
| @Override |
| public boolean isEnabled(int position) { |
| // None of history will be clickable. |
| return false; |
| } |
| |
| @Override |
| public int getCount() { |
| return mPhoneCallDetails.length; |
| } |
| |
| @Override |
| public Object getItem(int position) { |
| return mPhoneCallDetails[position]; |
| } |
| |
| @Override |
| public long getItemId(int position) { |
| return position; |
| } |
| |
| @Override |
| public int getViewTypeCount() { |
| return 1; |
| } |
| |
| @Override |
| public int getItemViewType(int position) { |
| return VIEW_TYPE_HISTORY_ITEM; |
| } |
| |
| @Override |
| public View getView(int position, View convertView, ViewGroup parent) { |
| // Make sure we have a valid convertView to start with |
| final View result = |
| convertView == null |
| ? mLayoutInflater.inflate(R.layout.call_detail_history_item, parent, false) |
| : convertView; |
| |
| PhoneCallDetails details = mPhoneCallDetails[position]; |
| CallTypeIconsView callTypeIconView = |
| (CallTypeIconsView) result.findViewById(R.id.call_type_icon); |
| TextView callTypeTextView = (TextView) result.findViewById(R.id.call_type_text); |
| TextView dateView = (TextView) result.findViewById(R.id.date); |
| TextView durationView = (TextView) result.findViewById(R.id.duration); |
| |
| int callType = details.callTypes[0]; |
| boolean isVideoCall = |
| (details.features & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO |
| && CallUtil.isVideoEnabled(mContext); |
| boolean isPulledCall = |
| (details.features & Calls.FEATURES_PULLED_EXTERNALLY) == Calls.FEATURES_PULLED_EXTERNALLY; |
| |
| callTypeIconView.clear(); |
| callTypeIconView.add(callType); |
| callTypeIconView.setShowVideo(isVideoCall); |
| callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType, isVideoCall, isPulledCall)); |
| // Set the date. |
| dateView.setText(formatDate(details.date)); |
| // Set the duration |
| if (Calls.VOICEMAIL_TYPE == callType || CallTypeHelper.isMissedCallType(callType)) { |
| durationView.setVisibility(View.GONE); |
| } else { |
| durationView.setVisibility(View.VISIBLE); |
| durationView.setText(formatDurationAndDataUsage(details.duration, details.dataUsage)); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Formats the provided date into a value suitable for display in the current locale. |
| * |
| * <p>For example, returns a string like "Wednesday, May 25, 2016, 8:02PM" or "Chorshanba, 2016 |
| * may 25,20:02". |
| * |
| * <p>For pre-N devices, the returned value may not start with a capital if the local convention |
| * is to not capitalize day names. On N+ devices, the returned value is always capitalized. |
| */ |
| private CharSequence formatDate(long callDateMillis) { |
| CharSequence dateValue = |
| DateUtils.formatDateRange( |
| mContext, |
| callDateMillis /* startDate */, |
| callDateMillis /* endDate */, |
| DateUtils.FORMAT_SHOW_TIME |
| | DateUtils.FORMAT_SHOW_DATE |
| | DateUtils.FORMAT_SHOW_WEEKDAY |
| | DateUtils.FORMAT_SHOW_YEAR); |
| |
| // We want the beginning of the date string to be capitalized, even if the word at the beginning |
| // of the string is not usually capitalized. For example, "Wednesdsay" in Uzbek is "chorshanba” |
| // (not capitalized). To handle this issue we apply title casing to the start of the sentence so |
| // that "chorshanba, 2016 may 25,20:02" becomes "Chorshanba, 2016 may 25,20:02". |
| // |
| // The ICU library was not available in Android until N, so we can only do this in N+ devices. |
| // Pre-N devices will still see incorrect capitalization in some languages. |
| if (VERSION.SDK_INT < VERSION_CODES.N) { |
| return dateValue; |
| } |
| |
| // Using the ICU library is safer than just applying toUpperCase() on the first letter of the |
| // word because in some languages, there can be multiple starting characters which should be |
| // upper-cased together. For example in Dutch "ij" is a digraph in which both letters should be |
| // capitalized together. |
| |
| // TITLECASE_NO_LOWERCASE is necessary so that things that are already capitalized like the |
| // month ("May") are not lower-cased as part of the conversion. |
| return UCharacter.toTitleCase( |
| Locale.getDefault(), |
| dateValue.toString(), |
| BreakIterator.getSentenceInstance(), |
| UCharacter.TITLECASE_NO_LOWERCASE); |
| } |
| |
| private CharSequence formatDuration(long elapsedSeconds) { |
| long minutes = 0; |
| long seconds = 0; |
| |
| if (elapsedSeconds >= 60) { |
| minutes = elapsedSeconds / 60; |
| elapsedSeconds -= minutes * 60; |
| seconds = elapsedSeconds; |
| return mContext.getString(R.string.callDetailsDurationFormat, minutes, seconds); |
| } else { |
| seconds = elapsedSeconds; |
| return mContext.getString(R.string.callDetailsShortDurationFormat, seconds); |
| } |
| } |
| |
| /** |
| * Formats a string containing the call duration and the data usage (if specified). |
| * |
| * @param elapsedSeconds Total elapsed seconds. |
| * @param dataUsage Data usage in bytes, or null if not specified. |
| * @return String containing call duration and data usage. |
| */ |
| private CharSequence formatDurationAndDataUsage(long elapsedSeconds, Long dataUsage) { |
| CharSequence duration = formatDuration(elapsedSeconds); |
| |
| if (dataUsage != null) { |
| mDurationItems.clear(); |
| mDurationItems.add(duration); |
| mDurationItems.add(Formatter.formatShortFileSize(mContext, dataUsage)); |
| |
| return DialerUtils.join(mDurationItems); |
| } else { |
| return duration; |
| } |
| } |
| } |