summaryrefslogtreecommitdiff
path: root/InCallUI/src/com/android/incallui/StatusBarNotifier.java
diff options
context:
space:
mode:
Diffstat (limited to 'InCallUI/src/com/android/incallui/StatusBarNotifier.java')
-rw-r--r--InCallUI/src/com/android/incallui/StatusBarNotifier.java793
1 files changed, 0 insertions, 793 deletions
diff --git a/InCallUI/src/com/android/incallui/StatusBarNotifier.java b/InCallUI/src/com/android/incallui/StatusBarNotifier.java
deleted file mode 100644
index cc87dd414..000000000
--- a/InCallUI/src/com/android/incallui/StatusBarNotifier.java
+++ /dev/null
@@ -1,793 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.incallui;
-
-import static com.android.contacts.common.compat.CallSdkCompat.Details.PROPERTY_ENTERPRISE_CALL;
-import static com.android.incallui.NotificationBroadcastReceiver.ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST;
-import static com.android.incallui.NotificationBroadcastReceiver.ACTION_ANSWER_VIDEO_INCOMING_CALL;
-import static com.android.incallui.NotificationBroadcastReceiver.ACTION_ANSWER_VOICE_INCOMING_CALL;
-import static com.android.incallui.NotificationBroadcastReceiver.ACTION_DECLINE_INCOMING_CALL;
-import static com.android.incallui.NotificationBroadcastReceiver.ACTION_DECLINE_VIDEO_UPGRADE_REQUEST;
-import static com.android.incallui.NotificationBroadcastReceiver.ACTION_HANG_UP_ONGOING_CALL;
-
-import com.google.common.base.Preconditions;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.media.AudioAttributes;
-import android.net.Uri;
-import android.provider.ContactsContract.Contacts;
-import android.support.annotation.Nullable;
-import android.telecom.Call.Details;
-import android.telecom.PhoneAccount;
-import android.telecom.TelecomManager;
-import android.text.BidiFormatter;
-import android.text.TextDirectionHeuristics;
-import android.text.TextUtils;
-
-import com.android.contacts.common.ContactsUtils;
-import com.android.contacts.common.ContactsUtils.UserType;
-import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.contacts.common.testing.NeededForTesting;
-import com.android.contacts.common.util.BitmapUtil;
-import com.android.contacts.common.util.ContactDisplayUtils;
-import com.android.dialer.R;
-import com.android.dialer.service.ExtendedCallInfoService;
-import com.android.incallui.ContactInfoCache.ContactCacheEntry;
-import com.android.incallui.ContactInfoCache.ContactInfoCacheCallback;
-import com.android.incallui.InCallPresenter.InCallState;
-import com.android.incallui.async.PausableExecutorImpl;
-import com.android.incallui.ringtone.DialerRingtoneManager;
-import com.android.incallui.ringtone.InCallTonePlayer;
-import com.android.incallui.ringtone.ToneGeneratorFactory;
-
-import java.util.Objects;
-
-/**
- * This class adds Notifications to the status bar for the in-call experience.
- */
-public class StatusBarNotifier implements InCallPresenter.InCallStateListener,
- CallList.CallUpdateListener {
-
- // Notification types
- // Indicates that no notification is currently showing.
- private static final int NOTIFICATION_NONE = 0;
- // Notification for an active call. This is non-interruptive, but cannot be dismissed.
- private static final int NOTIFICATION_IN_CALL = 1;
- // Notification for incoming calls. This is interruptive and will show up as a HUN.
- private static final int NOTIFICATION_INCOMING_CALL = 2;
-
- private static final int PENDING_INTENT_REQUEST_CODE_NON_FULL_SCREEN = 0;
- private static final int PENDING_INTENT_REQUEST_CODE_FULL_SCREEN = 1;
-
- private static final long[] VIBRATE_PATTERN = new long[] {0, 1000, 1000};
-
- private final Context mContext;
- @Nullable private ContactsPreferences mContactsPreferences;
- private final ContactInfoCache mContactInfoCache;
- private final NotificationManager mNotificationManager;
- private final DialerRingtoneManager mDialerRingtoneManager;
- private int mCurrentNotification = NOTIFICATION_NONE;
- private int mCallState = Call.State.INVALID;
- private int mSavedIcon = 0;
- private String mSavedContent = null;
- private Bitmap mSavedLargeIcon;
- private String mSavedContentTitle;
- private String mCallId = null;
- private InCallState mInCallState;
- private Uri mRingtone;
-
- public StatusBarNotifier(Context context, ContactInfoCache contactInfoCache) {
- Preconditions.checkNotNull(context);
- mContext = context;
- mContactsPreferences = ContactsPreferencesFactory.newContactsPreferences(mContext);
- mContactInfoCache = contactInfoCache;
- mNotificationManager =
- (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- mDialerRingtoneManager = new DialerRingtoneManager(
- new InCallTonePlayer(new ToneGeneratorFactory(), new PausableExecutorImpl()),
- CallList.getInstance());
- mCurrentNotification = NOTIFICATION_NONE;
- }
-
- /**
- * Creates notifications according to the state we receive from {@link InCallPresenter}.
- */
- @Override
- public void onStateChange(InCallState oldState, InCallState newState, CallList callList) {
- Log.d(this, "onStateChange");
- mInCallState = newState;
- updateNotification(newState, callList);
- }
-
- /**
- * Updates the phone app's status bar notification *and* launches the
- * incoming call UI in response to a new incoming call.
- *
- * If an incoming call is ringing (or call-waiting), the notification
- * will also include a "fullScreenIntent" that will cause the
- * InCallScreen to be launched, unless the current foreground activity
- * is marked as "immersive".
- *
- * (This is the mechanism that actually brings up the incoming call UI
- * when we receive a "new ringing connection" event from the telephony
- * layer.)
- *
- * Also note that this method is safe to call even if the phone isn't
- * actually ringing (or, more likely, if an incoming call *was*
- * ringing briefly but then disconnected). In that case, we'll simply
- * update or cancel the in-call notification based on the current
- * phone state.
- *
- * @see #updateInCallNotification(InCallState,CallList)
- */
- public void updateNotification(InCallState state, CallList callList) {
- updateInCallNotification(state, callList);
- }
-
- /**
- * Take down the in-call notification.
- * @see #updateInCallNotification(InCallState,CallList)
- */
- private void cancelNotification() {
- if (!TextUtils.isEmpty(mCallId)) {
- CallList.getInstance().removeCallUpdateListener(mCallId, this);
- mCallId = null;
- }
- if (mCurrentNotification != NOTIFICATION_NONE) {
- Log.d(this, "cancelInCall()...");
- mNotificationManager.cancel(mCurrentNotification);
- }
- mCurrentNotification = NOTIFICATION_NONE;
- }
-
- /**
- * Should only be called from a irrecoverable state where it is necessary to dismiss all
- * notifications.
- */
- static void clearAllCallNotifications(Context backupContext) {
- Log.i(StatusBarNotifier.class.getSimpleName(),
- "Something terrible happened. Clear all InCall notifications");
-
- NotificationManager notificationManager =
- (NotificationManager) backupContext.getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.cancel(NOTIFICATION_IN_CALL);
- notificationManager.cancel(NOTIFICATION_INCOMING_CALL);
- }
-
- /**
- * Helper method for updateInCallNotification() and
- * updateNotification(): Update the phone app's
- * status bar notification based on the current telephony state, or
- * cancels the notification if the phone is totally idle.
- */
- private void updateInCallNotification(final InCallState state, CallList callList) {
- Log.d(this, "updateInCallNotification...");
-
- final Call call = getCallToShow(callList);
-
- if (call != null) {
- showNotification(call);
- } else {
- cancelNotification();
- }
- }
-
- private void showNotification(final Call call) {
- final boolean isIncoming = (call.getState() == Call.State.INCOMING ||
- call.getState() == Call.State.CALL_WAITING);
- if (!TextUtils.isEmpty(mCallId)) {
- CallList.getInstance().removeCallUpdateListener(mCallId, this);
- }
- mCallId = call.getId();
- CallList.getInstance().addCallUpdateListener(call.getId(), this);
-
- // we make a call to the contact info cache to query for supplemental data to what the
- // call provides. This includes the contact name and photo.
- // This callback will always get called immediately and synchronously with whatever data
- // it has available, and may make a subsequent call later (same thread) if it had to
- // call into the contacts provider for more data.
- mContactInfoCache.findInfo(call, isIncoming, new ContactInfoCacheCallback() {
- @Override
- public void onContactInfoComplete(String callId, ContactCacheEntry entry) {
- Call call = CallList.getInstance().getCallById(callId);
- if (call != null) {
- call.getLogState().contactLookupResult = entry.contactLookupResult;
- buildAndSendNotification(call, entry);
- }
- }
-
- @Override
- public void onImageLoadComplete(String callId, ContactCacheEntry entry) {
- Call call = CallList.getInstance().getCallById(callId);
- if (call != null) {
- buildAndSendNotification(call, entry);
- }
- }
-
- @Override
- public void onContactInteractionsInfoComplete(String callId, ContactCacheEntry entry) {}
- });
- }
-
- /**
- * Sets up the main Ui for the notification
- */
- private void buildAndSendNotification(Call originalCall, ContactCacheEntry contactInfo) {
- // This can get called to update an existing notification after contact information has come
- // back. However, it can happen much later. Before we continue, we need to make sure that
- // the call being passed in is still the one we want to show in the notification.
- final Call call = getCallToShow(CallList.getInstance());
- if (call == null || !call.getId().equals(originalCall.getId())) {
- return;
- }
-
- final int callState = call.getState();
- // Dont' show as spam if the number is in local contact.
- if (contactInfo.contactLookupResult == Call.LogState.LOOKUP_LOCAL_CONTACT) {
- call.setSpam(false);
- }
-
- // Check if data has changed; if nothing is different, don't issue another notification.
- final int iconResId = getIconToDisplay(call);
- Bitmap largeIcon = getLargeIconToDisplay(contactInfo, call);
- final String content =
- getContentString(call, contactInfo.userType);
- final String contentTitle = getContentTitle(contactInfo, call);
-
- final boolean isVideoUpgradeRequest = call.getSessionModificationState()
- == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST;
- final int notificationType;
- if (callState == Call.State.INCOMING || callState == Call.State.CALL_WAITING
- || isVideoUpgradeRequest) {
- notificationType = NOTIFICATION_INCOMING_CALL;
- } else {
- notificationType = NOTIFICATION_IN_CALL;
- }
-
- if (!checkForChangeAndSaveData(iconResId, content, largeIcon, contentTitle, callState,
- notificationType, contactInfo.contactRingtoneUri)) {
- return;
- }
-
- if (largeIcon != null) {
- largeIcon = getRoundedIcon(largeIcon);
- }
-
- /*
- * This builder is used for the notification shown when the device is locked and the user
- * has set their notification settings to 'hide sensitive content'
- * {@see Notification.Builder#setPublicVersion}.
- */
- Notification.Builder publicBuilder = new Notification.Builder(mContext);
- publicBuilder.setSmallIcon(iconResId)
- .setColor(mContext.getResources().getColor(R.color.dialer_theme_color))
- // Hide work call state for the lock screen notification
- .setContentTitle(getContentString(call, ContactsUtils.USER_TYPE_CURRENT));
- setNotificationWhen(call, callState, publicBuilder);
-
- /*
- * Builder for the notification shown when the device is unlocked or the user has set their
- * notification settings to 'show all notification content'.
- */
- final Notification.Builder builder = getNotificationBuilder();
- builder.setPublicVersion(publicBuilder.build());
-
- // Set up the main intent to send the user to the in-call screen
- builder.setContentIntent(createLaunchPendingIntent(false /* isFullScreen */));
-
- // Set the intent as a full screen intent as well if a call is incoming
- if (notificationType == NOTIFICATION_INCOMING_CALL
- && !InCallPresenter.getInstance().isShowingInCallUi()) {
- configureFullScreenIntent(
- builder, createLaunchPendingIntent(true /* isFullScreen */), call);
- // Set the notification category for incoming calls
- builder.setCategory(Notification.CATEGORY_CALL);
- }
-
- // Set the content
- builder.setContentText(content);
- builder.setSmallIcon(iconResId);
- builder.setContentTitle(contentTitle);
- builder.setLargeIcon(largeIcon);
- builder.setColor(mContext.getResources().getColor(R.color.dialer_theme_color));
-
- if (isVideoUpgradeRequest) {
- builder.setUsesChronometer(false);
- addDismissUpgradeRequestAction(builder);
- addAcceptUpgradeRequestAction(builder);
- } else {
- createIncomingCallNotification(call, callState, builder);
- }
-
- addPersonReference(builder, contactInfo, call);
-
- /*
- * Fire off the notification
- */
- Notification notification = builder.build();
-
- if (mDialerRingtoneManager.shouldPlayRingtone(callState, contactInfo.contactRingtoneUri)) {
- notification.flags |= Notification.FLAG_INSISTENT;
- notification.sound = contactInfo.contactRingtoneUri;
- AudioAttributes.Builder audioAttributes = new AudioAttributes.Builder();
- audioAttributes.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC);
- audioAttributes.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE);
- notification.audioAttributes = audioAttributes.build();
- if (mDialerRingtoneManager.shouldVibrate(mContext.getContentResolver())) {
- notification.vibrate = VIBRATE_PATTERN;
- }
- }
- if (mDialerRingtoneManager.shouldPlayCallWaitingTone(callState)) {
- Log.v(this, "Playing call waiting tone");
- mDialerRingtoneManager.playCallWaitingTone();
- }
- if (mCurrentNotification != notificationType && mCurrentNotification != NOTIFICATION_NONE) {
- Log.i(this, "Previous notification already showing - cancelling "
- + mCurrentNotification);
- mNotificationManager.cancel(mCurrentNotification);
- }
-
- Log.i(this, "Displaying notification for " + notificationType);
- mNotificationManager.notify(notificationType, notification);
- call.getLatencyReport().onNotificationShown();
- mCurrentNotification = notificationType;
- }
-
- private void createIncomingCallNotification(
- Call call, int state, Notification.Builder builder) {
- setNotificationWhen(call, state, builder);
-
- // Add hang up option for any active calls (active | onhold), outgoing calls (dialing).
- if (state == Call.State.ACTIVE ||
- state == Call.State.ONHOLD ||
- Call.State.isDialing(state)) {
- addHangupAction(builder);
- } else if (state == Call.State.INCOMING || state == Call.State.CALL_WAITING) {
- addDismissAction(builder);
- if (call.isVideoCall(mContext)) {
- addVoiceAction(builder);
- addVideoCallAction(builder);
- } else {
- addAnswerAction(builder);
- }
- }
- }
-
- /*
- * Sets the notification's when section as needed. For active calls, this is explicitly set as
- * the duration of the call. For all other states, the notification will automatically show the
- * time at which the notification was created.
- */
- private void setNotificationWhen(Call call, int state, Notification.Builder builder) {
- if (state == Call.State.ACTIVE) {
- builder.setUsesChronometer(true);
- builder.setWhen(call.getConnectTimeMillis());
- } else {
- builder.setUsesChronometer(false);
- }
- }
-
- /**
- * Checks the new notification data and compares it against any notification that we
- * are already displaying. If the data is exactly the same, we return false so that
- * we do not issue a new notification for the exact same data.
- */
- private boolean checkForChangeAndSaveData(int icon, String content, Bitmap largeIcon,
- String contentTitle, int state, int notificationType, Uri ringtone) {
-
- // The two are different:
- // if new title is not null, it should be different from saved version OR
- // if new title is null, the saved version should not be null
- final boolean contentTitleChanged =
- (contentTitle != null && !contentTitle.equals(mSavedContentTitle)) ||
- (contentTitle == null && mSavedContentTitle != null);
-
- // any change means we are definitely updating
- boolean retval = (mSavedIcon != icon) || !Objects.equals(mSavedContent, content)
- || (mCallState != state) || (mSavedLargeIcon != largeIcon)
- || contentTitleChanged || !Objects.equals(mRingtone, ringtone);
-
- // If we aren't showing a notification right now or the notification type is changing,
- // definitely do an update.
- if (mCurrentNotification != notificationType) {
- if (mCurrentNotification == NOTIFICATION_NONE) {
- Log.d(this, "Showing notification for first time.");
- }
- retval = true;
- }
-
- mSavedIcon = icon;
- mSavedContent = content;
- mCallState = state;
- mSavedLargeIcon = largeIcon;
- mSavedContentTitle = contentTitle;
- mRingtone = ringtone;
-
- if (retval) {
- Log.d(this, "Data changed. Showing notification");
- }
-
- return retval;
- }
-
- /**
- * Returns the main string to use in the notification.
- */
- @NeededForTesting
- String getContentTitle(ContactCacheEntry contactInfo, Call call) {
- if (call.isConferenceCall() && !call.hasProperty(Details.PROPERTY_GENERIC_CONFERENCE)) {
- return mContext.getResources().getString(R.string.card_title_conf_call);
- }
-
- String preferredName = ContactDisplayUtils.getPreferredDisplayName(contactInfo.namePrimary,
- contactInfo.nameAlternative, mContactsPreferences);
- if (TextUtils.isEmpty(preferredName)) {
- return TextUtils.isEmpty(contactInfo.number) ? null : BidiFormatter.getInstance()
- .unicodeWrap(contactInfo.number, TextDirectionHeuristics.LTR);
- }
- return preferredName;
- }
-
- private void addPersonReference(Notification.Builder builder, ContactCacheEntry contactInfo,
- Call call) {
- // Query {@link Contacts#CONTENT_LOOKUP_URI} directly with work lookup key is not allowed.
- // So, do not pass {@link Contacts#CONTENT_LOOKUP_URI} to NotificationManager to avoid
- // NotificationManager using it.
- if (contactInfo.lookupUri != null && contactInfo.userType != ContactsUtils.USER_TYPE_WORK) {
- builder.addPerson(contactInfo.lookupUri.toString());
- } else if (!TextUtils.isEmpty(call.getNumber())) {
- builder.addPerson(Uri.fromParts(PhoneAccount.SCHEME_TEL,
- call.getNumber(), null).toString());
- }
- }
-
- /**
- * Gets a large icon from the contact info object to display in the notification.
- */
- private Bitmap getLargeIconToDisplay(ContactCacheEntry contactInfo, Call call) {
- Bitmap largeIcon = null;
- if (call.isConferenceCall() && !call.hasProperty(Details.PROPERTY_GENERIC_CONFERENCE)) {
- largeIcon = BitmapFactory.decodeResource(mContext.getResources(),
- R.drawable.img_conference);
- }
- if (contactInfo.photo != null && (contactInfo.photo instanceof BitmapDrawable)) {
- largeIcon = ((BitmapDrawable) contactInfo.photo).getBitmap();
- }
- if (call.isSpam()) {
- Drawable drawable = mContext.getResources().getDrawable(R.drawable.blocked_contact);
- largeIcon = CallCardFragment.drawableToBitmap(drawable);
- }
- return largeIcon;
- }
-
- private Bitmap getRoundedIcon(Bitmap bitmap) {
- if (bitmap == null) {
- return null;
- }
- final int height = (int) mContext.getResources().getDimension(
- android.R.dimen.notification_large_icon_height);
- final int width = (int) mContext.getResources().getDimension(
- android.R.dimen.notification_large_icon_width);
- return BitmapUtil.getRoundedBitmap(bitmap, width, height);
- }
-
- /**
- * Returns the appropriate icon res Id to display based on the call for which
- * we want to display information.
- */
- private int getIconToDisplay(Call call) {
- // Even if both lines are in use, we only show a single item in
- // the expanded Notifications UI. It's labeled "Ongoing call"
- // (or "On hold" if there's only one call, and it's on hold.)
- // Also, we don't have room to display caller-id info from two
- // different calls. So if both lines are in use, display info
- // from the foreground call. And if there's a ringing call,
- // display that regardless of the state of the other calls.
- if (call.getState() == Call.State.ONHOLD) {
- return R.drawable.ic_phone_paused_white_24dp;
- } else if (call.getSessionModificationState()
- == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) {
- return R.drawable.ic_videocam;
- }
- return R.drawable.ic_call_white_24dp;
- }
-
- /**
- * Returns the message to use with the notification.
- */
- private String getContentString(Call call, @UserType long userType) {
- boolean isIncomingOrWaiting = call.getState() == Call.State.INCOMING ||
- call.getState() == Call.State.CALL_WAITING;
-
- if (isIncomingOrWaiting &&
- call.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED) {
-
- if (!TextUtils.isEmpty(call.getChildNumber())) {
- return mContext.getString(R.string.child_number, call.getChildNumber());
- } else if (!TextUtils.isEmpty(call.getCallSubject()) && call.isCallSubjectSupported()) {
- return call.getCallSubject();
- }
- }
-
- int resId = R.string.notification_ongoing_call;
- if (call.hasProperty(Details.PROPERTY_WIFI)) {
- resId = R.string.notification_ongoing_call_wifi;
- }
-
- if (isIncomingOrWaiting) {
- if (call.hasProperty(Details.PROPERTY_WIFI)) {
- resId = R.string.notification_incoming_call_wifi;
- } else {
- if (call.isSpam()) {
- resId = R.string.notification_incoming_spam_call;
- } else {
- resId = R.string.notification_incoming_call;
- }
- }
- } else if (call.getState() == Call.State.ONHOLD) {
- resId = R.string.notification_on_hold;
- } else if (Call.State.isDialing(call.getState())) {
- resId = R.string.notification_dialing;
- } else if (call.getSessionModificationState()
- == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) {
- resId = R.string.notification_requesting_video_call;
- }
-
- // Is the call placed through work connection service.
- boolean isWorkCall = call.hasProperty(PROPERTY_ENTERPRISE_CALL);
- if(userType == ContactsUtils.USER_TYPE_WORK || isWorkCall) {
- resId = getWorkStringFromPersonalString(resId);
- }
-
- return mContext.getString(resId);
- }
-
- private static int getWorkStringFromPersonalString(int resId) {
- if (resId == R.string.notification_ongoing_call) {
- return R.string.notification_ongoing_work_call;
- } else if (resId == R.string.notification_ongoing_call_wifi) {
- return R.string.notification_ongoing_work_call_wifi;
- } else if (resId == R.string.notification_incoming_call_wifi) {
- return R.string.notification_incoming_work_call_wifi;
- } else if (resId == R.string.notification_incoming_call) {
- return R.string.notification_incoming_work_call;
- } else {
- return resId;
- }
- }
-
- /**
- * Gets the most relevant call to display in the notification.
- */
- private Call getCallToShow(CallList callList) {
- if (callList == null) {
- return null;
- }
- Call call = callList.getIncomingCall();
- if (call == null) {
- call = callList.getOutgoingCall();
- }
- if (call == null) {
- call = callList.getVideoUpgradeRequestCall();
- }
- if (call == null) {
- call = callList.getActiveOrBackgroundCall();
- }
- return call;
- }
-
- private void addAnswerAction(Notification.Builder builder) {
- Log.d(this, "Will show \"answer\" action in the incoming call Notification");
-
- PendingIntent answerVoicePendingIntent = createNotificationPendingIntent(
- mContext, ACTION_ANSWER_VOICE_INCOMING_CALL);
- builder.addAction(R.drawable.ic_call_white_24dp,
- mContext.getText(R.string.notification_action_answer),
- answerVoicePendingIntent);
- }
-
- private void addDismissAction(Notification.Builder builder) {
- Log.d(this, "Will show \"dismiss\" action in the incoming call Notification");
-
- PendingIntent declinePendingIntent =
- createNotificationPendingIntent(mContext, ACTION_DECLINE_INCOMING_CALL);
- builder.addAction(R.drawable.ic_close_dk,
- mContext.getText(R.string.notification_action_dismiss),
- declinePendingIntent);
- }
-
- private void addHangupAction(Notification.Builder builder) {
- Log.d(this, "Will show \"hang-up\" action in the ongoing active call Notification");
-
- PendingIntent hangupPendingIntent =
- createNotificationPendingIntent(mContext, ACTION_HANG_UP_ONGOING_CALL);
- builder.addAction(R.drawable.ic_call_end_white_24dp,
- mContext.getText(R.string.notification_action_end_call),
- hangupPendingIntent);
- }
-
- private void addVideoCallAction(Notification.Builder builder) {
- Log.i(this, "Will show \"video\" action in the incoming call Notification");
-
- PendingIntent answerVideoPendingIntent = createNotificationPendingIntent(
- mContext, ACTION_ANSWER_VIDEO_INCOMING_CALL);
- builder.addAction(R.drawable.ic_videocam,
- mContext.getText(R.string.notification_action_answer_video),
- answerVideoPendingIntent);
- }
-
- private void addVoiceAction(Notification.Builder builder) {
- Log.d(this, "Will show \"voice\" action in the incoming call Notification");
-
- PendingIntent answerVoicePendingIntent = createNotificationPendingIntent(
- mContext, ACTION_ANSWER_VOICE_INCOMING_CALL);
- builder.addAction(R.drawable.ic_call_white_24dp,
- mContext.getText(R.string.notification_action_answer_voice),
- answerVoicePendingIntent);
- }
-
- private void addAcceptUpgradeRequestAction(Notification.Builder builder) {
- Log.i(this, "Will show \"accept upgrade\" action in the incoming call Notification");
-
- PendingIntent acceptVideoPendingIntent = createNotificationPendingIntent(
- mContext, ACTION_ACCEPT_VIDEO_UPGRADE_REQUEST);
- builder.addAction(0, mContext.getText(R.string.notification_action_accept),
- acceptVideoPendingIntent);
- }
-
- private void addDismissUpgradeRequestAction(Notification.Builder builder) {
- Log.i(this, "Will show \"dismiss upgrade\" action in the incoming call Notification");
-
- PendingIntent declineVideoPendingIntent = createNotificationPendingIntent(
- mContext, ACTION_DECLINE_VIDEO_UPGRADE_REQUEST);
- builder.addAction(0, mContext.getText(R.string.notification_action_dismiss),
- declineVideoPendingIntent);
- }
-
- /**
- * Adds fullscreen intent to the builder.
- */
- private void configureFullScreenIntent(Notification.Builder builder, PendingIntent intent,
- Call call) {
- // Ok, we actually want to launch the incoming call
- // UI at this point (in addition to simply posting a notification
- // to the status bar). Setting fullScreenIntent will cause
- // the InCallScreen to be launched immediately *unless* the
- // current foreground activity is marked as "immersive".
- Log.d(this, "- Setting fullScreenIntent: " + intent);
- builder.setFullScreenIntent(intent, true);
-
- // Ugly hack alert:
- //
- // The NotificationManager has the (undocumented) behavior
- // that it will *ignore* the fullScreenIntent field if you
- // post a new Notification that matches the ID of one that's
- // already active. Unfortunately this is exactly what happens
- // when you get an incoming call-waiting call: the
- // "ongoing call" notification is already visible, so the
- // InCallScreen won't get launched in this case!
- // (The result: if you bail out of the in-call UI while on a
- // call and then get a call-waiting call, the incoming call UI
- // won't come up automatically.)
- //
- // The workaround is to just notice this exact case (this is a
- // call-waiting call *and* the InCallScreen is not in the
- // foreground) and manually cancel the in-call notification
- // before (re)posting it.
- //
- // TODO: there should be a cleaner way of avoiding this
- // problem (see discussion in bug 3184149.)
-
- // If a call is onhold during an incoming call, the call actually comes in as
- // INCOMING. For that case *and* traditional call-waiting, we want to
- // cancel the notification.
- boolean isCallWaiting = (call.getState() == Call.State.CALL_WAITING ||
- (call.getState() == Call.State.INCOMING &&
- CallList.getInstance().getBackgroundCall() != null));
-
- if (isCallWaiting) {
- Log.i(this, "updateInCallNotification: call-waiting! force relaunch...");
- // Cancel the IN_CALL_NOTIFICATION immediately before
- // (re)posting it; this seems to force the
- // NotificationManager to launch the fullScreenIntent.
- mNotificationManager.cancel(NOTIFICATION_IN_CALL);
- }
- }
-
- private Notification.Builder getNotificationBuilder() {
- final Notification.Builder builder = new Notification.Builder(mContext);
- builder.setOngoing(true);
-
- // Make the notification prioritized over the other normal notifications.
- builder.setPriority(Notification.PRIORITY_HIGH);
-
- return builder;
- }
-
- private PendingIntent createLaunchPendingIntent(boolean isFullScreen) {
- Intent intent = InCallPresenter.getInstance().getInCallIntent(
- false /* showDialpad */, false /* newOutgoingCall */);
-
- int requestCode = PENDING_INTENT_REQUEST_CODE_NON_FULL_SCREEN;
- if (isFullScreen) {
- intent.putExtra(InCallActivity.FOR_FULL_SCREEN_INTENT, true);
- // Use a unique request code so that the pending intent isn't clobbered by the
- // non-full screen pending intent.
- requestCode = PENDING_INTENT_REQUEST_CODE_FULL_SCREEN;
- }
-
- // PendingIntent that can be used to launch the InCallActivity. The
- // system fires off this intent if the user pulls down the windowshade
- // and clicks the notification's expanded view. It's also used to
- // launch the InCallActivity immediately when when there's an incoming
- // call (see the "fullScreenIntent" field below).
- return PendingIntent.getActivity(mContext, requestCode, intent, 0);
- }
-
- /**
- * Returns PendingIntent for answering a phone call. This will typically be used from
- * Notification context.
- */
- private static PendingIntent createNotificationPendingIntent(Context context, String action) {
- final Intent intent = new Intent(action, null,
- context, NotificationBroadcastReceiver.class);
- return PendingIntent.getBroadcast(context, 0, intent, 0);
- }
-
- @Override
- public void onCallChanged(Call call) {
- if (CallList.getInstance().getIncomingCall() == null) {
- mDialerRingtoneManager.stopCallWaitingTone();
- }
- }
-
- /**
- * Responds to changes in the session modification state for the call by dismissing the
- * status bar notification as required.
- *
- * @param sessionModificationState The new session modification state.
- */
- @Override
- public void onSessionModificationStateChange(int sessionModificationState) {
- if (sessionModificationState == Call.SessionModificationState.NO_REQUEST) {
- if (mCallId != null) {
- CallList.getInstance().removeCallUpdateListener(mCallId, this);
- }
-
- updateNotification(mInCallState, CallList.getInstance());
- }
- }
-
- @Override
- public void onLastForwardedNumberChange() {
- // no-op
- }
-
- @Override
- public void onChildNumberChange() {
- // no-op
- }
-}