summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChiao Cheng <chiaocheng@google.com>2013-08-16 15:45:35 -0700
committerChiao Cheng <chiaocheng@google.com>2013-08-20 16:13:55 -0700
commit033ed5926d2924d35b9c82898ab4e835da56b3af (patch)
tree202bb41ce24bca496fcc88dad57e1a8614dc1eb8
parentd28fc12696fa706fed70e04698275af7be7fee82 (diff)
Adding interfaces for phone number service.
- Fetch image url if present. Bug: 10359919 Change-Id: Idf2ff5405255f1e90a383902762585ae68249dbe
-rw-r--r--InCallUI/AndroidManifest.xml1
-rw-r--r--InCallUI/src/com/android/incallui/AnswerFragment.java10
-rw-r--r--InCallUI/src/com/android/incallui/BaseFragment.java25
-rw-r--r--InCallUI/src/com/android/incallui/CallButtonFragment.java18
-rw-r--r--InCallUI/src/com/android/incallui/CallCardFragment.java34
-rw-r--r--InCallUI/src/com/android/incallui/CallCardPresenter.java79
-rw-r--r--InCallUI/src/com/android/incallui/DialpadFragment.java8
-rw-r--r--InCallUI/src/com/android/incallui/service/PhoneNumberService.java40
-rw-r--r--InCallUI/src/com/android/incallui/util/HttpFetcher.java111
-rw-r--r--InCallUI/src/com/android/incalluibind/ServiceFactory.java32
10 files changed, 335 insertions, 23 deletions
diff --git a/InCallUI/AndroidManifest.xml b/InCallUI/AndroidManifest.xml
index 0b603e0b3..3196dba60 100644
--- a/InCallUI/AndroidManifest.xml
+++ b/InCallUI/AndroidManifest.xml
@@ -22,6 +22,7 @@
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.VIBRATE"/>
+ <uses-permission android:name="android.permission.INTERNET" />
<application
android:name="InCallApp"
diff --git a/InCallUI/src/com/android/incallui/AnswerFragment.java b/InCallUI/src/com/android/incallui/AnswerFragment.java
index d1a1df0a6..aea80eced 100644
--- a/InCallUI/src/com/android/incallui/AnswerFragment.java
+++ b/InCallUI/src/com/android/incallui/AnswerFragment.java
@@ -33,8 +33,8 @@ import java.util.ArrayList;
/**
*
*/
-public class AnswerFragment extends BaseFragment<AnswerPresenter> implements
- GlowPadWrapper.AnswerListener, AnswerPresenter.AnswerUi {
+public class AnswerFragment extends BaseFragment<AnswerPresenter, AnswerPresenter.AnswerUi>
+ implements GlowPadWrapper.AnswerListener, AnswerPresenter.AnswerUi {
/**
* The popup showing the list of canned responses.
@@ -57,13 +57,17 @@ public class AnswerFragment extends BaseFragment<AnswerPresenter> implements
}
@Override
+ AnswerPresenter.AnswerUi getUi() {
+ return this;
+ }
+
+ @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final GlowPadWrapper glowPad = (GlowPadWrapper) inflater.inflate(R.layout.answer_fragment,
container, false);
glowPad.setAnswerListener(this);
- getPresenter().onUiReady(this);
return glowPad;
}
diff --git a/InCallUI/src/com/android/incallui/BaseFragment.java b/InCallUI/src/com/android/incallui/BaseFragment.java
index a88f8407c..0f3d6b4ae 100644
--- a/InCallUI/src/com/android/incallui/BaseFragment.java
+++ b/InCallUI/src/com/android/incallui/BaseFragment.java
@@ -17,21 +17,38 @@
package com.android.incallui;
import android.app.Fragment;
+import android.os.Bundle;
+import android.view.View;
+
+import com.android.internal.util.Preconditions;
/**
*
*/
-public abstract class BaseFragment<T extends Presenter> extends Fragment {
+public abstract class BaseFragment<T extends Presenter<U>, U extends Ui> extends Fragment {
private T mPresenter;
+ abstract T createPresenter();
+
+ abstract U getUi();
+
protected BaseFragment() {
- this.mPresenter = createPresenter();
+ mPresenter = createPresenter();
}
- abstract T createPresenter();
-
+ /**
+ * Presenter will be available after onActivityCreated().
+ *
+ * @return The presenter associated with this fragment.
+ */
public T getPresenter() {
return mPresenter;
}
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mPresenter.onUiReady(getUi());
+ }
}
diff --git a/InCallUI/src/com/android/incallui/CallButtonFragment.java b/InCallUI/src/com/android/incallui/CallButtonFragment.java
index 21bfb1cf5..15d044684 100644
--- a/InCallUI/src/com/android/incallui/CallButtonFragment.java
+++ b/InCallUI/src/com/android/incallui/CallButtonFragment.java
@@ -16,9 +16,7 @@
package com.android.incallui;
-import android.content.Context;
import android.graphics.drawable.LayerDrawable;
-import android.media.AudioManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -37,9 +35,10 @@ import com.android.services.telephony.common.AudioMode;
/**
* Fragment for call control buttons
*/
-public class CallButtonFragment extends BaseFragment<CallButtonPresenter>
- implements CallButtonPresenter.CallButtonUi, OnMenuItemClickListener,
- OnDismissListener, View.OnClickListener, CompoundButton.OnCheckedChangeListener {
+public class CallButtonFragment
+ extends BaseFragment<CallButtonPresenter, CallButtonPresenter.CallButtonUi>
+ implements CallButtonPresenter.CallButtonUi, OnMenuItemClickListener, OnDismissListener,
+ View.OnClickListener, CompoundButton.OnCheckedChangeListener {
private ToggleButton mMuteButton;
private ToggleButton mAudioButton;
@@ -61,6 +60,11 @@ public class CallButtonFragment extends BaseFragment<CallButtonPresenter>
}
@Override
+ CallButtonPresenter.CallButtonUi getUi() {
+ return this;
+ }
+
+ @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@@ -115,8 +119,8 @@ public class CallButtonFragment extends BaseFragment<CallButtonPresenter>
}
@Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- getPresenter().onUiReady(this);
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
// set the buttons
updateAudioButtons(getPresenter().getSupportedAudio());
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java
index 18b51d9f8..347743845 100644
--- a/InCallUI/src/com/android/incallui/CallCardFragment.java
+++ b/InCallUI/src/com/android/incallui/CallCardFragment.java
@@ -31,12 +31,13 @@ import android.view.ViewStub;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.incalluibind.ServiceFactory;
import com.android.services.telephony.common.Call;
/**
* Fragment for call card.
*/
-public class CallCardFragment extends BaseFragment<CallCardPresenter>
+public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPresenter.CallCardUi>
implements CallCardPresenter.CallCardUi {
// Primary caller info
@@ -56,21 +57,36 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
private float mDensity;
@Override
+ CallCardPresenter.CallCardUi getUi() {
+ return this;
+ }
+
+ @Override
CallCardPresenter createPresenter() {
return new CallCardPresenter();
}
@Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getPresenter().init(ServiceFactory.newPhoneNumberService(getActivity()));
+ }
+
+ @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+
mDensity = getResources().getDisplayMetrics().density;
return inflater.inflate(R.layout.call_card, container, false);
}
-
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
mPhoneNumber = (TextView) view.findViewById(R.id.phoneNumber);
mName = (TextView) view.findViewById(R.id.name);
mNumberLabel = (TextView) view.findViewById(R.id.label);
@@ -78,10 +94,6 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
mPhoto = (ImageView) view.findViewById(R.id.photo);
mCallStateLabel = (TextView) view.findViewById(R.id.callStateLabel);
mElapsedTime = (TextView) view.findViewById(R.id.elapsedTime);
-
- // This method call will begin the callbacks on CallCardUi. We need to ensure
- // everything needed for the callbacks is set up before this is called.
- getPresenter().onUiReady(this);
}
@Override
@@ -100,6 +112,16 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter>
}
@Override
+ public void setName(String name) {
+ mName.setText(name);
+ }
+
+ @Override
+ public void setImage(Bitmap image) {
+ setDrawableToImageView(mPhoto, new BitmapDrawable(getResources(), image));
+ }
+
+ @Override
public void setPrimary(String number, String name, boolean nameIsNumber, String label,
Drawable photo, boolean isConference) {
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index bf27a1bb7..7eec3fb65 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -17,6 +17,14 @@
package com.android.incallui;
import android.graphics.drawable.Drawable;
+import android.content.ContentUris;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.provider.ContactsContract.Contacts;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -25,20 +33,27 @@ import com.android.incallui.ContactInfoCache.ContactCacheEntry;
import com.android.incallui.ContactInfoCache.ContactInfoCacheCallback;
import com.android.incallui.InCallPresenter.InCallState;
import com.android.incallui.InCallPresenter.InCallStateListener;
-
+import com.android.incallui.service.PhoneNumberService;
+import com.android.incallui.util.HttpFetcher;
+import com.android.incalluibind.ServiceFactory;
import com.android.services.telephony.common.AudioMode;
import com.android.services.telephony.common.Call;
import com.android.services.telephony.common.Call.DisconnectCause;
+import java.io.IOException;
+
/**
* Presenter for the Call Card Fragment.
+ * <p>
* This class listens for changes to InCallState and passes it along to the fragment.
*/
public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
implements InCallStateListener, AudioModeListener, ContactInfoCacheCallback {
+ private static final String TAG = CallCardPresenter.class.getSimpleName();
private static final long CALL_TIME_UPDATE_INTERVAL = 1000; // in milliseconds
+ private PhoneNumberService mPhoneNumberService;
private AudioModeProvider mAudioModeProvider;
private ContactInfoCache mContactInfoCache;
private Call mPrimary;
@@ -58,6 +73,10 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
});
}
+ public void init(PhoneNumberService phoneNumberService) {
+ mPhoneNumberService = phoneNumberService;
+ }
+
@Override
public void onUiReady(CallCardUi ui) {
super.onUiReady(ui);
@@ -81,6 +100,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
@Override
public void onStateChange(InCallState state, CallList callList) {
+ Logger.d(TAG, "onStateChange()");
final CallCardUi ui = getUi();
if (ui == null) {
return;
@@ -233,10 +253,12 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
if (mPrimary != null && mPrimary.getCallId() == callId) {
mPrimaryContactInfo = entry;
updatePrimaryDisplayInfo();
+ lookupPhoneNumber(mPrimary.getNumber());
}
if (mSecondary != null && mSecondary.getCallId() == callId) {
mSecondaryContactInfo = entry;
updateSecondaryDisplayInfo();
+ // TODO(klp): investigate reverse lookup for secondary call.
}
}
@@ -260,6 +282,59 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
}
+ public void lookupPhoneNumber(String phoneNumber) {
+ if (mPhoneNumberService != null) {
+ mPhoneNumberService.getPhoneNumberInfo(phoneNumber,
+ new PhoneNumberService.PhoneNumberServiceListener() {
+ @Override
+ public void onPhoneNumberInfoComplete(
+ final PhoneNumberService.PhoneNumberInfo info) {
+ if (info == null) {
+ return;
+ }
+ // TODO(klp): Ui is sometimes null due to something being shutdown.
+ if (getUi() != null) {
+ if (info.getName() != null) {
+ getUi().setName(info.getName());
+ }
+
+ if (info.getImageUrl() != null) {
+ fetchImage(info.getImageUrl());
+ }
+ }
+ }
+ });
+ }
+ }
+
+ private void fetchImage(final String url) {
+ if (url != null) {
+ new AsyncTask<Void, Void, Bitmap>() {
+
+ @Override
+ protected Bitmap doInBackground(Void... params) {
+ // Fetch the image
+ try {
+ final byte[] image = HttpFetcher.getRequestAsByteArray(url);
+ return BitmapFactory.decodeByteArray(image, 0, image.length);
+ } catch (IOException e) {
+ Logger.e(TAG, "Unable to download/decode photo.", e);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ // TODO(klp): same as above, figure out why it's null.
+ if (getUi() != null) {
+ getUi().setImage(bitmap);
+ }
+ }
+
+ }.execute();
+ }
+ }
+
/**
* Gets the name to display for the call.
*/
@@ -310,5 +385,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
void setSecondary(boolean show, String name, String label, Drawable photo);
void setCallState(int state, Call.DisconnectCause cause, boolean bluetoothOn);
void setPrimaryCallElapsedTime(boolean show, String duration);
+ void setName(String name);
+ void setImage(Bitmap bitmap);
}
}
diff --git a/InCallUI/src/com/android/incallui/DialpadFragment.java b/InCallUI/src/com/android/incallui/DialpadFragment.java
index 6be923cfb..b996e4f15 100644
--- a/InCallUI/src/com/android/incallui/DialpadFragment.java
+++ b/InCallUI/src/com/android/incallui/DialpadFragment.java
@@ -31,7 +31,7 @@ import java.util.HashMap;
/**
* Fragment for call control buttons
*/
-public class DialpadFragment extends BaseFragment<DialpadPresenter>
+public class DialpadFragment extends BaseFragment<DialpadPresenter, DialpadPresenter.DialpadUi>
implements DialpadPresenter.DialpadUi, View.OnTouchListener, View.OnKeyListener,
View.OnHoverListener, View.OnClickListener {
@@ -164,6 +164,11 @@ public class DialpadFragment extends BaseFragment<DialpadPresenter>
}
@Override
+ DialpadPresenter.DialpadUi getUi() {
+ return this;
+ }
+
+ @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@@ -181,7 +186,6 @@ public class DialpadFragment extends BaseFragment<DialpadPresenter>
setupKeypad(parent);
}
- getPresenter().onUiReady(this);
return parent;
}
diff --git a/InCallUI/src/com/android/incallui/service/PhoneNumberService.java b/InCallUI/src/com/android/incallui/service/PhoneNumberService.java
new file mode 100644
index 000000000..1e0cb950a
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/service/PhoneNumberService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.service;
+
+/**
+ *
+ */
+public interface PhoneNumberService {
+ public void getPhoneNumberInfo(String phoneNumber, PhoneNumberServiceListener listener);
+
+ public interface PhoneNumberServiceListener {
+
+ /**
+ * Callback when a phone number has been looked up.
+ *
+ * @param info The looked up information. Or (@literal null} if there are no results.
+ */
+ public void onPhoneNumberInfoComplete(PhoneNumberInfo info);
+ }
+
+ public interface PhoneNumberInfo {
+ public String getName();
+ public String getPhoneNumber();
+ public String getImageUrl();
+ }
+}
diff --git a/InCallUI/src/com/android/incallui/util/HttpFetcher.java b/InCallUI/src/com/android/incallui/util/HttpFetcher.java
new file mode 100644
index 000000000..b54bf718f
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/util/HttpFetcher.java
@@ -0,0 +1,111 @@
+/*
+ * 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.util;
+
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.google.common.io.Closeables;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+/**
+ * Utility for making http requests.
+ */
+public class HttpFetcher {
+
+ private static final String TAG = HttpFetcher.class.getSimpleName();
+
+ /**
+ * Send a http request to the given url.
+ *
+ * @param urlString The url to request.
+ * @return The response body as a byte array. Or {@literal null} if status code is not 2xx.
+ * @throws java.io.IOException when an error occurs.
+ */
+ public static byte[] getRequestAsByteArray(String urlString) throws IOException {
+ Log.d(TAG, "fetching " + urlString);
+ HttpURLConnection conn = null;
+ InputStream is = null;
+ boolean isError = false;
+ final long start = SystemClock.uptimeMillis();
+ try {
+ final URL url = new URL(urlString);
+ conn = (HttpURLConnection) url.openConnection();
+ Log.d(TAG, "response code: " + conn.getResponseCode());
+ // All 2xx codes are successful.
+ if (conn.getResponseCode() / 100 == 2) {
+ is = conn.getInputStream();
+ } else {
+ is = conn.getErrorStream();
+ isError = true;
+ }
+
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final byte[] buffer = new byte[1024];
+ int bytesRead;
+
+ while ((bytesRead = is.read(buffer)) != -1) {
+ baos.write(buffer, 0, bytesRead);
+ }
+
+ if (isError) {
+ handleBadResponse(urlString, baos.toByteArray());
+ return null;
+ }
+
+ final byte[] response = baos.toByteArray();
+ Log.d(TAG, "received " + response.length + " bytes");
+ final long end = SystemClock.uptimeMillis();
+ Log.d(TAG, "fetch took " + (end - start) + " ms");
+ return response;
+ } finally {
+ Closeables.closeQuietly(is);
+ if (conn != null) {
+ conn.disconnect();
+ }
+ }
+ }
+
+ /**
+ * Send a http request to the given url.
+ *
+ * @param urlString The url to request.
+ * @return The response body as a String. Or {@literal null} if status code is not 2xx.
+ * @throws java.io.IOException when an error occurs.
+ */
+ public static String getRequestAsString(String urlString) throws IOException {
+ final byte[] byteArr = getRequestAsByteArray(urlString);
+ if (byteArr == null) {
+ // Encountered error response... just return.
+ return null;
+ }
+ final String response = new String(byteArr);
+ Log.d(TAG, "response body: ");
+ Log.d(TAG, response);
+ return response;
+ }
+
+ private static void handleBadResponse(String url, byte[] response) {
+ Log.w(TAG, "Got bad response code from url: " + url);
+ Log.w(TAG, new String(response));
+ }
+}
diff --git a/InCallUI/src/com/android/incalluibind/ServiceFactory.java b/InCallUI/src/com/android/incalluibind/ServiceFactory.java
new file mode 100644
index 000000000..7191f146b
--- /dev/null
+++ b/InCallUI/src/com/android/incalluibind/ServiceFactory.java
@@ -0,0 +1,32 @@
+/*
+ * 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.incalluibind;
+
+import android.content.Context;
+
+import com.android.incallui.service.PhoneNumberService;
+
+/**
+ * Default static binder for services.
+ */
+public class ServiceFactory {
+
+ public static PhoneNumberService newPhoneNumberService(Context context) {
+ // no phone number service.
+ return null;
+ }
+}