summaryrefslogtreecommitdiff
path: root/src/com/android/dialer/calllog/DefaultVoicemailNotifier.java
blob: db822953818929f056ca1b4c38b28e1589647bc4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/*
 * 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.calllog;

import static android.Manifest.permission.READ_CALL_LOG;
import static android.Manifest.permission.READ_CONTACTS;

import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.compat.TelephonyManagerCompat;
import com.google.common.collect.Maps;

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.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;

import com.android.contacts.common.util.ContactDisplayUtils;
import com.android.dialer.DialtactsActivity;
import com.android.dialer.R;
import com.android.dialer.calllog.CallLogNotificationsHelper.NewCall;
import com.android.dialer.filterednumber.FilteredNumbersUtil;
import com.android.dialer.list.ListsFragment;

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;

    /** 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;
    }

    private DefaultVoicemailNotifier(Context context) {
        mContext = context;
    }

    /**
     * Updates the notification and notifies of the call with the given URI.
     *
     * Clears the notification if there are no new voicemails, and notifies if the given URI
     * corresponds to a new voicemail.
     *
     * 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 = Maps.newHashMap();

        // 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;

        Uri ringtoneUri = null;
        int notificationDefaults = 0;
        if (callToNotify != null) {
            PhoneAccountHandle accountHandle = new PhoneAccountHandle(
                    ComponentName.unflattenFromString(callToNotify.accountComponentName),
                    callToNotify.accountId);
            ringtoneUri = TelephonyManagerCompat
                    .getVoicemailRingtoneUri(getTelephonyManager(), accountHandle);
            if (ContactsUtils.FLAG_N_FEATURE) {
                notificationDefaults = TelephonyManagerCompat.isVoicemailVibrationEnabled(
                        getTelephonyManager(), accountHandle)
                        ? Notification.DEFAULT_VIBRATE : 0;
            } else {
                notificationDefaults = Notification.DEFAULT_ALL;
            }
        }

        Notification.Builder notificationBuilder = new Notification.Builder(mContext)
                .setSmallIcon(icon)
                .setContentTitle(title)
                .setContentText(callers)
                .setStyle(new Notification.BigTextStyle().bigText(transcription))
                .setColor(resources.getColor(R.color.dialer_theme_color))
                .setSound(ringtoneUri)
                .setDefaults(notificationDefaults)
                .setDeleteIntent(createMarkNewVoicemailsAsOldIntent())
                .setAutoCancel(true);

        // Determine the intent to fire when the notification is clicked on.
        final Intent contentIntent;
        // Open the call log.
        contentIntent = new Intent(mContext, DialtactsActivity.class);
        contentIntent.putExtra(DialtactsActivity.EXTRA_SHOW_TAB, ListsFragment.TAB_INDEX_VOICEMAIL);
        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);
        }

        getNotificationManager().notify(NOTIFICATION_TAG, NOTIFICATION_ID,
                notificationBuilder.build());
    }

    /** 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);
    }
}