StatusBarNotifier.java revision ccca31529c07970e89419fb85a9e8153a5396838
1ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/* 2ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Copyright (C) 2013 The Android Open Source Project 3ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 4ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License"); 5ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * you may not use this file except in compliance with the License. 6ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * You may obtain a copy of the License at 7ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 8ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * http://www.apache.org/licenses/LICENSE-2.0 9ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 10ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Unless required by applicable law or agreed to in writing, software 11ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS, 12ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * See the License for the specific language governing permissions and 14ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * limitations under the License. 15ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 16ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 17ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpackage com.android.incallui; 18ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 19ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.contacts.common.compat.CallCompat.Details.PROPERTY_ENTERPRISE_CALL; 20ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST; 21ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_ANSWER_VIDEO_INCOMING_CALL; 22ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_ANSWER_VOICE_INCOMING_CALL; 23ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_DECLINE_INCOMING_CALL; 24ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_DECLINE_VIDEO_UPGRADE_REQUEST; 25ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_HANG_UP_ONGOING_CALL; 26ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 27ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.app.ActivityManager; 28ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.app.Notification; 29ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.app.NotificationManager; 30ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.app.PendingIntent; 31ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.Context; 32ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.Intent; 33ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.graphics.Bitmap; 34ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.graphics.BitmapFactory; 35ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.graphics.drawable.BitmapDrawable; 36ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.graphics.drawable.Drawable; 37ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.media.AudioAttributes; 38ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.net.Uri; 39ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.os.Build.VERSION; 40ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.os.Build.VERSION_CODES; 41ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.ColorRes; 42ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.NonNull; 43ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.Nullable; 44ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.StringRes; 45ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.VisibleForTesting; 46ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.telecom.Call.Details; 47ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.telecom.PhoneAccount; 48ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.telecom.TelecomManager; 49ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.BidiFormatter; 50ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.Spannable; 51ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.SpannableString; 52ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.TextDirectionHeuristics; 53ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.TextUtils; 54ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.style.ForegroundColorSpan; 55ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.ContactsUtils; 56ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.ContactsUtils.UserType; 57ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.preference.ContactsPreferences; 58ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.util.BitmapUtil; 59ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.util.ContactDisplayUtils; 60ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.common.LogUtil; 61ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.util.DrawableConverter; 62ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.ContactInfoCache.ContactCacheEntry; 63ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.ContactInfoCache.ContactInfoCacheCallback; 64ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.InCallPresenter.InCallState; 65ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.async.PausableExecutorImpl; 66ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.call.CallList; 67ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.call.DialerCall; 68ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.call.DialerCall.SessionModificationState; 69ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.call.DialerCallListener; 70ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.ringtone.DialerRingtoneManager; 71ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.ringtone.InCallTonePlayer; 72ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.ringtone.ToneGeneratorFactory; 73ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport java.util.Objects; 74ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 75ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/** This class adds Notifications to the status bar for the in-call experience. */ 76ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianpublic class StatusBarNotifier implements InCallPresenter.InCallStateListener { 77ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 78ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Notification types 79ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Indicates that no notification is currently showing. 80ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final int NOTIFICATION_NONE = 0; 81ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Notification for an active call. This is non-interruptive, but cannot be dismissed. 82ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final int NOTIFICATION_IN_CALL = 1; 83ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Notification for incoming calls. This is interruptive and will show up as a HUN. 84ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final int NOTIFICATION_INCOMING_CALL = 2; 85ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 86ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final int PENDING_INTENT_REQUEST_CODE_NON_FULL_SCREEN = 0; 87ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final int PENDING_INTENT_REQUEST_CODE_FULL_SCREEN = 1; 88ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 89ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final long[] VIBRATE_PATTERN = new long[] {0, 1000, 1000}; 90ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 91ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final Context mContext; 92ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final ContactInfoCache mContactInfoCache; 93ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final NotificationManager mNotificationManager; 94ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final DialerRingtoneManager mDialerRingtoneManager; 95ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Nullable private ContactsPreferences mContactsPreferences; 96ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private int mCurrentNotification = NOTIFICATION_NONE; 97ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private int mCallState = DialerCall.State.INVALID; 98ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private int mSavedIcon = 0; 99ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private String mSavedContent = null; 100ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Bitmap mSavedLargeIcon; 101ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private String mSavedContentTitle; 102ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Uri mRingtone; 103ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private StatusBarCallListener mStatusBarCallListener; 104ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 105ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public StatusBarNotifier(@NonNull Context context, @NonNull ContactInfoCache contactInfoCache) { 106ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Objects.requireNonNull(context); 107ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContext = context; 108ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContactsPreferences = ContactsPreferencesFactory.newContactsPreferences(mContext); 109ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContactInfoCache = contactInfoCache; 110ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mNotificationManager = context.getSystemService(NotificationManager.class); 111ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerRingtoneManager = 112ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new DialerRingtoneManager( 113ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new InCallTonePlayer(new ToneGeneratorFactory(), new PausableExecutorImpl()), 114ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian CallList.getInstance()); 115ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mCurrentNotification = NOTIFICATION_NONE; 116ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 117ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 118ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 119ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Should only be called from a irrecoverable state where it is necessary to dismiss all 120ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * notifications. 121ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 122ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian static void clearAllCallNotifications(Context backupContext) { 123ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.i( 124ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian StatusBarNotifier.class.getSimpleName(), 125ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian "Something terrible happened. Clear all InCall notifications"); 126ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 127ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian NotificationManager notificationManager = 128ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian backupContext.getSystemService(NotificationManager.class); 129ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notificationManager.cancel(NOTIFICATION_IN_CALL); 130ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notificationManager.cancel(NOTIFICATION_INCOMING_CALL); 131ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 132ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 133ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static int getWorkStringFromPersonalString(int resId) { 134ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (resId == R.string.notification_ongoing_call) { 135ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.string.notification_ongoing_work_call; 136ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (resId == R.string.notification_ongoing_call_wifi) { 137ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.string.notification_ongoing_work_call_wifi; 138ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (resId == R.string.notification_incoming_call_wifi) { 139ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.string.notification_incoming_work_call_wifi; 140ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (resId == R.string.notification_incoming_call) { 141ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.string.notification_incoming_work_call; 142ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 143ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return resId; 144ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 145ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 146ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 147ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 148ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Returns PendingIntent for answering a phone call. This will typically be used from Notification 149ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * context. 150ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 151ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static PendingIntent createNotificationPendingIntent(Context context, String action) { 152ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final Intent intent = new Intent(action, null, context, NotificationBroadcastReceiver.class); 153ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return PendingIntent.getBroadcast(context, 0, intent, 0); 154ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 155ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 156ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Creates notifications according to the state we receive from {@link InCallPresenter}. */ 157ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 158ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onStateChange(InCallState oldState, InCallState newState, CallList callList) { 159ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.d(this, "onStateChange"); 160ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian updateNotification(callList); 161ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 162ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 163ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 164ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Updates the phone app's status bar notification *and* launches the incoming call UI in response 165ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * to a new incoming call. 166ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 167ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>If an incoming call is ringing (or call-waiting), the notification will also include a 168ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * "fullScreenIntent" that will cause the InCallScreen to be launched, unless the current 169ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * foreground activity is marked as "immersive". 170ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 171ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>(This is the mechanism that actually brings up the incoming call UI when we receive a "new 172ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * ringing connection" event from the telephony layer.) 173ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 174ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>Also note that this method is safe to call even if the phone isn't actually ringing (or, 175ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * more likely, if an incoming call *was* ringing briefly but then disconnected). In that case, 176ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * we'll simply update or cancel the in-call notification based on the current phone state. 177ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 178ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @see #updateInCallNotification(CallList) 179ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 180ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void updateNotification(CallList callList) { 181ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian updateInCallNotification(callList); 182ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 183ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 184ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 185ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Take down the in-call notification. 186ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 187ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @see #updateInCallNotification(CallList) 188ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 189ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void cancelNotification() { 190ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mStatusBarCallListener != null) { 191ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian setStatusBarCallListener(null); 192ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 193ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mCurrentNotification != NOTIFICATION_NONE) { 194ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.d(this, "cancelInCall()..."); 195ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mNotificationManager.cancel(mCurrentNotification); 196ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 197ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mCurrentNotification = NOTIFICATION_NONE; 198ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 199ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 200ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 201ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Helper method for updateInCallNotification() and updateNotification(): Update the phone app's 202ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * status bar notification based on the current telephony state, or cancels the notification if 203ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * the phone is totally idle. 204ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 205ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void updateInCallNotification(CallList callList) { 206ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.d(this, "updateInCallNotification..."); 207ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 208ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final DialerCall call = getCallToShow(callList); 209ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 210ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call != null) { 211ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian showNotification(callList, call); 212ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 213ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian cancelNotification(); 214ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 215ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 216ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 217ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void showNotification(final CallList callList, final DialerCall call) { 218ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final boolean isIncoming = 219ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian (call.getState() == DialerCall.State.INCOMING 220ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || call.getState() == DialerCall.State.CALL_WAITING); 221ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian setStatusBarCallListener(new StatusBarCallListener(call)); 222ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 223ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // we make a call to the contact info cache to query for supplemental data to what the 224ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // call provides. This includes the contact name and photo. 225ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This callback will always get called immediately and synchronously with whatever data 226ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // it has available, and may make a subsequent call later (same thread) if it had to 227ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // call into the contacts provider for more data. 228ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContactInfoCache.findInfo( 229ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call, 230ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian isIncoming, 231ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new ContactInfoCacheCallback() { 232ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 233ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onContactInfoComplete(String callId, ContactCacheEntry entry) { 234ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian DialerCall call = callList.getCallById(callId); 235ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call != null) { 236ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call.getLogState().contactLookupResult = entry.contactLookupResult; 237ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian buildAndSendNotification(callList, call, entry); 238ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 239ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 240ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 241ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 242ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onImageLoadComplete(String callId, ContactCacheEntry entry) { 243ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian DialerCall call = callList.getCallById(callId); 244ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call != null) { 245ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian buildAndSendNotification(callList, call, entry); 246ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 247ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 248ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian }); 249ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 250ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 251ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Sets up the main Ui for the notification */ 252ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void buildAndSendNotification( 253ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian CallList callList, DialerCall originalCall, ContactCacheEntry contactInfo) { 254ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This can get called to update an existing notification after contact information has come 255ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // back. However, it can happen much later. Before we continue, we need to make sure that 256ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // the call being passed in is still the one we want to show in the notification. 257ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final DialerCall call = getCallToShow(callList); 258ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call == null || !call.getId().equals(originalCall.getId())) { 259ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return; 260ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 261ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 262ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final int callState = call.getState(); 263ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 264ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Check if data has changed; if nothing is different, don't issue another notification. 265ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final int iconResId = getIconToDisplay(call); 266ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Bitmap largeIcon = getLargeIconToDisplay(contactInfo, call); 267ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final String content = getContentString(call, contactInfo.userType); 268ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final String contentTitle = getContentTitle(contactInfo, call); 269ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 270ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final boolean isVideoUpgradeRequest = 271ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call.getSessionModificationState() 272ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian == DialerCall.SESSION_MODIFICATION_STATE_RECEIVED_UPGRADE_TO_VIDEO_REQUEST; 273ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final int notificationType; 274ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (callState == DialerCall.State.INCOMING 275ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || callState == DialerCall.State.CALL_WAITING 276ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || isVideoUpgradeRequest) { 277ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notificationType = NOTIFICATION_INCOMING_CALL; 278ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 279ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notificationType = NOTIFICATION_IN_CALL; 280ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 281ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 282ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!checkForChangeAndSaveData( 283ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian iconResId, 284ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian content, 285ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian largeIcon, 286ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian contentTitle, 287ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian callState, 288ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notificationType, 289ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian contactInfo.contactRingtoneUri)) { 290ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return; 291ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 292ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 293ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (largeIcon != null) { 294ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian largeIcon = getRoundedIcon(largeIcon); 295ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 296ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 297ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This builder is used for the notification shown when the device is locked and the user 298ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // has set their notification settings to 'hide sensitive content' 299ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // {@see Notification.Builder#setPublicVersion}. 300ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Notification.Builder publicBuilder = new Notification.Builder(mContext); 301ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian publicBuilder 302ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .setSmallIcon(iconResId) 303ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .setColor(mContext.getResources().getColor(R.color.dialer_theme_color)) 304ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Hide work call state for the lock screen notification 305ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .setContentTitle(getContentString(call, ContactsUtils.USER_TYPE_CURRENT)); 306ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian setNotificationWhen(call, callState, publicBuilder); 307ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 308ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Builder for the notification shown when the device is unlocked or the user has set their 309ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // notification settings to 'show all notification content'. 310ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final Notification.Builder builder = getNotificationBuilder(); 311ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setPublicVersion(publicBuilder.build()); 312ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 313ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Set up the main intent to send the user to the in-call screen 314ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setContentIntent( 315ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createLaunchPendingIntent(false /* isFullScreen */, call.isVideoCall())); 316ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 317ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Set the intent as a full screen intent as well if a call is incoming 318ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (notificationType == NOTIFICATION_INCOMING_CALL) { 319ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!InCallPresenter.getInstance().isActivityStarted()) { 320ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian configureFullScreenIntent( 321ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder, 322ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createLaunchPendingIntent(true /* isFullScreen */, call.isVideoCall()), 323ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian callList, 324ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call); 325ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 326ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // If the incall screen is already up, we don't want to show HUN but regular notification 327ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // should still be shown. In order to do that the previous one with full screen intent 328ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // needs to be cancelled. 329ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian LogUtil.d( 330ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian "StatusBarNotifier.buildAndSendNotification", 331ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian "cancel previous incoming call notification"); 332ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mNotificationManager.cancel(NOTIFICATION_INCOMING_CALL); 333ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 334ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Set the notification category for incoming calls 335ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setCategory(Notification.CATEGORY_CALL); 336ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 337ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 338ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Set the content 339ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setContentText(content); 340ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setSmallIcon(iconResId); 341ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setContentTitle(contentTitle); 342ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setLargeIcon(largeIcon); 343ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setColor(mContext.getResources().getColor(R.color.dialer_theme_color)); 344ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 345ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (isVideoUpgradeRequest) { 346ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setUsesChronometer(false); 347ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addDismissUpgradeRequestAction(builder); 348ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addAcceptUpgradeRequestAction(builder); 349ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 350ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createIncomingCallNotification(call, callState, builder); 351ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 352ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 353ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addPersonReference(builder, contactInfo, call); 354ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 355ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Fire off the notification 356ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Notification notification = builder.build(); 357ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 358ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mDialerRingtoneManager.shouldPlayRingtone(callState, contactInfo.contactRingtoneUri)) { 359ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notification.flags |= Notification.FLAG_INSISTENT; 360ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notification.sound = contactInfo.contactRingtoneUri; 361ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian AudioAttributes.Builder audioAttributes = new AudioAttributes.Builder(); 362ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian audioAttributes.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC); 363ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian audioAttributes.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE); 364ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notification.audioAttributes = audioAttributes.build(); 365ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mDialerRingtoneManager.shouldVibrate(mContext.getContentResolver())) { 366ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notification.vibrate = VIBRATE_PATTERN; 367ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 368ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 369ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mDialerRingtoneManager.shouldPlayCallWaitingTone(callState)) { 370ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.v(this, "Playing call waiting tone"); 371ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerRingtoneManager.playCallWaitingTone(); 372ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 373ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mCurrentNotification != notificationType && mCurrentNotification != NOTIFICATION_NONE) { 374ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.i(this, "Previous notification already showing - cancelling " + mCurrentNotification); 375ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mNotificationManager.cancel(mCurrentNotification); 376ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 377ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 378ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.i(this, "Displaying notification for " + notificationType); 379ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian try { 380ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mNotificationManager.notify(notificationType, notification); 381ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } catch (RuntimeException e) { 382ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // TODO(b/34744003): Move the memory stats into silent feedback PSD. 383ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian ActivityManager activityManager = mContext.getSystemService(ActivityManager.class); 384ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); 385ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian activityManager.getMemoryInfo(memoryInfo); 386ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian throw new RuntimeException( 387ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String.format( 388ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian "Error displaying notification with photo type: %d (low memory? %b, availMem: %d)", 389ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian contactInfo.photoType, memoryInfo.lowMemory, memoryInfo.availMem), 390ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian e); 391ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 392ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call.getLatencyReport().onNotificationShown(); 393ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mCurrentNotification = notificationType; 394ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 395ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 396ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void createIncomingCallNotification( 397ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian DialerCall call, int state, Notification.Builder builder) { 398ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian setNotificationWhen(call, state, builder); 399ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 400ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Add hang up option for any active calls (active | onhold), outgoing calls (dialing). 401ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (state == DialerCall.State.ACTIVE 402ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || state == DialerCall.State.ONHOLD 403ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || DialerCall.State.isDialing(state)) { 404ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addHangupAction(builder); 405ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (state == DialerCall.State.INCOMING || state == DialerCall.State.CALL_WAITING) { 406ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addDismissAction(builder); 407ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.isVideoCall()) { 408ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addVideoCallAction(builder); 409ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 410ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addAnswerAction(builder); 411ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 412ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 413ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 414ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 415ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 416ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Sets the notification's when section as needed. For active calls, this is explicitly set as the 417ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * duration of the call. For all other states, the notification will automatically show the time 418ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * at which the notification was created. 419ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 420ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void setNotificationWhen(DialerCall call, int state, Notification.Builder builder) { 421ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (state == DialerCall.State.ACTIVE) { 422ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setUsesChronometer(true); 423ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setWhen(call.getConnectTimeMillis()); 424ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 425ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setUsesChronometer(false); 426ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 427ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 428ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 429ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 430ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Checks the new notification data and compares it against any notification that we are already 431ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * displaying. If the data is exactly the same, we return false so that we do not issue a new 432ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * notification for the exact same data. 433ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 434ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private boolean checkForChangeAndSaveData( 435ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int icon, 436ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String content, 437ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Bitmap largeIcon, 438ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String contentTitle, 439ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int state, 440ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int notificationType, 441ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Uri ringtone) { 442ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 443ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // The two are different: 444ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // if new title is not null, it should be different from saved version OR 445ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // if new title is null, the saved version should not be null 446ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final boolean contentTitleChanged = 447ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian (contentTitle != null && !contentTitle.equals(mSavedContentTitle)) 448ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || (contentTitle == null && mSavedContentTitle != null); 449ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 450ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // any change means we are definitely updating 451ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian boolean retval = 452ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian (mSavedIcon != icon) 453ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || !Objects.equals(mSavedContent, content) 454ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || (mCallState != state) 455ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || (mSavedLargeIcon != largeIcon) 456ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || contentTitleChanged 457ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || !Objects.equals(mRingtone, ringtone); 458ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 459ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // If we aren't showing a notification right now or the notification type is changing, 460ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // definitely do an update. 461ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mCurrentNotification != notificationType) { 462ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mCurrentNotification == NOTIFICATION_NONE) { 463ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.d(this, "Showing notification for first time."); 464ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 465ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian retval = true; 466ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 467ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 468ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mSavedIcon = icon; 469ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mSavedContent = content; 470ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mCallState = state; 471ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mSavedLargeIcon = largeIcon; 472ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mSavedContentTitle = contentTitle; 473ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRingtone = ringtone; 474ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 475ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (retval) { 476ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.d(this, "Data changed. Showing notification"); 477ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 478ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 479ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return retval; 480ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 481ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 482ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Returns the main string to use in the notification. */ 483ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @VisibleForTesting 484ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Nullable 485ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String getContentTitle(ContactCacheEntry contactInfo, DialerCall call) { 486ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.isConferenceCall() && !call.hasProperty(Details.PROPERTY_GENERIC_CONFERENCE)) { 487ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return mContext.getResources().getString(R.string.conference_call_name); 488ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 489ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 490ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String preferredName = 491ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian ContactDisplayUtils.getPreferredDisplayName( 492ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian contactInfo.namePrimary, contactInfo.nameAlternative, mContactsPreferences); 493ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (TextUtils.isEmpty(preferredName)) { 494ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return TextUtils.isEmpty(contactInfo.number) 495ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian ? null 496ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian : BidiFormatter.getInstance() 497ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .unicodeWrap(contactInfo.number, TextDirectionHeuristics.LTR); 498ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 499ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return preferredName; 500ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 501ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 502ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addPersonReference( 503ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Notification.Builder builder, ContactCacheEntry contactInfo, DialerCall call) { 504ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Query {@link Contacts#CONTENT_LOOKUP_URI} directly with work lookup key is not allowed. 505ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // So, do not pass {@link Contacts#CONTENT_LOOKUP_URI} to NotificationManager to avoid 506ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // NotificationManager using it. 507ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (contactInfo.lookupUri != null && contactInfo.userType != ContactsUtils.USER_TYPE_WORK) { 508ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addPerson(contactInfo.lookupUri.toString()); 509ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (!TextUtils.isEmpty(call.getNumber())) { 510ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addPerson(Uri.fromParts(PhoneAccount.SCHEME_TEL, call.getNumber(), null).toString()); 511ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 512ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 513ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 514ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Gets a large icon from the contact info object to display in the notification. */ 515ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Bitmap getLargeIconToDisplay(ContactCacheEntry contactInfo, DialerCall call) { 516ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Bitmap largeIcon = null; 517ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.isConferenceCall() && !call.hasProperty(Details.PROPERTY_GENERIC_CONFERENCE)) { 518ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian largeIcon = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.img_conference); 519ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 520ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (contactInfo.photo != null && (contactInfo.photo instanceof BitmapDrawable)) { 521ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian largeIcon = ((BitmapDrawable) contactInfo.photo).getBitmap(); 522ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 523ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.isSpam()) { 524ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Drawable drawable = mContext.getResources().getDrawable(R.drawable.blocked_contact); 525ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian largeIcon = DrawableConverter.drawableToBitmap(drawable); 526ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 527ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return largeIcon; 528ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 529ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 530ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Bitmap getRoundedIcon(Bitmap bitmap) { 531ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (bitmap == null) { 532ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return null; 533ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 534ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final int height = 535ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian (int) mContext.getResources().getDimension(android.R.dimen.notification_large_icon_height); 536ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final int width = 537ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian (int) mContext.getResources().getDimension(android.R.dimen.notification_large_icon_width); 538ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return BitmapUtil.getRoundedBitmap(bitmap, width, height); 539ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 540ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 541ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 542ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Returns the appropriate icon res Id to display based on the call for which we want to display 543ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * information. 544ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 545ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private int getIconToDisplay(DialerCall call) { 546ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Even if both lines are in use, we only show a single item in 547ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // the expanded Notifications UI. It's labeled "Ongoing call" 548ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // (or "On hold" if there's only one call, and it's on hold.) 549ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Also, we don't have room to display caller-id info from two 550ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // different calls. So if both lines are in use, display info 551ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // from the foreground call. And if there's a ringing call, 552ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // display that regardless of the state of the other calls. 553ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.getState() == DialerCall.State.ONHOLD) { 554ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.drawable.ic_phone_paused_white_24dp; 555ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (call.getSessionModificationState() 556ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian == DialerCall.SESSION_MODIFICATION_STATE_RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { 557ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.drawable.ic_videocam; 558ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 559ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.anim.on_going_call; 560ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 561ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 562ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Returns the message to use with the notification. */ 563ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private String getContentString(DialerCall call, @UserType long userType) { 564ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian boolean isIncomingOrWaiting = 565ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call.getState() == DialerCall.State.INCOMING 566ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || call.getState() == DialerCall.State.CALL_WAITING; 567ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 568ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (isIncomingOrWaiting 569ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian && call.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED) { 570ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 571ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!TextUtils.isEmpty(call.getChildNumber())) { 572ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return mContext.getString(R.string.child_number, call.getChildNumber()); 573ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (!TextUtils.isEmpty(call.getCallSubject()) && call.isCallSubjectSupported()) { 574ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return call.getCallSubject(); 575ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 576ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 577ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 578ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int resId = R.string.notification_ongoing_call; 579ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.hasProperty(Details.PROPERTY_WIFI)) { 580ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_ongoing_call_wifi; 581ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 582ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 583ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (isIncomingOrWaiting) { 584ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.hasProperty(Details.PROPERTY_WIFI)) { 585ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_incoming_call_wifi; 586ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 587ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.isSpam()) { 588ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_incoming_spam_call; 589ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 590ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_incoming_call; 591ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 592ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 593ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (call.getState() == DialerCall.State.ONHOLD) { 594ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_on_hold; 595ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (DialerCall.State.isDialing(call.getState())) { 596ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_dialing; 597ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (call.getSessionModificationState() 598ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian == DialerCall.SESSION_MODIFICATION_STATE_RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { 599ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_requesting_video_call; 600ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 601ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 602ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Is the call placed through work connection service. 603ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian boolean isWorkCall = call.hasProperty(PROPERTY_ENTERPRISE_CALL); 604ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (userType == ContactsUtils.USER_TYPE_WORK || isWorkCall) { 605ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = getWorkStringFromPersonalString(resId); 606ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 607ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 608ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return mContext.getString(resId); 609ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 610ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 611ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Gets the most relevant call to display in the notification. */ 612ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private DialerCall getCallToShow(CallList callList) { 613ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (callList == null) { 614ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return null; 615ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 616ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian DialerCall call = callList.getIncomingCall(); 617ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call == null) { 618ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call = callList.getOutgoingCall(); 619ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 620ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call == null) { 621ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call = callList.getVideoUpgradeRequestCall(); 622ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 623ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call == null) { 624ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call = callList.getActiveOrBackgroundCall(); 625ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 626ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return call; 627ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 628ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 629ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Spannable getActionText(@StringRes int stringRes, @ColorRes int colorRes) { 630ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Spannable spannable = new SpannableString(mContext.getText(stringRes)); 631ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) { 632ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This will only work for cases where the Notification.Builder has a fullscreen intent set 633ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Notification.Builder that does not have a full screen intent will take the color of the 634ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // app and the following leads to a no-op. 635ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian spannable.setSpan( 636ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new ForegroundColorSpan(mContext.getColor(colorRes)), 0, spannable.length(), 0); 637ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 638ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return spannable; 639ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 640ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 641ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addAnswerAction(Notification.Builder builder) { 642ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.d(this, "Will show \"answer\" action in the incoming call Notification"); 643ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent answerVoicePendingIntent = 644ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_ANSWER_VOICE_INCOMING_CALL); 645ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 646ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian R.anim.on_going_call, 647ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getActionText(R.string.notification_action_answer, R.color.notification_action_accept), 648ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian answerVoicePendingIntent); 649ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 650ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 651ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addDismissAction(Notification.Builder builder) { 652ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.d(this, "Will show \"decline\" action in the incoming call Notification"); 653ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent declinePendingIntent = 654ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_DECLINE_INCOMING_CALL); 655ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 656ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian R.drawable.ic_close_dk, 657ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getActionText(R.string.notification_action_dismiss, R.color.notification_action_dismiss), 658ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian declinePendingIntent); 659ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 660ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 661ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addHangupAction(Notification.Builder builder) { 662ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.d(this, "Will show \"hang-up\" action in the ongoing active call Notification"); 663ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent hangupPendingIntent = 664ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_HANG_UP_ONGOING_CALL); 665ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 666ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian R.drawable.ic_call_end_white_24dp, 667ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getActionText(R.string.notification_action_end_call, R.color.notification_action_end_call), 668ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian hangupPendingIntent); 669ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 670ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 671ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addVideoCallAction(Notification.Builder builder) { 672ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.i(this, "Will show \"video\" action in the incoming call Notification"); 673ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent answerVideoPendingIntent = 674ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_ANSWER_VIDEO_INCOMING_CALL); 675ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 676ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian R.drawable.ic_videocam, 677ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getActionText( 678ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian R.string.notification_action_answer_video, R.color.notification_action_answer_video), 679ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian answerVideoPendingIntent); 680ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 681ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 682ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addAcceptUpgradeRequestAction(Notification.Builder builder) { 683ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.i(this, "Will show \"accept upgrade\" action in the incoming call Notification"); 684ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent acceptVideoPendingIntent = 685ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST); 686ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 687ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian R.drawable.ic_videocam, 688ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getActionText(R.string.notification_action_accept, R.color.notification_action_accept), 689ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian acceptVideoPendingIntent); 690ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 691ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 692ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addDismissUpgradeRequestAction(Notification.Builder builder) { 693ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.i(this, "Will show \"dismiss upgrade\" action in the incoming call Notification"); 694ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent declineVideoPendingIntent = 695ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_DECLINE_VIDEO_UPGRADE_REQUEST); 696ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 697ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian R.drawable.ic_videocam, 698ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian getActionText(R.string.notification_action_dismiss, R.color.notification_action_dismiss), 699ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian declineVideoPendingIntent); 700ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 701ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 702ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Adds fullscreen intent to the builder. */ 703ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void configureFullScreenIntent( 704ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Notification.Builder builder, PendingIntent intent, CallList callList, DialerCall call) { 705ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Ok, we actually want to launch the incoming call 706ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // UI at this point (in addition to simply posting a notification 707ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // to the status bar). Setting fullScreenIntent will cause 708ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // the InCallScreen to be launched immediately *unless* the 709ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // current foreground activity is marked as "immersive". 710ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.d(this, "- Setting fullScreenIntent: " + intent); 711ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setFullScreenIntent(intent, true); 712ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 713ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Ugly hack alert: 714ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // 715ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // The NotificationManager has the (undocumented) behavior 716ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // that it will *ignore* the fullScreenIntent field if you 717ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // post a new Notification that matches the ID of one that's 718ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // already active. Unfortunately this is exactly what happens 719ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // when you get an incoming call-waiting call: the 720ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // "ongoing call" notification is already visible, so the 721ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // InCallScreen won't get launched in this case! 722ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // (The result: if you bail out of the in-call UI while on a 723ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // call and then get a call-waiting call, the incoming call UI 724ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // won't come up automatically.) 725ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // 726ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // The workaround is to just notice this exact case (this is a 727ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // call-waiting call *and* the InCallScreen is not in the 728ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // foreground) and manually cancel the in-call notification 729ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // before (re)posting it. 730ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // 731ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // TODO: there should be a cleaner way of avoiding this 732ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // problem (see discussion in bug 3184149.) 733ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 734ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // If a call is onhold during an incoming call, the call actually comes in as 735ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // INCOMING. For that case *and* traditional call-waiting, we want to 736ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // cancel the notification. 737ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian boolean isCallWaiting = 738ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian (call.getState() == DialerCall.State.CALL_WAITING 739ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || (call.getState() == DialerCall.State.INCOMING 740ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian && callList.getBackgroundCall() != null)); 741ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 742ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (isCallWaiting) { 743ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Log.i(this, "updateInCallNotification: call-waiting! force relaunch..."); 744ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Cancel the IN_CALL_NOTIFICATION immediately before 745ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // (re)posting it; this seems to force the 746ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // NotificationManager to launch the fullScreenIntent. 747ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mNotificationManager.cancel(NOTIFICATION_IN_CALL); 748ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 749ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 750ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 751ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Notification.Builder getNotificationBuilder() { 752ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final Notification.Builder builder = new Notification.Builder(mContext); 753ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setOngoing(true); 754ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 755ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Make the notification prioritized over the other normal notifications. 756ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setPriority(Notification.PRIORITY_HIGH); 757ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 758ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return builder; 759ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 760ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 761ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private PendingIntent createLaunchPendingIntent(boolean isFullScreen, boolean isVideoCall) { 762ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Intent intent = 763ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian InCallActivity.getIntent( 764ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContext, 765ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian false /* showDialpad */, 766ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian false /* newOutgoingCall */, 767ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian isVideoCall, 768ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian isFullScreen); 769ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 770ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int requestCode = PENDING_INTENT_REQUEST_CODE_NON_FULL_SCREEN; 771ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (isFullScreen) { 772ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Use a unique request code so that the pending intent isn't clobbered by the 773ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // non-full screen pending intent. 774ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian requestCode = PENDING_INTENT_REQUEST_CODE_FULL_SCREEN; 775ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 776ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 777ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // PendingIntent that can be used to launch the InCallActivity. The 778ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // system fires off this intent if the user pulls down the windowshade 779ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // and clicks the notification's expanded view. It's also used to 780ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // launch the InCallActivity immediately when when there's an incoming 781ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // call (see the "fullScreenIntent" field below). 782ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return PendingIntent.getActivity(mContext, requestCode, intent, 0); 783ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 784ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 785ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void setStatusBarCallListener(StatusBarCallListener listener) { 786ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mStatusBarCallListener != null) { 787ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mStatusBarCallListener.cleanup(); 788ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 789ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mStatusBarCallListener = listener; 790ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 791ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 792ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private class StatusBarCallListener implements DialerCallListener { 793ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 794ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private DialerCall mDialerCall; 795ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 796ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian StatusBarCallListener(DialerCall dialerCall) { 797ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerCall = dialerCall; 798ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerCall.addListener(this); 799ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 800ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 801ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian void cleanup() { 802ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerCall.removeListener(this); 803ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 804ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 805ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 806ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDialerCallDisconnect() {} 807ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 808ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 809ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDialerCallUpdate() { 810ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (CallList.getInstance().getIncomingCall() == null) { 811ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerRingtoneManager.stopCallWaitingTone(); 812ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 813ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 814ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 815ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 816ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDialerCallChildNumberChange() {} 817ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 818ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 819ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDialerCallLastForwardedNumberChange() {} 820ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 821ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 822ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDialerCallUpgradeToVideo() {} 823ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 824ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 825ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onWiFiToLteHandover() {} 826ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 827ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 828ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onHandoverToWifiFailure() {} 829ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 830ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 831ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Responds to changes in the session modification state for the call by dismissing the status 832ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * bar notification as required. 833ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 834ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 835ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDialerCallSessionModificationStateChange(@SessionModificationState int state) { 836ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (state == DialerCall.SESSION_MODIFICATION_STATE_NO_REQUEST) { 837ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian cleanup(); 838ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian updateNotification(CallList.getInstance()); 839ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 840ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 841ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 842ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian} 843