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 199050823ccf6f512e06ad65c8a741cb17cbc4a833Eric Erfanianimport static android.telecom.Call.Details.PROPERTY_HIGH_DEF_AUDIO; 20ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.contacts.common.compat.CallCompat.Details.PROPERTY_ENTERPRISE_CALL; 21ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST; 22ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_ANSWER_VIDEO_INCOMING_CALL; 23ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_ANSWER_VOICE_INCOMING_CALL; 24ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_DECLINE_INCOMING_CALL; 25ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_DECLINE_VIDEO_UPGRADE_REQUEST; 26ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport static com.android.incallui.NotificationBroadcastReceiver.ACTION_HANG_UP_ONGOING_CALL; 27ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 28d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.Manifest; 29ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.app.ActivityManager; 30ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.app.Notification; 31ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.app.NotificationManager; 32ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.app.PendingIntent; 33ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.Context; 34ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.content.Intent; 3583b20211c3be04a850de3674977deee8e448d17fEric Erfanianimport android.content.res.Resources; 36ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.graphics.Bitmap; 37ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.graphics.drawable.BitmapDrawable; 38ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.graphics.drawable.Drawable; 39d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.graphics.drawable.Icon; 40ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.media.AudioAttributes; 41ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.net.Uri; 42ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.os.Build.VERSION; 43ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.os.Build.VERSION_CODES; 44ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.ColorRes; 45ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.NonNull; 46ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.Nullable; 47d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.support.annotation.RequiresPermission; 48ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.StringRes; 49ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.support.annotation.VisibleForTesting; 50d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.support.v4.os.BuildCompat; 51ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.telecom.Call.Details; 52ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.telecom.PhoneAccount; 53d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport android.telecom.PhoneAccountHandle; 54ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.telecom.TelecomManager; 55ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.BidiFormatter; 56ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.Spannable; 57ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.SpannableString; 58ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.TextDirectionHeuristics; 59ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.TextUtils; 60ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport android.text.style.ForegroundColorSpan; 61ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.ContactsUtils; 62ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.ContactsUtils.UserType; 63d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport com.android.contacts.common.lettertiles.LetterTileDrawable; 642f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanianimport com.android.contacts.common.lettertiles.LetterTileDrawable.ContactType; 65ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.preference.ContactsPreferences; 66ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.util.BitmapUtil; 67ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.contacts.common.util.ContactDisplayUtils; 68ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.common.LogUtil; 693128dea03a0e3981511dfed6f3ef555f0b574725twyenimport com.android.dialer.configprovider.ConfigProviderBindings; 70d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanianimport com.android.dialer.enrichedcall.EnrichedCallManager; 71d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanianimport com.android.dialer.enrichedcall.Session; 72d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanianimport com.android.dialer.multimedia.MultimediaData; 732f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanianimport com.android.dialer.notification.NotificationChannelId; 749050823ccf6f512e06ad65c8a741cb17cbc4a833Eric Erfanianimport com.android.dialer.oem.MotorolaUtils; 75ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.dialer.util.DrawableConverter; 76ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.ContactInfoCache.ContactCacheEntry; 77ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.ContactInfoCache.ContactInfoCacheCallback; 78ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.InCallPresenter.InCallState; 79ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.async.PausableExecutorImpl; 80ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.call.CallList; 81ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.call.DialerCall; 82ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.call.DialerCallListener; 83ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.ringtone.DialerRingtoneManager; 84ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.ringtone.InCallTonePlayer; 85ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport com.android.incallui.ringtone.ToneGeneratorFactory; 869050823ccf6f512e06ad65c8a741cb17cbc4a833Eric Erfanianimport com.android.incallui.videotech.utils.SessionModificationState; 87d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport java.util.List; 88d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanianimport java.util.Locale; 89ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanianimport java.util.Objects; 90ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 91ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian/** This class adds Notifications to the status bar for the in-call experience. */ 92d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanianpublic class StatusBarNotifier 93d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian implements InCallPresenter.InCallStateListener, EnrichedCallManager.StateChangedListener { 94ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 952f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian private static final String NOTIFICATION_TAG = "STATUS_BAR_NOTIFIER"; 962f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian private static final int NOTIFICATION_ID = 1; 972f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian 98ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Notification types 99ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Indicates that no notification is currently showing. 100ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final int NOTIFICATION_NONE = 0; 101ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Notification for an active call. This is non-interruptive, but cannot be dismissed. 10210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian private static final int NOTIFICATION_IN_CALL = 1; 103ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Notification for incoming calls. This is interruptive and will show up as a HUN. 10410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian private static final int NOTIFICATION_INCOMING_CALL = 2; 10510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian // Notification for incoming calls in the case where there is already an active call. 10610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian // This is non-interruptive, but otherwise behaves the same as NOTIFICATION_INCOMING_CALL 10710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian private static final int NOTIFICATION_INCOMING_CALL_QUIET = 3; 108ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 109ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final int PENDING_INTENT_REQUEST_CODE_NON_FULL_SCREEN = 0; 110ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final int PENDING_INTENT_REQUEST_CODE_FULL_SCREEN = 1; 111ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 112ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static final long[] VIBRATE_PATTERN = new long[] {0, 1000, 1000}; 113ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 114ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final Context mContext; 115ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final ContactInfoCache mContactInfoCache; 116ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final NotificationManager mNotificationManager; 117ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private final DialerRingtoneManager mDialerRingtoneManager; 118ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Nullable private ContactsPreferences mContactsPreferences; 119ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private int mCurrentNotification = NOTIFICATION_NONE; 120ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private int mCallState = DialerCall.State.INVALID; 121ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private int mSavedIcon = 0; 122ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private String mSavedContent = null; 123ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Bitmap mSavedLargeIcon; 124ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private String mSavedContentTitle; 125ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Uri mRingtone; 126ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private StatusBarCallListener mStatusBarCallListener; 127ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 128d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian public StatusBarNotifier(@NonNull Context context, @NonNull ContactInfoCache contactInfoCache) { 129ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Objects.requireNonNull(context); 130ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContext = context; 131ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContactsPreferences = ContactsPreferencesFactory.newContactsPreferences(mContext); 132ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContactInfoCache = contactInfoCache; 133ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mNotificationManager = context.getSystemService(NotificationManager.class); 134ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerRingtoneManager = 135ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new DialerRingtoneManager( 136ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new InCallTonePlayer(new ToneGeneratorFactory(), new PausableExecutorImpl()), 137ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian CallList.getInstance()); 138ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mCurrentNotification = NOTIFICATION_NONE; 139ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 140ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 141ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 142ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Should only be called from a irrecoverable state where it is necessary to dismiss all 143ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * notifications. 144ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 145ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian static void clearAllCallNotifications(Context backupContext) { 146d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.i( 147d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "StatusBarNotifier.clearAllCallNotifications", 148d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "something terrible happened, clear all InCall notifications"); 149ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 150ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian NotificationManager notificationManager = 151ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian backupContext.getSystemService(NotificationManager.class); 1522f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian notificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID); 153ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 154ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 155ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static int getWorkStringFromPersonalString(int resId) { 156ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (resId == R.string.notification_ongoing_call) { 157ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.string.notification_ongoing_work_call; 158ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (resId == R.string.notification_ongoing_call_wifi) { 159ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.string.notification_ongoing_work_call_wifi; 160ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (resId == R.string.notification_incoming_call_wifi) { 161ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.string.notification_incoming_work_call_wifi; 162ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (resId == R.string.notification_incoming_call) { 163ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.string.notification_incoming_work_call; 164ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 165ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return resId; 166ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 167ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 168ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 169ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 170ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Returns PendingIntent for answering a phone call. This will typically be used from Notification 171ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * context. 172ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 173ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private static PendingIntent createNotificationPendingIntent(Context context, String action) { 174ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final Intent intent = new Intent(action, null, context, NotificationBroadcastReceiver.class); 175ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return PendingIntent.getBroadcast(context, 0, intent, 0); 176ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 177ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 178ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Creates notifications according to the state we receive from {@link InCallPresenter}. */ 179ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 180d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian @RequiresPermission(Manifest.permission.READ_PHONE_STATE) 181ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onStateChange(InCallState oldState, InCallState newState, CallList callList) { 182d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.d("StatusBarNotifier.onStateChange", "%s->%s", oldState, newState); 183ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian updateNotification(callList); 184ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 185ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 186d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian @Override 187d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian public void onEnrichedCallStateChanged() { 188d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian LogUtil.enterBlock("StatusBarNotifier.onEnrichedCallStateChanged"); 189d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian updateNotification(CallList.getInstance()); 190d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 191d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian 192ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 193ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Updates the phone app's status bar notification *and* launches the incoming call UI in response 194ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * to a new incoming call. 195ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 196ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>If an incoming call is ringing (or call-waiting), the notification will also include a 197ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * "fullScreenIntent" that will cause the InCallScreen to be launched, unless the current 198ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * foreground activity is marked as "immersive". 199ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 200ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>(This is the mechanism that actually brings up the incoming call UI when we receive a "new 201ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * ringing connection" event from the telephony layer.) 202ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 203ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * <p>Also note that this method is safe to call even if the phone isn't actually ringing (or, 204ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * more likely, if an incoming call *was* ringing briefly but then disconnected). In that case, 205ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * we'll simply update or cancel the in-call notification based on the current phone state. 206ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 207ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @see #updateInCallNotification(CallList) 208ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 209d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian @RequiresPermission(Manifest.permission.READ_PHONE_STATE) 210d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian public void updateNotification(CallList callList) { 211ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian updateInCallNotification(callList); 212ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 213ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 214ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 215ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Take down the in-call notification. 216ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * 217ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * @see #updateInCallNotification(CallList) 218ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 219ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void cancelNotification() { 220ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mStatusBarCallListener != null) { 221ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian setStatusBarCallListener(null); 222ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 223ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mCurrentNotification != NOTIFICATION_NONE) { 2248369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian LogUtil.i("StatusBarNotifier.cancelNotification", "cancel"); 2252f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID); 226ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 227ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mCurrentNotification = NOTIFICATION_NONE; 228ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 229ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 230ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 231ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Helper method for updateInCallNotification() and updateNotification(): Update the phone app's 232ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * status bar notification based on the current telephony state, or cancels the notification if 233ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * the phone is totally idle. 234ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 235d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian @RequiresPermission(Manifest.permission.READ_PHONE_STATE) 236ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void updateInCallNotification(CallList callList) { 237d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.d("StatusBarNotifier.updateInCallNotification", ""); 238ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 239ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final DialerCall call = getCallToShow(callList); 240ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 241ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call != null) { 242ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian showNotification(callList, call); 243ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 244ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian cancelNotification(); 245ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 246ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 247ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 248d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian @RequiresPermission(Manifest.permission.READ_PHONE_STATE) 249ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void showNotification(final CallList callList, final DialerCall call) { 250ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final boolean isIncoming = 251ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian (call.getState() == DialerCall.State.INCOMING 252ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || call.getState() == DialerCall.State.CALL_WAITING); 253ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian setStatusBarCallListener(new StatusBarCallListener(call)); 254ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 255ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // we make a call to the contact info cache to query for supplemental data to what the 256ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // call provides. This includes the contact name and photo. 257ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This callback will always get called immediately and synchronously with whatever data 258ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // it has available, and may make a subsequent call later (same thread) if it had to 259ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // call into the contacts provider for more data. 260ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mContactInfoCache.findInfo( 261ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call, 262ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian isIncoming, 263ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new ContactInfoCacheCallback() { 264ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 265d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian @RequiresPermission(Manifest.permission.READ_PHONE_STATE) 266ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onContactInfoComplete(String callId, ContactCacheEntry entry) { 267ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian DialerCall call = callList.getCallById(callId); 268ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call != null) { 269ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call.getLogState().contactLookupResult = entry.contactLookupResult; 270ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian buildAndSendNotification(callList, call, entry); 271ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 272ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 273ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 274ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 275d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian @RequiresPermission(Manifest.permission.READ_PHONE_STATE) 276ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onImageLoadComplete(String callId, ContactCacheEntry entry) { 277ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian DialerCall call = callList.getCallById(callId); 278ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call != null) { 279ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian buildAndSendNotification(callList, call, entry); 280ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 281ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 282ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian }); 283ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 284ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 285ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Sets up the main Ui for the notification */ 286d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian @RequiresPermission(Manifest.permission.READ_PHONE_STATE) 287ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void buildAndSendNotification( 288ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian CallList callList, DialerCall originalCall, ContactCacheEntry contactInfo) { 289ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This can get called to update an existing notification after contact information has come 290ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // back. However, it can happen much later. Before we continue, we need to make sure that 291ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // the call being passed in is still the one we want to show in the notification. 292ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final DialerCall call = getCallToShow(callList); 293ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call == null || !call.getId().equals(originalCall.getId())) { 294ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return; 295ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 296ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 297ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final int callState = call.getState(); 298ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 299ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Check if data has changed; if nothing is different, don't issue another notification. 300ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final int iconResId = getIconToDisplay(call); 30183b20211c3be04a850de3674977deee8e448d17fEric Erfanian Bitmap largeIcon = getLargeIconToDisplay(mContext, contactInfo, call); 302ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final String content = getContentString(call, contactInfo.userType); 303ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final String contentTitle = getContentTitle(contactInfo, call); 304ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 305ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final boolean isVideoUpgradeRequest = 306d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian call.getVideoTech().getSessionModificationState() 3079050823ccf6f512e06ad65c8a741cb17cbc4a833Eric Erfanian == SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST; 308ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final int notificationType; 309ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (callState == DialerCall.State.INCOMING 310ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || callState == DialerCall.State.CALL_WAITING 311ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || isVideoUpgradeRequest) { 3123128dea03a0e3981511dfed6f3ef555f0b574725twyen if (ConfigProviderBindings.get(mContext) 3133128dea03a0e3981511dfed6f3ef555f0b574725twyen .getBoolean("quiet_incoming_call_if_ui_showing", true)) { 3143128dea03a0e3981511dfed6f3ef555f0b574725twyen notificationType = 3153128dea03a0e3981511dfed6f3ef555f0b574725twyen InCallPresenter.getInstance().isShowingInCallUi() 3163128dea03a0e3981511dfed6f3ef555f0b574725twyen ? NOTIFICATION_INCOMING_CALL_QUIET 3173128dea03a0e3981511dfed6f3ef555f0b574725twyen : NOTIFICATION_INCOMING_CALL; 3183128dea03a0e3981511dfed6f3ef555f0b574725twyen } else { 3193128dea03a0e3981511dfed6f3ef555f0b574725twyen boolean alreadyActive = 3203128dea03a0e3981511dfed6f3ef555f0b574725twyen callList.getActiveOrBackgroundCall() != null 3213128dea03a0e3981511dfed6f3ef555f0b574725twyen && InCallPresenter.getInstance().isShowingInCallUi(); 3223128dea03a0e3981511dfed6f3ef555f0b574725twyen notificationType = 3233128dea03a0e3981511dfed6f3ef555f0b574725twyen alreadyActive ? NOTIFICATION_INCOMING_CALL_QUIET : NOTIFICATION_INCOMING_CALL; 3243128dea03a0e3981511dfed6f3ef555f0b574725twyen } 325ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 326ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notificationType = NOTIFICATION_IN_CALL; 327ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 328ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 329ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!checkForChangeAndSaveData( 330ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian iconResId, 331ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian content, 332ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian largeIcon, 333ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian contentTitle, 334ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian callState, 335ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notificationType, 3368369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian contactInfo.contactRingtoneUri)) { 337ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return; 338ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 339ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 340ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (largeIcon != null) { 341ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian largeIcon = getRoundedIcon(largeIcon); 342ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 343ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 344ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This builder is used for the notification shown when the device is locked and the user 345ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // has set their notification settings to 'hide sensitive content' 346ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // {@see Notification.Builder#setPublicVersion}. 347ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Notification.Builder publicBuilder = new Notification.Builder(mContext); 348ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian publicBuilder 349ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .setSmallIcon(iconResId) 350d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian .setColor(mContext.getResources().getColor(R.color.dialer_theme_color, mContext.getTheme())) 351ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Hide work call state for the lock screen notification 352ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .setContentTitle(getContentString(call, ContactsUtils.USER_TYPE_CURRENT)); 353ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian setNotificationWhen(call, callState, publicBuilder); 354ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 355ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Builder for the notification shown when the device is unlocked or the user has set their 356ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // notification settings to 'show all notification content'. 357ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final Notification.Builder builder = getNotificationBuilder(); 358ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setPublicVersion(publicBuilder.build()); 359ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 360ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Set up the main intent to send the user to the in-call screen 361d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian builder.setContentIntent(createLaunchPendingIntent(false /* isFullScreen */)); 362ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 363ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Set the intent as a full screen intent as well if a call is incoming 364d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian PhoneAccountHandle accountHandle = call.getAccountHandle(); 365d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (accountHandle == null) { 366d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian accountHandle = getAnyPhoneAccount(); 367d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 36810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian 36910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian LogUtil.i("StatusBarNotifier.buildAndSendNotification", "notificationType=" + notificationType); 37010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian switch (notificationType) { 37110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian case NOTIFICATION_INCOMING_CALL: 3722f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian if (BuildCompat.isAtLeastO()) { 3732f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian builder.setChannelId(NotificationChannelId.INCOMING_CALL); 3742f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian } 37510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian configureFullScreenIntent(builder, createLaunchPendingIntent(true /* isFullScreen */)); 37610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian // Set the notification category and bump the priority for incoming calls 37710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian builder.setCategory(Notification.CATEGORY_CALL); 37810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian // This will be ignored on O+ and handled by the channel 37910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian builder.setPriority(Notification.PRIORITY_MAX); 38010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian if (mCurrentNotification != NOTIFICATION_INCOMING_CALL) { 38110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian LogUtil.i( 38210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian "StatusBarNotifier.buildAndSendNotification", 38310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian "Canceling old notification so this one can be noisy"); 38410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian // Moving from a non-interuptive notification (or none) to a noisy one. Cancel the old 38510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian // notification (if there is one) so the fullScreenIntent or HUN will show 3862f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID); 38710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian } 38810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian break; 38910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian case NOTIFICATION_INCOMING_CALL_QUIET: 3902f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian if (BuildCompat.isAtLeastO()) { 3912f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian builder.setChannelId(NotificationChannelId.ONGOING_CALL); 3922f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian } 39310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian break; 39410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian case NOTIFICATION_IN_CALL: 3952f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian if (BuildCompat.isAtLeastO()) { 3962f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian publicBuilder.setColorized(true); 3972f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian builder.setColorized(true); 3982f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian builder.setChannelId(NotificationChannelId.ONGOING_CALL); 3992f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian } 40010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian break; 401ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 402ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 403ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Set the content 404ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setContentText(content); 405ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setSmallIcon(iconResId); 406ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setContentTitle(contentTitle); 407ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setLargeIcon(largeIcon); 408d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian builder.setColor( 409d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mContext.getResources().getColor(R.color.dialer_theme_color, mContext.getTheme())); 410ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 411ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (isVideoUpgradeRequest) { 412ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setUsesChronometer(false); 413ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addDismissUpgradeRequestAction(builder); 414ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addAcceptUpgradeRequestAction(builder); 415ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 416ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createIncomingCallNotification(call, callState, builder); 417ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 418ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 419ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addPersonReference(builder, contactInfo, call); 420ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 421ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Fire off the notification 422ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Notification notification = builder.build(); 423ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 424ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mDialerRingtoneManager.shouldPlayRingtone(callState, contactInfo.contactRingtoneUri)) { 425ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notification.flags |= Notification.FLAG_INSISTENT; 426ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notification.sound = contactInfo.contactRingtoneUri; 427ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian AudioAttributes.Builder audioAttributes = new AudioAttributes.Builder(); 428ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian audioAttributes.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC); 429ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian audioAttributes.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE); 430ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notification.audioAttributes = audioAttributes.build(); 431ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mDialerRingtoneManager.shouldVibrate(mContext.getContentResolver())) { 432ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian notification.vibrate = VIBRATE_PATTERN; 433ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 434ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 435ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mDialerRingtoneManager.shouldPlayCallWaitingTone(callState)) { 436d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.v("StatusBarNotifier.buildAndSendNotification", "playing call waiting tone"); 437ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerRingtoneManager.playCallWaitingTone(); 438ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 439ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 440d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.i( 441d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "StatusBarNotifier.buildAndSendNotification", 442d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "displaying notification for " + notificationType); 443d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 444ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian try { 4452f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, notification); 446ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } catch (RuntimeException e) { 447ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // TODO(b/34744003): Move the memory stats into silent feedback PSD. 448ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian ActivityManager activityManager = mContext.getSystemService(ActivityManager.class); 449ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); 450ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian activityManager.getMemoryInfo(memoryInfo); 451ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian throw new RuntimeException( 452ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String.format( 453d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Locale.US, 454ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian "Error displaying notification with photo type: %d (low memory? %b, availMem: %d)", 455d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian contactInfo.photoType, 456d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian memoryInfo.lowMemory, 457d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian memoryInfo.availMem), 458ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian e); 459ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 460ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call.getLatencyReport().onNotificationShown(); 461ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mCurrentNotification = notificationType; 462ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 463ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 464d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian @Nullable 465d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian @RequiresPermission(Manifest.permission.READ_PHONE_STATE) 466d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private PhoneAccountHandle getAnyPhoneAccount() { 467d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian PhoneAccountHandle accountHandle; 468d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); 469d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian accountHandle = telecomManager.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL); 470d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (accountHandle == null) { 471d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian List<PhoneAccountHandle> accountHandles = telecomManager.getCallCapablePhoneAccounts(); 472d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (!accountHandles.isEmpty()) { 473d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian accountHandle = accountHandles.get(0); 474d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 475d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 476d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian return accountHandle; 477d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 478d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 479ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void createIncomingCallNotification( 480ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian DialerCall call, int state, Notification.Builder builder) { 481ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian setNotificationWhen(call, state, builder); 482ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 483ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Add hang up option for any active calls (active | onhold), outgoing calls (dialing). 484ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (state == DialerCall.State.ACTIVE 485ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || state == DialerCall.State.ONHOLD 486ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || DialerCall.State.isDialing(state)) { 487ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addHangupAction(builder); 488ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (state == DialerCall.State.INCOMING || state == DialerCall.State.CALL_WAITING) { 489ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addDismissAction(builder); 490ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.isVideoCall()) { 491ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addVideoCallAction(builder); 492ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 493ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian addAnswerAction(builder); 494ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 495ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 496ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 497ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 498ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 499ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Sets the notification's when section as needed. For active calls, this is explicitly set as the 500ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * duration of the call. For all other states, the notification will automatically show the time 501ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * at which the notification was created. 502ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 503ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void setNotificationWhen(DialerCall call, int state, Notification.Builder builder) { 504ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (state == DialerCall.State.ACTIVE) { 505ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setUsesChronometer(true); 506ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setWhen(call.getConnectTimeMillis()); 507ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 508ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setUsesChronometer(false); 509ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 510ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 511ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 512ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 513ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Checks the new notification data and compares it against any notification that we are already 514ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * displaying. If the data is exactly the same, we return false so that we do not issue a new 515ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * notification for the exact same data. 516ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 517ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private boolean checkForChangeAndSaveData( 518ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int icon, 519ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String content, 520ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Bitmap largeIcon, 521ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String contentTitle, 522ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int state, 523ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int notificationType, 5248369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian Uri ringtone) { 525ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 526ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // The two are different: 527ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // if new title is not null, it should be different from saved version OR 528ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // if new title is null, the saved version should not be null 529ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final boolean contentTitleChanged = 530ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian (contentTitle != null && !contentTitle.equals(mSavedContentTitle)) 531ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || (contentTitle == null && mSavedContentTitle != null); 532ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 5338369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian boolean largeIconChanged = 5348369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian mSavedLargeIcon == null ? largeIcon != null : !mSavedLargeIcon.sameAs(largeIcon); 5358369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian 536ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // any change means we are definitely updating 537ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian boolean retval = 538ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian (mSavedIcon != icon) 539ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || !Objects.equals(mSavedContent, content) 540ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || (mCallState != state) 5418369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian || largeIconChanged 542ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || contentTitleChanged 5438369df095a73a77b3715f8ae7ba06089cebca4ceEric Erfanian || !Objects.equals(mRingtone, ringtone); 544ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 545ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // If we aren't showing a notification right now or the notification type is changing, 546ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // definitely do an update. 547ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mCurrentNotification != notificationType) { 548ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mCurrentNotification == NOTIFICATION_NONE) { 549d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.d( 550d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "StatusBarNotifier.checkForChangeAndSaveData", "showing notification for first time."); 551ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 552ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian retval = true; 553ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 554ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 555ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mSavedIcon = icon; 556ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mSavedContent = content; 557ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mCallState = state; 558ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mSavedLargeIcon = largeIcon; 559ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mSavedContentTitle = contentTitle; 560ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mRingtone = ringtone; 561ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 562ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (retval) { 563d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.d( 564d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "StatusBarNotifier.checkForChangeAndSaveData", "data changed. Showing notification"); 565ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 566ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 567ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return retval; 568ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 569ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 570ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Returns the main string to use in the notification. */ 571ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @VisibleForTesting 572ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Nullable 573ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String getContentTitle(ContactCacheEntry contactInfo, DialerCall call) { 5742f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian if (call.isConferenceCall()) { 5752f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian return CallerInfoUtils.getConferenceString( 5762f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian mContext, call.hasProperty(Details.PROPERTY_GENERIC_CONFERENCE)); 577ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 578ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 579ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian String preferredName = 580ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian ContactDisplayUtils.getPreferredDisplayName( 581ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian contactInfo.namePrimary, contactInfo.nameAlternative, mContactsPreferences); 582ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (TextUtils.isEmpty(preferredName)) { 583ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return TextUtils.isEmpty(contactInfo.number) 584ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian ? null 585ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian : BidiFormatter.getInstance() 586ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian .unicodeWrap(contactInfo.number, TextDirectionHeuristics.LTR); 587ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 588ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return preferredName; 589ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 590ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 591ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addPersonReference( 592ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Notification.Builder builder, ContactCacheEntry contactInfo, DialerCall call) { 593ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Query {@link Contacts#CONTENT_LOOKUP_URI} directly with work lookup key is not allowed. 594ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // So, do not pass {@link Contacts#CONTENT_LOOKUP_URI} to NotificationManager to avoid 595ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // NotificationManager using it. 596ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (contactInfo.lookupUri != null && contactInfo.userType != ContactsUtils.USER_TYPE_WORK) { 597ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addPerson(contactInfo.lookupUri.toString()); 598ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (!TextUtils.isEmpty(call.getNumber())) { 599ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addPerson(Uri.fromParts(PhoneAccount.SCHEME_TEL, call.getNumber(), null).toString()); 600ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 601ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 602ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 603ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Gets a large icon from the contact info object to display in the notification. */ 60483b20211c3be04a850de3674977deee8e448d17fEric Erfanian private static Bitmap getLargeIconToDisplay( 60583b20211c3be04a850de3674977deee8e448d17fEric Erfanian Context context, ContactCacheEntry contactInfo, DialerCall call) { 60683b20211c3be04a850de3674977deee8e448d17fEric Erfanian Resources resources = context.getResources(); 607ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Bitmap largeIcon = null; 608ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (contactInfo.photo != null && (contactInfo.photo instanceof BitmapDrawable)) { 609ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian largeIcon = ((BitmapDrawable) contactInfo.photo).getBitmap(); 610ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 611d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (contactInfo.photo == null) { 61283b20211c3be04a850de3674977deee8e448d17fEric Erfanian int width = (int) resources.getDimension(android.R.dimen.notification_large_icon_width); 61383b20211c3be04a850de3674977deee8e448d17fEric Erfanian int height = (int) resources.getDimension(android.R.dimen.notification_large_icon_height); 6142f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian @ContactType 6152f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian int contactType = 6162f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian LetterTileDrawable.getContactTypeFromPrimitives( 6172f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian CallerInfoUtils.isVoiceMailNumber(context, call), 6182f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian call.isSpam(), 6192f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian contactInfo.isBusiness, 6202f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian call.getNumberPresentation(), 6212f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian call.isConferenceCall() && !call.hasProperty(Details.PROPERTY_GENERIC_CONFERENCE)); 62283b20211c3be04a850de3674977deee8e448d17fEric Erfanian LetterTileDrawable lettertile = new LetterTileDrawable(resources); 623d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 624d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian lettertile.setCanonicalDialerLetterTileDetails( 625d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian contactInfo.namePrimary == null ? contactInfo.number : contactInfo.namePrimary, 626d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian contactInfo.lookupKey, 627d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LetterTileDrawable.SHAPE_CIRCLE, 628d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian contactType); 629d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian largeIcon = lettertile.getBitmap(width, height); 630d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } 631d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian 632ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.isSpam()) { 63383b20211c3be04a850de3674977deee8e448d17fEric Erfanian Drawable drawable = resources.getDrawable(R.drawable.blocked_contact, context.getTheme()); 634ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian largeIcon = DrawableConverter.drawableToBitmap(drawable); 635ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 636ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return largeIcon; 637ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 638ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 639ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Bitmap getRoundedIcon(Bitmap bitmap) { 640ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (bitmap == null) { 641ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return null; 642ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 643ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final int height = 644ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian (int) mContext.getResources().getDimension(android.R.dimen.notification_large_icon_height); 645ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final int width = 646ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian (int) mContext.getResources().getDimension(android.R.dimen.notification_large_icon_width); 647ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return BitmapUtil.getRoundedBitmap(bitmap, width, height); 648ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 649ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 650ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 651ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Returns the appropriate icon res Id to display based on the call for which we want to display 652ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * information. 653ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 654ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private int getIconToDisplay(DialerCall call) { 655ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Even if both lines are in use, we only show a single item in 656ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // the expanded Notifications UI. It's labeled "Ongoing call" 657ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // (or "On hold" if there's only one call, and it's on hold.) 658ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Also, we don't have room to display caller-id info from two 659ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // different calls. So if both lines are in use, display info 660ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // from the foreground call. And if there's a ringing call, 661ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // display that regardless of the state of the other calls. 662ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.getState() == DialerCall.State.ONHOLD) { 663ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return R.drawable.ic_phone_paused_white_24dp; 664d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } else if (call.getVideoTech().getSessionModificationState() 6659050823ccf6f512e06ad65c8a741cb17cbc4a833Eric Erfanian == SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { 666d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian return R.drawable.quantum_ic_videocam_white_24; 6679050823ccf6f512e06ad65c8a741cb17cbc4a833Eric Erfanian } else if (call.hasProperty(PROPERTY_HIGH_DEF_AUDIO) 6689050823ccf6f512e06ad65c8a741cb17cbc4a833Eric Erfanian && MotorolaUtils.shouldShowHdIconInNotification(mContext)) { 6692f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian // Normally when a call is ongoing the status bar displays an icon of a phone. This is a 6702f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian // helpful hint for users so they know how to get back to the call. For Sprint HD calls, we 6712f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian // replace this icon with an icon of a phone with a HD badge. This is a carrier requirement. 6729050823ccf6f512e06ad65c8a741cb17cbc4a833Eric Erfanian return R.drawable.ic_hd_call; 673ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 6742f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian // If ReturnToCall is enabled, use the static icon. The animated one will show in the bubble. 6752f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian if (ReturnToCallController.isEnabled(mContext)) { 6762f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian return R.drawable.quantum_ic_call_white_24; 6772f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian } else { 6782f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian return R.drawable.on_going_call; 6792f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian } 680ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 681ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 682ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Returns the message to use with the notification. */ 683ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private String getContentString(DialerCall call, @UserType long userType) { 684ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian boolean isIncomingOrWaiting = 685ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call.getState() == DialerCall.State.INCOMING 686ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian || call.getState() == DialerCall.State.CALL_WAITING; 687ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 688ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (isIncomingOrWaiting 689ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian && call.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED) { 690ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 691ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (!TextUtils.isEmpty(call.getChildNumber())) { 692ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return mContext.getString(R.string.child_number, call.getChildNumber()); 693ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (!TextUtils.isEmpty(call.getCallSubject()) && call.isCallSubjectSupported()) { 694ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return call.getCallSubject(); 695ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 696ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 697ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 698ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int resId = R.string.notification_ongoing_call; 699ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call.hasProperty(Details.PROPERTY_WIFI)) { 700ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_ongoing_call_wifi; 701ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 702ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 703ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (isIncomingOrWaiting) { 704d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (call.isSpam()) { 705d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.notification_incoming_spam_call; 7062f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian } else if (shouldShowEnrichedCallNotification(call.getEnrichedCallSession())) { 7072f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian resId = getECIncomingCallText(call.getEnrichedCallSession()); 708d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else if (call.hasProperty(Details.PROPERTY_WIFI)) { 709ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_incoming_call_wifi; 710ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else { 711d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.notification_incoming_call; 712ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 713ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (call.getState() == DialerCall.State.ONHOLD) { 714ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_on_hold; 715ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } else if (DialerCall.State.isDialing(call.getState())) { 716ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_dialing; 717d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian } else if (call.getVideoTech().getSessionModificationState() 7189050823ccf6f512e06ad65c8a741cb17cbc4a833Eric Erfanian == SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { 719ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = R.string.notification_requesting_video_call; 720ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 721ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 722ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Is the call placed through work connection service. 723ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian boolean isWorkCall = call.hasProperty(PROPERTY_ENTERPRISE_CALL); 724ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (userType == ContactsUtils.USER_TYPE_WORK || isWorkCall) { 725ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian resId = getWorkStringFromPersonalString(resId); 726ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 727ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 728ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return mContext.getString(resId); 729ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 730ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 7312f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian private boolean shouldShowEnrichedCallNotification(Session session) { 7322f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian if (session == null) { 7332f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian return false; 7342f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian } 7352f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian return session.getMultimediaData().hasData() || session.getMultimediaData().isImportant(); 7362f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian } 7372f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian 738d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian private int getECIncomingCallText(Session session) { 739d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian int resId; 740d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian MultimediaData data = session.getMultimediaData(); 741d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian boolean hasImage = data.hasImageData(); 742d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian boolean hasSubject = !TextUtils.isEmpty(data.getText()); 743d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian boolean hasMap = data.getLocation() != null; 744d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (data.isImportant()) { 745d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (hasMap) { 746d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (hasImage) { 747d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (hasSubject) { 748d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.important_notification_incoming_call_with_photo_message_location; 749d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else { 750d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.important_notification_incoming_call_with_photo_location; 751d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 752d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else if (hasSubject) { 753d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.important_notification_incoming_call_with_message_location; 754d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else { 755d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.important_notification_incoming_call_with_location; 756d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 757d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else if (hasImage) { 758d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (hasSubject) { 759d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.important_notification_incoming_call_with_photo_message; 760d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else { 761d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.important_notification_incoming_call_with_photo; 762d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 7632f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian } else if (hasSubject) { 764cded3beaf28a703e1ef8f71bbc6836e6806c3736Tobias Thierer resId = R.string.important_notification_incoming_call_with_message; 7652f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian } else { 7662f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian resId = R.string.important_notification_incoming_call; 767d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 768d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (mContext.getString(resId).length() > 50) { 769d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.important_notification_incoming_call_attachments; 770d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 771d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else { 772d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (hasMap) { 773d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (hasImage) { 774d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (hasSubject) { 775d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.notification_incoming_call_with_photo_message_location; 776d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else { 777d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.notification_incoming_call_with_photo_location; 778d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 779d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else if (hasSubject) { 780d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.notification_incoming_call_with_message_location; 781d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else { 782d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.notification_incoming_call_with_location; 783d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 784d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else if (hasImage) { 785d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (hasSubject) { 786d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.notification_incoming_call_with_photo_message; 787d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else { 788d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.notification_incoming_call_with_photo; 789d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 790d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } else { 791d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.notification_incoming_call_with_message; 792d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 793d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 794d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian if (mContext.getString(resId).length() > 50) { 795d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian resId = R.string.notification_incoming_call_attachments; 796d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 797d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian return resId; 798d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian } 799d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian 800ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Gets the most relevant call to display in the notification. */ 801ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private DialerCall getCallToShow(CallList callList) { 802ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (callList == null) { 803ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return null; 804ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 805ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian DialerCall call = callList.getIncomingCall(); 806ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call == null) { 807ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call = callList.getOutgoingCall(); 808ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 809ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call == null) { 810ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call = callList.getVideoUpgradeRequestCall(); 811ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 812ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (call == null) { 813ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian call = callList.getActiveOrBackgroundCall(); 814ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 815ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return call; 816ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 817ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 818ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Spannable getActionText(@StringRes int stringRes, @ColorRes int colorRes) { 819ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Spannable spannable = new SpannableString(mContext.getText(stringRes)); 820ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (VERSION.SDK_INT >= VERSION_CODES.N_MR1) { 821ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // This will only work for cases where the Notification.Builder has a fullscreen intent set 822ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Notification.Builder that does not have a full screen intent will take the color of the 823ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // app and the following leads to a no-op. 824ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian spannable.setSpan( 825ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian new ForegroundColorSpan(mContext.getColor(colorRes)), 0, spannable.length(), 0); 826ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 827ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return spannable; 828ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 829ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 830ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addAnswerAction(Notification.Builder builder) { 831d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.d( 832d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "StatusBarNotifier.addAnswerAction", 833d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "will show \"answer\" action in the incoming call Notification"); 834ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent answerVoicePendingIntent = 835ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_ANSWER_VOICE_INCOMING_CALL); 836ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 837d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian new Notification.Action.Builder( 8382f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian Icon.createWithResource(mContext, R.drawable.quantum_ic_call_white_24), 839d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian getActionText( 840d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian R.string.notification_action_answer, R.color.notification_action_accept), 841d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian answerVoicePendingIntent) 842d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian .build()); 843ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 844ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 845ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addDismissAction(Notification.Builder builder) { 846d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.d( 847d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "StatusBarNotifier.addDismissAction", 848d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "will show \"decline\" action in the incoming call Notification"); 849ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent declinePendingIntent = 850ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_DECLINE_INCOMING_CALL); 851ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 852d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian new Notification.Action.Builder( 853d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian Icon.createWithResource(mContext, R.drawable.quantum_ic_close_white_24), 854d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian getActionText( 855d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian R.string.notification_action_dismiss, R.color.notification_action_dismiss), 856d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian declinePendingIntent) 857d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian .build()); 858ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 859ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 860ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addHangupAction(Notification.Builder builder) { 861d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.d( 862d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "StatusBarNotifier.addHangupAction", 863d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "will show \"hang-up\" action in the ongoing active call Notification"); 864ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent hangupPendingIntent = 865ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_HANG_UP_ONGOING_CALL); 866ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 867d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian new Notification.Action.Builder( 868d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian Icon.createWithResource(mContext, R.drawable.ic_call_end_white_24dp), 86910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian mContext.getText(R.string.notification_action_end_call), 870d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian hangupPendingIntent) 871d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian .build()); 872ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 873ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 874ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addVideoCallAction(Notification.Builder builder) { 875d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.i( 876d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "StatusBarNotifier.addVideoCallAction", 877d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "will show \"video\" action in the incoming call Notification"); 878ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent answerVideoPendingIntent = 879ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_ANSWER_VIDEO_INCOMING_CALL); 880ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 881d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian new Notification.Action.Builder( 882d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian Icon.createWithResource(mContext, R.drawable.quantum_ic_videocam_white_24), 883d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian getActionText( 884d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian R.string.notification_action_answer_video, 885d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian R.color.notification_action_answer_video), 886d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian answerVideoPendingIntent) 887d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian .build()); 888ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 889ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 890ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addAcceptUpgradeRequestAction(Notification.Builder builder) { 891d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.i( 892d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "StatusBarNotifier.addAcceptUpgradeRequestAction", 893d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "will show \"accept upgrade\" action in the incoming call Notification"); 894ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent acceptVideoPendingIntent = 895ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST); 896ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 897d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian new Notification.Action.Builder( 898d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian Icon.createWithResource(mContext, R.drawable.quantum_ic_videocam_white_24), 899d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian getActionText( 900d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian R.string.notification_action_accept, R.color.notification_action_accept), 901d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian acceptVideoPendingIntent) 902d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian .build()); 903ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 904ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 905ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void addDismissUpgradeRequestAction(Notification.Builder builder) { 906d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.i( 907d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "StatusBarNotifier.addDismissUpgradeRequestAction", 908d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian "will show \"dismiss upgrade\" action in the incoming call Notification"); 909ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian PendingIntent declineVideoPendingIntent = 910ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian createNotificationPendingIntent(mContext, ACTION_DECLINE_VIDEO_UPGRADE_REQUEST); 911ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.addAction( 912d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian new Notification.Action.Builder( 913d8046e520a866b9948ee9ba47cf642b441ca8e23Eric Erfanian Icon.createWithResource(mContext, R.drawable.quantum_ic_videocam_white_24), 914d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian getActionText( 915d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian R.string.notification_action_dismiss, R.color.notification_action_dismiss), 916d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian declineVideoPendingIntent) 917d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian .build()); 918ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 919ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 920ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** Adds fullscreen intent to the builder. */ 92110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian private void configureFullScreenIntent(Notification.Builder builder, PendingIntent intent) { 922ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Ok, we actually want to launch the incoming call 923ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // UI at this point (in addition to simply posting a notification 924ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // to the status bar). Setting fullScreenIntent will cause 925ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // the InCallScreen to be launched immediately *unless* the 926ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // current foreground activity is marked as "immersive". 927d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian LogUtil.d("StatusBarNotifier.configureFullScreenIntent", "setting fullScreenIntent: " + intent); 928ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setFullScreenIntent(intent, true); 929ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 930ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 931ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private Notification.Builder getNotificationBuilder() { 932ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian final Notification.Builder builder = new Notification.Builder(mContext); 933ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian builder.setOngoing(true); 934d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian builder.setOnlyAlertOnce(true); 93510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian // This will be ignored on O+ and handled by the channel 9362f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian // noinspection deprecation 93710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian builder.setPriority(Notification.PRIORITY_HIGH); 938ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 939ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return builder; 940ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 941ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 942d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian private PendingIntent createLaunchPendingIntent(boolean isFullScreen) { 943ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian Intent intent = 944ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian InCallActivity.getIntent( 945d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian mContext, false /* showDialpad */, false /* newOutgoingCall */, isFullScreen); 946ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 947ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian int requestCode = PENDING_INTENT_REQUEST_CODE_NON_FULL_SCREEN; 948ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (isFullScreen) { 949ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // Use a unique request code so that the pending intent isn't clobbered by the 950ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // non-full screen pending intent. 951ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian requestCode = PENDING_INTENT_REQUEST_CODE_FULL_SCREEN; 952ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 953ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 954ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // PendingIntent that can be used to launch the InCallActivity. The 955ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // system fires off this intent if the user pulls down the windowshade 956ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // and clicks the notification's expanded view. It's also used to 957ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // launch the InCallActivity immediately when when there's an incoming 958ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian // call (see the "fullScreenIntent" field below). 959ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian return PendingIntent.getActivity(mContext, requestCode, intent, 0); 960ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 961ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 962ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private void setStatusBarCallListener(StatusBarCallListener listener) { 963ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (mStatusBarCallListener != null) { 964ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mStatusBarCallListener.cleanup(); 965ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 966ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mStatusBarCallListener = listener; 967ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 968ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 969ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private class StatusBarCallListener implements DialerCallListener { 970ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 971ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian private DialerCall mDialerCall; 972ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 973ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian StatusBarCallListener(DialerCall dialerCall) { 974ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerCall = dialerCall; 975ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerCall.addListener(this); 976ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 977ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 978ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian void cleanup() { 979ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerCall.removeListener(this); 980ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 981ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 982ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 983ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDialerCallDisconnect() {} 984ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 985ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 986ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDialerCallUpdate() { 987ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian if (CallList.getInstance().getIncomingCall() == null) { 988ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian mDialerRingtoneManager.stopCallWaitingTone(); 989ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 990ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 991ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 992ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 993ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDialerCallChildNumberChange() {} 994ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 995ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 996ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDialerCallLastForwardedNumberChange() {} 997ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 998ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 999ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onDialerCallUpgradeToVideo() {} 1000ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 1001ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 1002ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onWiFiToLteHandover() {} 1003ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 1004ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 1005ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian public void onHandoverToWifiFailure() {} 1006ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian 1007c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian @Override 1008c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian public void onInternationalCallOnWifi() {} 1009c857f90590e7d7fcffa89511982eb33afd34805fEric Erfanian 10102f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian @Override 10112f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian public void onEnrichedCallSessionUpdate() {} 10122f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian 1013ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian /** 1014ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * Responds to changes in the session modification state for the call by dismissing the status 1015ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian * bar notification as required. 1016ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian */ 1017ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian @Override 1018d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian public void onDialerCallSessionModificationStateChange() { 1019d5e47f6da5b08b13ecdfa7f1edc7e12aeb83fab9Eric Erfanian if (mDialerCall.getVideoTech().getSessionModificationState() 10209050823ccf6f512e06ad65c8a741cb17cbc4a833Eric Erfanian == SessionModificationState.NO_REQUEST) { 1021ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian cleanup(); 1022ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian updateNotification(CallList.getInstance()); 1023ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 1024ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 1025ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian } 1026ccca31529c07970e89419fb85a9e8153a5396838Eric Erfanian} 1027