blob: 651a0ccb85136eba38c9a0604774520bc8b77b6e [file] [log] [blame]
/*
* 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.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import com.android.contacts.common.compat.TelephonyManagerCompat;
import com.android.contacts.common.util.ContactDisplayUtils;
import com.android.dialer.app.DialtactsActivity;
import com.android.dialer.app.R;
import com.android.dialer.app.calllog.CallLogNotificationsHelper.NewCall;
import com.android.dialer.app.list.ListsFragment;
import com.android.dialer.blocking.FilteredNumbersUtil;
import com.android.dialer.telecom.TelecomUtil;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/** Shows a voicemail notification in the status bar. */
public class DefaultVoicemailNotifier {
public static final String TAG = "VoicemailNotifier";
/** The tag used to identify notifications from this class. */
private static final String NOTIFICATION_TAG = "DefaultVoicemailNotifier";
/** The identifier of the notification of new voicemails. */
private static final int NOTIFICATION_ID = 1;
/** The singleton instance of {@link DefaultVoicemailNotifier}. */
private static DefaultVoicemailNotifier sInstance;
private final Context mContext;
private DefaultVoicemailNotifier(Context context) {
mContext = context;
}
/** Returns the singleton instance of the {@link DefaultVoicemailNotifier}. */
public static DefaultVoicemailNotifier getInstance(Context context) {
if (sInstance == null) {
ContentResolver contentResolver = context.getContentResolver();
sInstance = new DefaultVoicemailNotifier(context);
}
return sInstance;
}
/**
* Updates the notification and notifies of the call with the given URI.
*
* <p>Clears the notification if there are no new voicemails, and notifies if the given URI
* corresponds to a new voicemail.
*
* <p>It is not safe to call this method from the main thread.
*/
public void updateNotification(Uri newCallUri) {
// Lookup the list of new voicemails to include in the notification.
// TODO: Move this into a service, to avoid holding the receiver up.
final List<NewCall> newCalls =
CallLogNotificationsHelper.getInstance(mContext).getNewVoicemails();
if (newCalls == null) {
// Query failed, just return.
return;
}
if (newCalls.isEmpty()) {
// No voicemails to notify about: clear the notification.
getNotificationManager().cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
return;
}
Resources resources = mContext.getResources();
// This represents a list of names to include in the notification.
String callers = null;
// Maps each number into a name: if a number is in the map, it has already left a more
// recent voicemail.
final Map<String, String> names = new ArrayMap<>();
// Determine the call corresponding to the new voicemail we have to notify about.
NewCall callToNotify = null;
// Iterate over the new voicemails to determine all the information above.
Iterator<NewCall> itr = newCalls.iterator();
while (itr.hasNext()) {
NewCall newCall = itr.next();
// Skip notifying for numbers which are blocked.
if (FilteredNumbersUtil.shouldBlockVoicemail(
mContext, newCall.number, newCall.countryIso, newCall.dateMs)) {
itr.remove();
// Delete the voicemail.
mContext.getContentResolver().delete(newCall.voicemailUri, null, null);
continue;
}
// Check if we already know the name associated with this number.
String name = names.get(newCall.number);
if (name == null) {
name =
CallLogNotificationsHelper.getInstance(mContext)
.getName(newCall.number, newCall.numberPresentation, newCall.countryIso);
names.put(newCall.number, name);
// This is a new caller. Add it to the back of the list of callers.
if (TextUtils.isEmpty(callers)) {
callers = name;
} else {
callers =
resources.getString(R.string.notification_voicemail_callers_list, callers, name);
}
}
// Check if this is the new call we need to notify about.
if (newCallUri != null
&& newCall.voicemailUri != null
&& ContentUris.parseId(newCallUri) == ContentUris.parseId(newCall.voicemailUri)) {
callToNotify = newCall;
}
}
// All the potential new voicemails have been removed, e.g. if they were spam.
if (newCalls.isEmpty()) {
return;
}
// If there is only one voicemail, set its transcription as the "long text".
String transcription = null;
if (newCalls.size() == 1) {
transcription = newCalls.get(0).transcription;
}
if (newCallUri != null && callToNotify == null) {
Log.e(TAG, "The new call could not be found in the call log: " + newCallUri);
}
// Determine the title of the notification and the icon for it.
final String title =
resources.getQuantityString(
R.plurals.notification_voicemail_title, newCalls.size(), newCalls.size());
// TODO: Use the photo of contact if all calls are from the same person.
final int icon = android.R.drawable.stat_notify_voicemail;
Pair<Uri, Integer> info = getNotificationInfo(callToNotify);
Notification.Builder notificationBuilder =
new Notification.Builder(mContext)
.setSmallIcon(icon)
.setContentTitle(title)
.setContentText(callers)
.setColor(resources.getColor(R.color.dialer_theme_color))
.setSound(info.first)
.setDefaults(info.second)
.setDeleteIntent(createMarkNewVoicemailsAsOldIntent())
.setAutoCancel(true);
if (!TextUtils.isEmpty(transcription)) {
notificationBuilder.setStyle(new Notification.BigTextStyle().bigText(transcription));
}
// Determine the intent to fire when the notification is clicked on.
final Intent contentIntent;
// Open the call log.
contentIntent = DialtactsActivity.getShowTabIntent(mContext, ListsFragment.TAB_INDEX_VOICEMAIL);
contentIntent.putExtra(DialtactsActivity.EXTRA_CLEAR_NEW_VOICEMAILS, true);
notificationBuilder.setContentIntent(
PendingIntent.getActivity(mContext, 0, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT));
// The text to show in the ticker, describing the new event.
if (callToNotify != null) {
CharSequence msg =
ContactDisplayUtils.getTtsSpannedPhoneNumber(
resources,
R.string.notification_new_voicemail_ticker,
names.get(callToNotify.number));
notificationBuilder.setTicker(msg);
}
Log.i(TAG, "Creating voicemail notification");
getNotificationManager().notify(NOTIFICATION_TAG, NOTIFICATION_ID, notificationBuilder.build());
}
/**
* Determines which ringtone Uri and Notification defaults to use when updating the notification
* for the given call.
*/
private Pair<Uri, Integer> getNotificationInfo(@Nullable NewCall callToNotify) {
Log.v(TAG, "getNotificationInfo");
if (callToNotify == null) {
Log.i(TAG, "callToNotify == null");
return new Pair<>(null, 0);
}
PhoneAccountHandle accountHandle;
if (callToNotify.accountComponentName == null || callToNotify.accountId == null) {
Log.v(TAG, "accountComponentName == null || callToNotify.accountId == null");
accountHandle = TelecomUtil.getDefaultOutgoingPhoneAccount(mContext, PhoneAccount.SCHEME_TEL);
if (accountHandle == null) {
Log.i(TAG, "No default phone account found, using default notification ringtone");
return new Pair<>(null, Notification.DEFAULT_ALL);
}
} else {
accountHandle =
new PhoneAccountHandle(
ComponentName.unflattenFromString(callToNotify.accountComponentName),
callToNotify.accountId);
}
if (accountHandle.getComponentName() != null) {
Log.v(TAG, "PhoneAccountHandle.ComponentInfo:" + accountHandle.getComponentName());
} else {
Log.i(TAG, "PhoneAccountHandle.ComponentInfo: null");
}
return new Pair<>(
TelephonyManagerCompat.getVoicemailRingtoneUri(getTelephonyManager(), accountHandle),
getNotificationDefaults(accountHandle));
}
private int getNotificationDefaults(PhoneAccountHandle accountHandle) {
if (VERSION.SDK_INT >= VERSION_CODES.N) {
return TelephonyManagerCompat.isVoicemailVibrationEnabled(
getTelephonyManager(), accountHandle)
? Notification.DEFAULT_VIBRATE
: 0;
}
return Notification.DEFAULT_ALL;
}
/** Creates a pending intent that marks all new voicemails as old. */
private PendingIntent createMarkNewVoicemailsAsOldIntent() {
Intent intent = new Intent(mContext, CallLogNotificationsService.class);
intent.setAction(CallLogNotificationsService.ACTION_MARK_NEW_VOICEMAILS_AS_OLD);
return PendingIntent.getService(mContext, 0, intent, 0);
}
private NotificationManager getNotificationManager() {
return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
}
private TelephonyManager getTelephonyManager() {
return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
}
}