blob: db32c70757c13aa94186e4b44ceda8539e7d1375 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
* Copyright (C) 2013 Android Open Kang Project
* Copyright (C) 2023 The LineageOS 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.callstats;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.CallLog.Calls;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.view.View;
import android.widget.QuickContactBadge;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.android.dialer.R;
import com.android.dialer.app.AccountSelectionActivity;
import com.android.dialer.callintent.CallInitiationType;
import com.android.dialer.callintent.CallIntentBuilder;
import com.android.dialer.calllogutils.CallTypeIconsView;
import com.android.dialer.clipboard.ClipboardUtils;
import com.android.dialer.contactphoto.ContactPhotoManager;
import com.android.dialer.contacts.ContactsComponent;
import com.android.dialer.contacts.displaypreference.ContactDisplayPreferences;
import com.android.dialer.lettertile.LetterTileDrawable;
import com.android.dialer.location.GeoUtil;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.dialer.phonenumbercache.ContactInfoHelper;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
import com.android.dialer.util.CallUtil;
import com.android.dialer.widget.LinearColorBar;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Activity to display detailed information about a callstat item
*/
public class CallStatsDetailActivity extends AppCompatActivity implements
View.OnClickListener, View.OnLongClickListener {
private static final String TAG = "CallStatsDetailActivity";
public static final String EXTRA_DETAILS = "details";
public static final String EXTRA_TOTAL = "total";
public static final String EXTRA_FROM = "from";
public static final String EXTRA_TO = "to";
private ContactInfoHelper mContactInfoHelper;
private ContactDisplayPreferences mContactDisplayPreferences;
private Resources mResources;
private QuickContactBadge mQuickContactBadge;
private TextView mCallerName;
private TextView mCallerNumber;
private View mCallButton;
private View mSeparator;
private View mCopyButton;
private View mEditNumberButton;
private TextView mTotalDuration, mTotalCount;
private TextView mTotalTotalDuration, mTotalTotalCount;
private DetailLine mInDuration, mOutDuration;
private DetailLine mInCount, mOutCount;
private DetailLine mMissedCount, mBlockedCount;
private DetailLine mInAverage, mOutAverage;
private LinearColorBar mDurationBar, mCountBar;
private LinearColorBar mTotalDurationBar, mTotalCountBar;
private CallStatsDetails mData;
private CallStatsDetails mTotalData;
private String mNumber = null;
private class UpdateContactTask {
private void execute(String number, String countryIso) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
final ContactInfo info = mContactInfoHelper.lookupNumber(number, countryIso);
handler.post(() -> {
if (info != null) {
mData.updateFromInfo(info);
updateData();
}
});
});
}
}
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.call_stats_detail);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(v -> finish());
toolbar.setTitle(R.string.call_stats_detail_title);
mResources = getResources();
mContactInfoHelper = new ContactInfoHelper(this, GeoUtil.getCurrentCountryIso(this));
mContactDisplayPreferences = ContactsComponent.get(this).contactDisplayPreferences();
mQuickContactBadge = (QuickContactBadge) findViewById(R.id.quick_contact_photo);
mQuickContactBadge.setOverlay(null);
mQuickContactBadge.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
mCallerName = (TextView) findViewById(R.id.caller_name);
mCallerNumber = (TextView) findViewById(R.id.caller_number);
mCallButton = findViewById(R.id.call_back_button);
mCallButton.setOnClickListener(this);
mCallButton.setOnLongClickListener(this);
mSeparator = findViewById(R.id.separator);
mEditNumberButton = findViewById(R.id.call_detail_action_edit_before_call);
mEditNumberButton.setOnClickListener(this);
mCopyButton = findViewById(R.id.call_detail_action_copy);
mCopyButton.setOnClickListener(this);
mDurationBar = (LinearColorBar) findViewById(R.id.duration_number_percent_bar);
mTotalDurationBar = (LinearColorBar) findViewById(R.id.duration_total_percent_bar);
mTotalDuration = (TextView) findViewById(R.id.total_duration_number);
mTotalTotalDuration = (TextView) findViewById(R.id.total_duration_total);
mInDuration = new DetailLine(R.id.in_duration,
R.string.call_stats_incoming, Calls.INCOMING_TYPE);
mOutDuration = new DetailLine(R.id.out_duration,
R.string.call_stats_outgoing, Calls.OUTGOING_TYPE);
mCountBar = (LinearColorBar) findViewById(R.id.count_number_percent_bar);
mTotalCountBar = (LinearColorBar) findViewById(R.id.count_total_percent_bar);
mTotalCount = (TextView) findViewById(R.id.total_count_number);
mTotalTotalCount = (TextView) findViewById(R.id.total_count_total);
mInCount = new DetailLine(R.id.in_count, R.string.call_stats_incoming, Calls.INCOMING_TYPE);
mOutCount = new DetailLine(R.id.out_count, R.string.call_stats_outgoing, Calls.OUTGOING_TYPE);
mMissedCount = new DetailLine(R.id.missed_count,
R.string.call_stats_missed, Calls.MISSED_TYPE);
mBlockedCount = new DetailLine(R.id.blocked_count,
R.string.call_stats_blocked, Calls.BLOCKED_TYPE);
mInAverage = new DetailLine(R.id.in_average,
R.string.call_stats_incoming, Calls.INCOMING_TYPE);
mOutAverage = new DetailLine(R.id.out_average,
R.string.call_stats_outgoing, Calls.OUTGOING_TYPE);
Intent launchIntent = getIntent();
mData = launchIntent.getParcelableExtra(EXTRA_DETAILS, CallStatsDetails.class);
mTotalData = launchIntent.getParcelableExtra(EXTRA_TOTAL, CallStatsDetails.class);
updateData();
TextView dateFilterView = findViewById(R.id.date_filter);
long filterFrom = launchIntent.getLongExtra(EXTRA_FROM, -1);
if (filterFrom == -1) {
dateFilterView.setVisibility(View.GONE);
} else {
long filterTo = launchIntent.getLongExtra(EXTRA_TO, -1);
dateFilterView.setText(DateUtils.formatDateRange(this, filterFrom, filterTo, 0));
}
}
@Override
public void onResume() {
super.onResume();
new UpdateContactTask().execute(mData.number, mData.countryIso);
}
private void updateData() {
mNumber = mData.number;
// Cache the details about the phone number.
boolean canPlaceCallsTo = PhoneNumberHelper.canPlaceCallsTo(mNumber, mData.numberPresentation);
final CharSequence callLocationOrType = !TextUtils.isEmpty(mData.displayName)
? Phone.getTypeLabel(mResources, mData.numberType, mData.numberLabel)
: mData.geocode;
mData.updateDisplayProperties(this, mContactDisplayPreferences.getDisplayOrder());
final boolean isSipNumber = PhoneNumberHelper.isSipNumber(mNumber);
boolean hasEditNumberBeforeCallOption =
canPlaceCallsTo && !isSipNumber && !mData.isVoicemailNumber;
if (!TextUtils.isEmpty(mData.displayName)) {
mCallerName.setText(mData.displayName);
mCallerNumber.setText(callLocationOrType + " " + mData.displayNumber);
} else {
mCallerName.setText(mData.displayNumber);
if (!TextUtils.isEmpty(callLocationOrType)) {
mCallerNumber.setText(callLocationOrType);
mCallerNumber.setVisibility(View.VISIBLE);
} else {
mCallerNumber.setVisibility(View.GONE);
}
}
mCallButton.setVisibility(canPlaceCallsTo ? View.VISIBLE : View.GONE);
mCopyButton.setVisibility(canPlaceCallsTo ? View.VISIBLE : View.GONE);
mEditNumberButton.setVisibility(hasEditNumberBeforeCallOption ? View.VISIBLE : View.GONE);
mSeparator.setVisibility(canPlaceCallsTo || hasEditNumberBeforeCallOption
? View.VISIBLE : View.GONE);
final boolean isBusiness = mContactInfoHelper.isBusiness(mData.sourceType);
final int contactType =
mData.isVoicemailNumber ? LetterTileDrawable.TYPE_VOICEMAIL :
isBusiness ? LetterTileDrawable.TYPE_BUSINESS :
LetterTileDrawable.TYPE_DEFAULT;
final String nameForDefaultImage = TextUtils.isEmpty(mData.name)
? mData.displayNumber : mData.name;
ContactPhotoManager.getInstance(this).loadDialerThumbnailOrPhoto(mQuickContactBadge,
mData.contactUri, mData.photoId, mData.photoUri, nameForDefaultImage, contactType);
invalidateOptionsMenu();
long totalDuration = mData.getFullDuration();
mInDuration.updateFromDurations(mData.inDuration, totalDuration);
mOutDuration.updateFromDurations(mData.outDuration, totalDuration);
if (totalDuration != 0) {
mTotalDuration.setText(CallStatsListItemViewHolder.getDurationString(this,
totalDuration, true));
mTotalTotalDuration.setText(CallStatsListItemViewHolder.getDurationString(this,
mTotalData.getFullDuration(), true));
updateBar(mDurationBar, mData.inDuration, mData.outDuration, 0, 0, totalDuration);
updateBar(mTotalDurationBar, mData.inDuration, mData.outDuration,
0, 0, mTotalData.getFullDuration());
findViewById(R.id.duration_container).setVisibility(View.VISIBLE);
} else {
findViewById(R.id.duration_container).setVisibility(View.GONE);
}
mInAverage.updateAsAverage(mData.inDuration, mData.incomingCount);
mOutAverage.updateAsAverage(mData.outDuration, mData.outgoingCount);
int totalCount = mData.getTotalCount();
mTotalCount.setText(CallStatsListItemViewHolder.getCallCountString(this, totalCount));
mTotalTotalCount.setText(
CallStatsListItemViewHolder.getCallCountString(this, mTotalData.getTotalCount()));
mInCount.updateFromCounts(mData.incomingCount, totalCount);
mOutCount.updateFromCounts(mData.outgoingCount, totalCount);
mMissedCount.updateFromCounts(mData.missedCount, totalCount);
mBlockedCount.updateFromCounts(mData.blockedCount, totalCount);
updateBar(mCountBar, mData.incomingCount, mData.outgoingCount,
mData.missedCount, mData.blockedCount, totalCount);
updateBar(mTotalCountBar, mData.incomingCount, mData.outgoingCount,
mData.missedCount, mData.blockedCount, mTotalData.getTotalCount());
}
private void updateBar(LinearColorBar bar,
long value1, long value2, long value3, long value4, long total) {
bar.setRatios((float) value1 / total, (float) value2 / total,
(float) value3 / total, (float) value4 / total);
}
@Override
public void onClick(View view) {
if (view == mCallButton) {
Intent intent = new CallIntentBuilder(mNumber, CallInitiationType.Type.CALL_LOG).build();
startActivity(intent);
} else if (view == mCopyButton) {
ClipboardUtils.copyText(this, null, mNumber, true);
} else if (view == mEditNumberButton) {
startActivity(new Intent(Intent.ACTION_DIAL, CallUtil.getCallUri(mNumber)));
}
}
@Override
public boolean onLongClick(View view) {
if (view == mCallButton) {
Intent intent = AccountSelectionActivity.createIntent(
CallStatsDetailActivity.this, mNumber, CallInitiationType.Type.CALL_LOG);
if (intent != null) {
startActivity(intent);
return true;
}
}
return false;
}
private void onHomeSelected() {
Intent intent = new Intent(Intent.ACTION_VIEW, Calls.CONTENT_URI);
// This will open the call log even if the detail view has been opened directly.
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
private class DetailLine {
private final int mValueTemplateResId;
private final View mRootView;
private final TextView mTextView;
private final TextView mPercentView;
public DetailLine(int rootViewId, int valueTemplateResId, int iconType) {
mValueTemplateResId = valueTemplateResId;
mRootView = findViewById(rootViewId);
mTextView = (TextView) mRootView.findViewById(R.id.value);
mPercentView = (TextView) mRootView.findViewById(R.id.percent);
CallTypeIconsView icon = (CallTypeIconsView) mRootView.findViewById(R.id.icon);
icon.add(iconType);
}
public void updateFromCounts(int count, int totalCount) {
if (count == 0 && totalCount > 0) {
mRootView.setVisibility(View.GONE);
return;
}
mRootView.setVisibility(View.VISIBLE);
String value = CallStatsListItemViewHolder.getCallCountString(mTextView.getContext(), count);
mTextView.setText(getString(mValueTemplateResId, value));
updatePercent(count, totalCount);
}
public void updateFromDurations(long duration, long totalDuration) {
if (duration == 0 && totalDuration >= 0) {
mRootView.setVisibility(View.GONE);
return;
}
mRootView.setVisibility(View.VISIBLE);
String value = CallStatsListItemViewHolder.getDurationString(
mTextView.getContext(), duration, true);
mTextView.setText(getString(mValueTemplateResId, value));
updatePercent(duration, totalDuration);
}
public void updateAsAverage(long duration, int count) {
if (count == 0) {
mRootView.setVisibility(View.GONE);
return;
}
mRootView.setVisibility(View.VISIBLE);
mPercentView.setVisibility(View.GONE);
long averageDuration = (long) Math.round((float) duration / (float) count);
String value = CallStatsListItemViewHolder.getDurationString(
mTextView.getContext(), averageDuration, true);
mTextView.setText(getString(mValueTemplateResId, value));
}
private void updatePercent(long value, long total) {
int percent = (int) Math.round(100F * value / total);
mPercentView.setText(getString(R.string.call_stats_percent, percent));
}
}
}