Merge "Clean up listeners when view is destroyed." into klp-dev
diff --git a/InCallUI/res/layout/answer_fragment.xml b/InCallUI/res/layout/answer_fragment.xml
index 05e83de..d62a8d5 100644
--- a/InCallUI/res/layout/answer_fragment.xml
+++ b/InCallUI/res/layout/answer_fragment.xml
@@ -27,9 +27,9 @@
android:background="@android:color/black"
android:visibility="gone"
- dc:targetDrawables="@array/incoming_call_widget_2way_targets"
- dc:targetDescriptions="@array/incoming_call_widget_2way_target_descriptions"
- dc:directionDescriptions="@array/incoming_call_widget_2way_direction_descriptions"
+ dc:targetDrawables="@array/incoming_call_widget_3way_targets"
+ dc:targetDescriptions="@array/incoming_call_widget_3way_target_descriptions"
+ dc:directionDescriptions="@array/incoming_call_widget_3way_direction_descriptions"
dc:handleDrawable="@drawable/ic_in_call_touch_handle"
dc:outerRingDrawable="@*android:drawable/ic_lockscreen_outerring"
dc:outerRadius="@dimen/glowpadview_target_placement_radius"
diff --git a/InCallUI/src/com/android/incallui/AnswerFragment.java b/InCallUI/src/com/android/incallui/AnswerFragment.java
index 40462ce..2429dac 100644
--- a/InCallUI/src/com/android/incallui/AnswerFragment.java
+++ b/InCallUI/src/com/android/incallui/AnswerFragment.java
@@ -47,6 +47,8 @@
private ArrayAdapter<String> mTextResponsesAdapter = null;
+ private GlowPadWrapper mGlowpad;
+
public AnswerFragment() {
}
@@ -63,18 +65,12 @@
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- final GlowPadWrapper glowPad = (GlowPadWrapper) inflater.inflate(R.layout.answer_fragment,
+ mGlowpad = (GlowPadWrapper) inflater.inflate(R.layout.answer_fragment,
container, false);
- glowPad.setAnswerListener(this);
+ mGlowpad.setAnswerListener(this);
- return glowPad;
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- getPresenter().onUiUnready(this);
+ return mGlowpad;
}
@Override
@@ -84,7 +80,29 @@
@Override
public void showTextButton(boolean show) {
- // TODO(klp) Hide the text button when the call does not support reject by text.
+ final int targetResourceId = show
+ ? R.array.incoming_call_widget_3way_targets
+ : R.array.incoming_call_widget_2way_targets;
+
+ if (targetResourceId != mGlowpad.getTargetResourceId()) {
+ if (show) {
+ // Answer, Decline, and Respond via SMS.
+ mGlowpad.setTargetResources(targetResourceId);
+ mGlowpad.setTargetDescriptionsResourceId(
+ R.array.incoming_call_widget_3way_target_descriptions);
+ mGlowpad.setDirectionDescriptionsResourceId(
+ R.array.incoming_call_widget_3way_direction_descriptions);
+ } else {
+ // Answer or Decline.
+ mGlowpad.setTargetResources(targetResourceId);
+ mGlowpad.setTargetDescriptionsResourceId(
+ R.array.incoming_call_widget_2way_target_descriptions);
+ mGlowpad.setDirectionDescriptionsResourceId(
+ R.array.incoming_call_widget_2way_direction_descriptions);
+ }
+
+ mGlowpad.reset(false);
+ }
}
@Override
diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java
index 40b2a36..4c0f1d6 100644
--- a/InCallUI/src/com/android/incallui/AnswerPresenter.java
+++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java
@@ -85,7 +85,7 @@
call.getCallId());
getUi().showAnswerUi(true);
- if (textMsgs != null) {
+ if (call.can(Call.Capabilities.RESPOND_VIA_TEXT) && textMsgs != null) {
getUi().showTextButton(true);
getUi().configureMessageDialogue(textMsgs);
} else {
@@ -127,14 +127,13 @@
}
public void onText() {
- // No-op for now. b/10424370
- // getUi().showMessageDialogue();
+ getUi().showMessageDialogue();
}
public void rejectCallWithMessage(String message) {
Log.d(this, "sendTextToDefaultActivity()...");
- CallCommandClient.getInstance().rejectCall(mCallId, true, message);
getUi().dismissPopup();
+ CallCommandClient.getInstance().rejectCall(mCallId, true, message);
}
interface AnswerUi extends Ui {
diff --git a/InCallUI/src/com/android/incallui/AudioModeProvider.java b/InCallUI/src/com/android/incallui/AudioModeProvider.java
index 36ec20f..8224d3e 100644
--- a/InCallUI/src/com/android/incallui/AudioModeProvider.java
+++ b/InCallUI/src/com/android/incallui/AudioModeProvider.java
@@ -84,6 +84,10 @@
return mAudioMode;
}
+ public boolean getMute() {
+ return mMuted;
+ }
+
/* package */ interface AudioModeListener {
void onAudioMode(int newMode);
void onMute(boolean muted);
diff --git a/InCallUI/src/com/android/incallui/BaseFragment.java b/InCallUI/src/com/android/incallui/BaseFragment.java
index a348ce4..ae207f3 100644
--- a/InCallUI/src/com/android/incallui/BaseFragment.java
+++ b/InCallUI/src/com/android/incallui/BaseFragment.java
@@ -18,12 +18,9 @@
import android.app.Fragment;
import android.os.Bundle;
-import android.view.View;
-
-import com.android.internal.util.Preconditions;
/**
- *
+ * Parent for all fragments that use Presenters and Ui design.
*/
public abstract class BaseFragment<T extends Presenter<U>, U extends Ui> extends Fragment {
@@ -51,4 +48,10 @@
super.onActivityCreated(savedInstanceState);
mPresenter.onUiReady(getUi());
}
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ mPresenter.onUiUnready(getUi());
+ }
}
diff --git a/InCallUI/src/com/android/incallui/CallButtonFragment.java b/InCallUI/src/com/android/incallui/CallButtonFragment.java
index bd19381..1c3e737 100644
--- a/InCallUI/src/com/android/incallui/CallButtonFragment.java
+++ b/InCallUI/src/com/android/incallui/CallButtonFragment.java
@@ -127,12 +127,6 @@
}
@Override
- public void onDestroyView() {
- super.onDestroyView();
- getPresenter().onUiUnready(this);
- }
-
- @Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
}
diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
index 6e64e65..bc9efe5 100644
--- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java
@@ -32,6 +32,8 @@
private Call mCall;
private AudioModeProvider mAudioModeProvider;
private ProximitySensor mProximitySensor;
+ private boolean mAutomaticallyMuted = false;
+ private boolean mPreviousMuteState = false;
public CallButtonPresenter() {
}
@@ -166,6 +168,11 @@
}
public void addCallClicked() {
+ // Automatically mute the current call
+ mAutomaticallyMuted = true;
+ mPreviousMuteState = mAudioModeProvider.getMute();
+ getUi().setMute(true);
+
CallCommandClient.getInstance().addCall();
}
@@ -204,6 +211,12 @@
ui.showMerge(call.can(Capabilities.MERGE_CALLS));
ui.showSwap(call.can(Capabilities.SWAP_CALLS));
ui.showAddCall(call.can(Capabilities.ADD_CALL));
+
+ // Restore the previous mute state
+ if (mAutomaticallyMuted && mAudioModeProvider.getMute() != mPreviousMuteState) {
+ ui.setMute(mPreviousMuteState);
+ mAutomaticallyMuted = false;
+ }
}
}
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java
index d880b97..6009036 100644
--- a/InCallUI/src/com/android/incallui/CallCardFragment.java
+++ b/InCallUI/src/com/android/incallui/CallCardFragment.java
@@ -111,12 +111,6 @@
}
@Override
- public void onDestroyView() {
- super.onDestroyView();
- getPresenter().onUiUnready(this);
- }
-
- @Override
public void setVisible(boolean on) {
if (on) {
getView().setVisibility(View.VISIBLE);
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index 59e846b..a0ad3ce 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -74,6 +74,8 @@
// Call may be null if disconnect happened already.
if (call != null) {
+ mPrimary = call;
+
final CallIdentification identification = call.getIdentification();
// TODO(klp): Logic to determine which ui field get what data resides in
@@ -241,7 +243,7 @@
// 1) a lookup occurred but failed to find a local contact.
// 2) a lookup has not occurred.
// We need to track it so we can avoid an un-necessary lookup here.
- Log.d(TAG, "Local contact cache does not contain the contact. Searching provider.");
+ Log.d(TAG, "Contact lookup. In memory cache miss. Searching provider.");
cache.findInfo(identification, isIncoming, new ContactInfoCacheCallback() {
@Override
public void onContactInfoComplete(int callId, ContactCacheEntry entry) {
@@ -250,16 +252,16 @@
// Need to do massaging outside of contactinfocache.
if (entry.label == null) {
// Name not found. Try lookup.
- Log.d(TAG, "Local contact not found, performing reverse lookup.");
+ Log.d(TAG, "Contact lookup. Contact provider miss. Searching people api.");
lookupPhoneNumber(identification.getNumber());
} else {
- Log.d(TAG, "Found contact in provider: " + entry);
+ Log.d(TAG, "Contact lookup. Found in contact provider: " + entry);
updateContactEntry(entry, isPrimary, isConference);
}
}
});
} else {
- Log.d(TAG, "Found contact in cache: " + entry);
+ Log.d(TAG, "Contact lookup. Found in memory cache: " + entry);
updateContactEntry(entry, isPrimary, isConference);
}
}
diff --git a/InCallUI/src/com/android/incallui/ContactInfoCache.java b/InCallUI/src/com/android/incallui/ContactInfoCache.java
index 1895989..0796794 100644
--- a/InCallUI/src/com/android/incallui/ContactInfoCache.java
+++ b/InCallUI/src/com/android/incallui/ContactInfoCache.java
@@ -36,14 +36,12 @@
import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
- * Class responsible for querying Contact Information for Call objects.
- * Can perform asynchronous requests to the Contact Provider for information as well
- * as respond synchronously for any data that it currently has cached from previous
- * queries.
- * This class always gets called from the UI thread so it does not need thread protection.
+ * Class responsible for querying Contact Information for Call objects. Can perform asynchronous
+ * requests to the Contact Provider for information as well as respond synchronously for any data
+ * that it currently has cached from previous queries. This class always gets called from the UI
+ * thread so it does not need thread protection.
*/
public class ContactInfoCache implements ContactsAsyncHelper.OnImageLoadCompleteListener {
@@ -52,7 +50,9 @@
private final Context mContext;
private final HashMap<Integer, ContactCacheEntry> mInfoMap = Maps.newHashMap();
- private final HashMap<Integer, List<ContactInfoCacheCallback>> mCallBacks = Maps.newHashMap();
+ private final HashMap<Integer, List<ContactInfoCacheCallback>> mCallBacksGuarded = Maps
+ .newHashMap();
+ private final Object mCallBackLock = new Object();
private static ContactInfoCache sCache = null;
@@ -95,46 +95,48 @@
Preconditions.checkState(Looper.getMainLooper().getThread() == Thread.currentThread());
Preconditions.checkNotNull(callback);
- // TODO(klp): We dont need to make this call if the call Id already exists in mInfoMap.
final int callId = identification.getCallId();
// If the entry already exists, add callback
- List<ContactInfoCacheCallback> callBacks = mCallBacks.get(callId);
- if (callBacks == null) {
-
- // New lookup
- callBacks = Lists.newArrayList();
- callBacks.add(callback);
- mCallBacks.put(callId, callBacks);
-
- /**
- * 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
- * emergency call information, will not perform an additional asynchronous query.
- */
- CallerInfoUtils.getCallerInfoForCall(mContext, identification,
- new CallerInfoAsyncQuery.OnQueryCompleteListener() {
- @Override
- public void onQueryComplete(int token, Object cookie, CallerInfo ci) {
- int presentationMode = identification.getNumberPresentation();
- if (ci.contactExists || ci.isEmergencyNumber() || ci
- .isVoiceMailNumber()) {
- presentationMode = Call.PRESENTATION_ALLOWED;
- }
-
- // This starts the photo load.
- final ContactCacheEntry cacheEntry = buildEntry(mContext,
- identification.getCallId(), ci, presentationMode, isIncoming,
- ContactInfoCache.this);
-
- // Add the contact info to the cache.
- mInfoMap.put(callId, cacheEntry);
- sendNotification(identification.getCallId(), cacheEntry);
- }
- });
- } else {
- callBacks.add(callback);
+ List<ContactInfoCacheCallback> callBacks;
+ synchronized (mCallBackLock) {
+ callBacks = mCallBacksGuarded.get(callId);
+ if (callBacks != null) {
+ callBacks.add(callback);
+ return;
+ } else {
+ // New lookup
+ callBacks = Lists.newArrayList();
+ callBacks.add(callback);
+ mCallBacksGuarded.put(callId, callBacks);
+ }
}
+
+ /**
+ * 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
+ * emergency call information, will not perform an additional asynchronous query.
+ */
+ CallerInfoUtils.getCallerInfoForCall(mContext, identification,
+ new CallerInfoAsyncQuery.OnQueryCompleteListener() {
+ @Override
+ public void onQueryComplete(int token, Object cookie, CallerInfo ci) {
+ int presentationMode = identification.getNumberPresentation();
+ if (ci.contactExists || ci.isEmergencyNumber() || ci.isVoiceMailNumber()) {
+ presentationMode = Call.PRESENTATION_ALLOWED;
+ }
+
+ // This starts the photo load.
+ final ContactCacheEntry cacheEntry = buildEntry(mContext,
+ identification.getCallId(), ci, presentationMode, isIncoming,
+ ContactInfoCache.this);
+
+ // Add the contact info to the cache.
+ mInfoMap.put(callId, cacheEntry);
+ sendNotification(identification.getCallId(), cacheEntry);
+ }
+ });
+
}
/**
@@ -179,8 +181,10 @@
* Blows away the stored cache values.
*/
public void clearCache() {
- mInfoMap.clear();
- mCallBacks.clear();
+ synchronized (mCallBackLock) {
+ mInfoMap.clear();
+ mCallBacksGuarded.clear();
+ }
}
private static ContactCacheEntry buildEntry(Context context, int callId,
@@ -338,7 +342,12 @@
* Sends the updated information to call the callbacks for the entry.
*/
private void sendNotification(int callId, ContactCacheEntry entry) {
- List<ContactInfoCacheCallback> callBacks = mCallBacks.get(callId);
+ final List<ContactInfoCacheCallback> callBacks;
+ synchronized (mCallBackLock) {
+ callBacks = mCallBacksGuarded.get(callId);
+ // Do not clear mInfoMap here because we still need the data.
+ mCallBacksGuarded.clear();
+ }
if (callBacks != null) {
for (ContactInfoCacheCallback callBack : callBacks) {
callBack.onContactInfoComplete(callId, entry);