diff options
6 files changed, 112 insertions, 31 deletions
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java index 6caf0089c..552a42a61 100644 --- a/InCallUI/src/com/android/incallui/CallCardFragment.java +++ b/InCallUI/src/com/android/incallui/CallCardFragment.java @@ -95,12 +95,6 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter> } @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - getPresenter().setContext(activity); - } - - @Override public void setPrimary(String number, String name, String label, Drawable photo) { boolean nameIsNumber = false; @@ -197,8 +191,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter> private void setDrawableToImageView(ImageView view, Drawable photo) { if (photo == null) { - mPhoto.setVisibility(View.INVISIBLE); - return; + photo = view.getResources().getDrawable(R.drawable.picture_unknown); } final Drawable current = view.getDrawable(); diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java index 105e3482a..8a855c104 100644 --- a/InCallUI/src/com/android/incallui/CallCardPresenter.java +++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java @@ -35,7 +35,6 @@ import com.android.services.telephony.common.Call; public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> implements InCallStateListener, AudioModeListener, ContactInfoCacheCallback { - private Context mContext; private AudioModeProvider mAudioModeProvider; private ContactInfoCache mContactInfoCache; private Call mPrimary; @@ -67,9 +66,8 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> mSecondaryContactInfo = null; } - public void setContext(Context context) { - mContext = context; - mContactInfoCache = new ContactInfoCache(mContext); + public void setContactInfoCache(ContactInfoCache cache) { + mContactInfoCache = cache; startContactInfoSearch(); } diff --git a/InCallUI/src/com/android/incallui/ContactInfoCache.java b/InCallUI/src/com/android/incallui/ContactInfoCache.java index 6cbe060ac..c5a4cf551 100644 --- a/InCallUI/src/com/android/incallui/ContactInfoCache.java +++ b/InCallUI/src/com/android/incallui/ContactInfoCache.java @@ -144,13 +144,20 @@ public class ContactInfoCache implements CallerInfoAsyncQuery.OnQueryCompleteLis entry.info.photo = new BitmapDrawable(mContext.getResources(), photoIcon); } else { Logger.v(this, "unknown photo"); - entry.info.photo = mContext.getResources().getDrawable(R.drawable.picture_unknown); + entry.info.photo = null; } sendNotification(entry); } /** + * Blows away the stored cache values. + */ + public void clearCache() { + mInfoMap.clear(); + } + + /** * Performs a query for caller information. * Save any immediate data we get from the query. An asynchronous query may also be made * for any data that we do not already have. Some queries, such as those for voicemail and diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java index c76f08ad0..e1a979693 100644 --- a/InCallUI/src/com/android/incallui/InCallActivity.java +++ b/InCallUI/src/com/android/incallui/InCallActivity.java @@ -287,6 +287,8 @@ public class InCallActivity extends Activity { mainPresenter.getAudioModeProvider()); mCallCardFragment.getPresenter().setAudioModeProvider( mainPresenter.getAudioModeProvider()); + mCallCardFragment.getPresenter().setContactInfoCache( + mainPresenter.getContactInfoCache()); mainPresenter.addListener(mCallButtonFragment.getPresenter()); mainPresenter.addListener(mCallCardFragment.getPresenter()); diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java index 25c2447dd..3ae4d3aaf 100644 --- a/InCallUI/src/com/android/incallui/InCallPresenter.java +++ b/InCallUI/src/com/android/incallui/InCallPresenter.java @@ -43,6 +43,7 @@ public class InCallPresenter implements CallList.Listener { private AudioModeProvider mAudioModeProvider; private StatusBarNotifier mStatusBarNotifier; + private ContactInfoCache mContactInfoCache; private Context mContext; private CallList mCallList; private InCallActivity mInCallActivity; @@ -63,7 +64,9 @@ public class InCallPresenter implements CallList.Listener { mCallList = callList; mCallList.addListener(this); - mStatusBarNotifier = new StatusBarNotifier(context); + mContactInfoCache = new ContactInfoCache(context); + + mStatusBarNotifier = new StatusBarNotifier(context, mContactInfoCache, mCallList); addListener(mStatusBarNotifier); mAudioModeProvider = audioModeProvider; @@ -148,6 +151,10 @@ public class InCallPresenter implements CallList.Listener { return mAudioModeProvider; } + public ContactInfoCache getContactInfoCache() { + return mContactInfoCache; + } + /** * Hangs up any active or outgoing calls. */ @@ -244,6 +251,10 @@ public class InCallPresenter implements CallList.Listener { mInCallActivity = null; temp.finish(); + + // blow away stale contact info so that we get fresh data on + // the next set of calls + mContactInfoCache.clearCache(); } } diff --git a/InCallUI/src/com/android/incallui/StatusBarNotifier.java b/InCallUI/src/com/android/incallui/StatusBarNotifier.java index ff3c47b16..e2dc42ca8 100644 --- a/InCallUI/src/com/android/incallui/StatusBarNotifier.java +++ b/InCallUI/src/com/android/incallui/StatusBarNotifier.java @@ -23,7 +23,13 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import com.android.incallui.ContactInfoCache.ContactCacheEntry; +import com.android.incallui.ContactInfoCache.ContactInfoCacheCallback; import com.android.incallui.InCallApp.NotificationBroadcastReceiver; import com.android.incallui.InCallPresenter.InCallState; import com.android.services.telephony.common.Call; @@ -31,21 +37,29 @@ import com.android.services.telephony.common.Call; /** * This class adds Notifications to the status bar for the in-call experience. */ -public class StatusBarNotifier implements InCallPresenter.InCallStateListener { +public class StatusBarNotifier implements InCallPresenter.InCallStateListener, + ContactInfoCacheCallback { // notification types private static final int IN_CALL_NOTIFICATION = 1; private final Context mContext; + private final ContactInfoCache mContactInfoCache; + private final CallList mCallList; private final NotificationManager mNotificationManager; private boolean mIsShowingNotification = false; private InCallState mInCallState = InCallState.HIDDEN; private int mSavedIcon = 0; private int mSavedContent = 0; + private Bitmap mSavedLargeIcon; + private String mSavedContentTitle; - public StatusBarNotifier(Context context) { + public StatusBarNotifier(Context context, ContactInfoCache contactInfoCache, + CallList callList) { Preconditions.checkNotNull(context); mContext = context; + mContactInfoCache = contactInfoCache; + mCallList = callList; mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); } @@ -59,6 +73,14 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { } /** + * Called after the Contact Info query has finished. + */ + @Override + public void onContactInfoComplete(int callId, ContactCacheEntry entry) { + updateNotification(mInCallState, mCallList); + } + + /** * Updates the phone app's status bar notification based on the * current telephony state, or cancels the notification if the phone * is totally idle. @@ -134,8 +156,8 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { * Watch out: This should be set to true *only* when directly * handling a new incoming call for the first time. */ - private void updateInCallNotification(boolean allowFullScreenIntent, InCallState state, - CallList callList) { + private void updateInCallNotification(final boolean allowFullScreenIntent, + final InCallState state, CallList callList) { Logger.d(this, "updateInCallNotification(allowFullScreenIntent = " + allowFullScreenIntent + ")..."); @@ -144,30 +166,42 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { return; } - buildAndSendNotification(state, callList, allowFullScreenIntent); + final Call call = getCallToShow(callList); + if (call == null) { + Logger.wtf(this, "No call for the notification!"); + } + + // 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, new ContactInfoCacheCallback() { + @Override + public void onContactInfoComplete(int callId, ContactCacheEntry entry) { + buildAndSendNotification(state, call, entry, allowFullScreenIntent); + } + }); } /** * Sets up the main Ui for the notification */ - private void buildAndSendNotification(InCallState state, CallList callList, - boolean allowFullScreenIntent) { - - final Call call = getCallToShow(callList); - if (call == null) { - Logger.wtf(this, "No call for the notification!"); - } + private void buildAndSendNotification(InCallState state, Call call, + ContactCacheEntry contactInfo, boolean allowFullScreenIntent) { final int iconResId = getIconToDisplay(call); + final Bitmap largeIcon = getLargeIconToDisplay(contactInfo); final int contentResId = getContentString(call); + final String contentTitle = getContentTitle(contactInfo); // If we checked and found that nothing is different, dont issue another notification. - if (!checkForChangeAndSaveData(iconResId, contentResId, state, allowFullScreenIntent)) { + if (!checkForChangeAndSaveData(iconResId, contentResId, largeIcon, contentTitle, state, + allowFullScreenIntent)) { return; } - /* * Nothing more to check...build and send it. */ @@ -185,6 +219,8 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { // set the content builder.setContentText(mContext.getString(contentResId)); builder.setSmallIcon(iconResId); + builder.setContentTitle(contentTitle); + builder.setLargeIcon(largeIcon); // Add special Content for calls that are ongoing if (InCallState.INCALL == state || InCallState.OUTGOING == state) { @@ -205,10 +241,20 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { * 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, int content, InCallState state, - boolean showFullScreenIntent) { + private boolean checkForChangeAndSaveData(int icon, int content, Bitmap largeIcon, + String contentTitle, InCallState state, boolean showFullScreenIntent) { + + // 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) || (mSavedContent != content) || - (mInCallState == state); + (mInCallState != state) || (mSavedLargeIcon != largeIcon) || + contentTitleChanged; // A full screen intent means that we have been asked to interrupt an activity, // so we definitely want to show it. @@ -226,6 +272,8 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { mSavedIcon = icon; mSavedContent = content; mInCallState = state; + mSavedLargeIcon = largeIcon; + mSavedContentTitle = contentTitle; if (retval) { Logger.d(this, "Data changed. Showing notification"); @@ -235,6 +283,28 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { } /** + * Returns the main string to use in the notification. + */ + private String getContentTitle(ContactCacheEntry contactInfo) { + if (TextUtils.isEmpty(contactInfo.name)) { + return contactInfo.number; + } + + return contactInfo.name; + } + + /** + * Gets a large icon from the contact info object to display in the notification. + */ + private Bitmap getLargeIconToDisplay(ContactCacheEntry contactInfo) { + if (contactInfo.photo != null && (contactInfo.photo instanceof BitmapDrawable)) { + return ((BitmapDrawable) contactInfo.photo).getBitmap(); + } + + return null; + } + + /** * Returns the appropriate icon res Id to display based on the call for which * we want to display information. */ |