Initial support for contact picture retrieving

Search for
- custom im 'sip' from username@domain;
- then android sip from username@domain;
- then number from username
This commit is contained in:
Guillaume Beraudo 2011-10-03 16:33:59 +02:00
parent 362e154a6e
commit b3f7a20857
15 changed files with 233 additions and 29 deletions

View file

@ -61,7 +61,8 @@
</intent-filter>
</activity>
<activity android:name="org.linphone.ConferenceActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 812 B

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

@ -54,6 +54,15 @@
android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<FrameLayout android:id="@+id/incall_picture_box" android:layout_above="@id/conf_simple_actions"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_centerInParent="true">
<ImageView android:id="@+id/incall_picture" android:visibility="gone"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_gravity="center" android:scaleType="fitCenter"
android:padding="10sp" android:minWidth="288px" android:minHeight="288px"
android:paddingBottom="50sp" />
</FrameLayout>
<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
@ -62,7 +71,7 @@
android:dividerHeight="10dip"
android:divider="@android:color/transparent"
android:layout_below="@id/conf_header"
android:layout_above="@id/conf_simple_actions"
android:layout_above="@id/incall_picture_box"
android:layout_alignWithParentIfMissing="true"
android:fadeScrollbars="false"
/>

View file

@ -13,6 +13,11 @@
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content" android:orientation="vertical"
android:layout_centerInParent="true">
<ImageView android:id="@+id/incoming_picture"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_gravity="center" android:scaleType="fitCenter"
android:minWidth="288px" android:minHeight="288px"
android:paddingBottom="10sp"/>
<TextView android:id="@+id/incoming_caller_name"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Caller name" android:textAppearance="?android:attr/textAppearanceLarge"

View file

@ -21,6 +21,8 @@ package org.linphone;
import java.util.Collections;
import java.util.List;
import org.linphone.mediastream.Version;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;

View file

@ -41,6 +41,7 @@ import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
@ -51,6 +52,7 @@ import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;
import android.widget.Toast;
@ -132,6 +134,7 @@ public class ConferenceActivity extends ListActivity implements
@Override
public void onResumeWhenManagerReady() {
registerLinphoneListener(true);
updateCalleeImage();
updateConfState();
updateMergeButtonState();
}
@ -164,6 +167,23 @@ public class ConferenceActivity extends ListActivity implements
super.onPause();
}
private void updateCalleeImage() {
ImageView view = (ImageView) findViewById(R.id.incall_picture);
LinphoneCall currentCall = lc().getCurrentCall();
if (lc().getCallsNb() != 1 || currentCall == null) {
view.setVisibility(GONE);
return;
}
Uri picture = LinphoneUtils.findPictureOfContact(
getContentResolver(),
currentCall.getRemoteAddress().getUserName(),
currentCall.getRemoteAddress().getDomain());
LinphoneUtils.setImagePictureFromUri(view, picture, R.drawable.unknown_person);
view.setVisibility(VISIBLE);
}
private void enableView(View root, int id, OnClickListener l, boolean enable) {
View v = root.findViewById(id);
v.setVisibility(enable ? VISIBLE : GONE);
@ -418,15 +438,15 @@ public class ConferenceActivity extends ListActivity implements
final LinphoneCall.State state = call.getState();
String mainText = call.getRemoteAddress().getDisplayName();
String complText = call.getRemoteAddress().getUserName();
String username = call.getRemoteAddress().getUserName();
TextView mainTextView = (TextView) v.findViewById(R.id.name);
TextView complTextView = (TextView) v.findViewById(R.id.address);
if (TextUtils.isEmpty(mainText)) {
mainTextView.setText(complText);
mainTextView.setText(username);
complTextView.setVisibility(View.GONE);
} else {
mainTextView.setText(mainText);
complTextView.setText(complText);
complTextView.setText(username);
complTextView.setVisibility(View.VISIBLE);
}
@ -510,6 +530,17 @@ public class ConferenceActivity extends ListActivity implements
}
});
ImageView pictureView = (ImageView) v.findViewById(R.id.picture);
if (numberOfCalls != 1) {
String domain = call.getRemoteAddress().getDomain();
// May be greatly sped up using a drawable cache
Uri uri = LinphoneUtils.findPictureOfContact(getContentResolver(), username, domain);
LinphoneUtils.setImagePictureFromUri(pictureView, uri, R.drawable.unknown_person);
pictureView.setVisibility(VISIBLE);
} else {
pictureView.setVisibility(GONE);
}
return v;
}
}
@ -548,6 +579,7 @@ public class ConferenceActivity extends ListActivity implements
CalleeListAdapter adapter = (CalleeListAdapter) getListAdapter();
Log.d("ConferenceActivity applying state ",stateStr);
updateMergeButtonState();
updateCalleeImage();
if (state == State.IncomingReceived || state == State.OutgoingRinging) {
if (!adapter.linphoneCalls.contains(call)) {
adapter.linphoneCalls.add(call);

View file

@ -23,12 +23,14 @@ import java.util.List;
import org.linphone.mediastream.Version;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.PhoneLookup;
import android.text.TextUtils;
@ -52,19 +54,27 @@ public class ContactPickerActivityNew extends AbstractContactPickerActivity {
@Override
public Uri getPhotoUri(String id) {
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(id));
return retrievePhotoUri(getContentResolver(), Long.parseLong(id));
}
private static Uri retrievePhotoUri(ContentResolver resolver, long id) {
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id);
Uri photoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY);
if (photoUri == null) {
return null;
}
Cursor cursor = getContentResolver().query(photoUri,
new String[]{ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null);
String[] projection = {ContactsContract.CommonDataKinds.Photo.PHOTO};
Cursor cursor = resolver.query(photoUri, projection, null, null, null);
try {
if (cursor == null || !cursor.moveToNext()) {
return null;
}
byte[] data = cursor.getBlob(0);
if (data == null) {
// TODO: simplify all this stuff
// which is here only to check that the
// photoUri really points to some data.
// Not retrieving the data now would be better.
return null;
}
return photoUri;
@ -78,9 +88,10 @@ public class ContactPickerActivityNew extends AbstractContactPickerActivity {
protected List<String> extractPhones(String id) {
List<String> list = new ArrayList<String>();
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] projection = {ContactsContract.CommonDataKinds.Phone.NUMBER};
String selection = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?";
String[] selArgs = new String[] {id};
Cursor c = this.getContentResolver().query(uri, null, selection, selArgs, null);
Cursor c = this.getContentResolver().query(uri, projection, selection, selArgs, null);
int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
@ -96,35 +107,41 @@ public class ContactPickerActivityNew extends AbstractContactPickerActivity {
protected List<String> extractSipNumbers(String id) {
List<String> list = new ArrayList<String>();
Uri uri = ContactsContract.Data.CONTENT_URI;
String[] projection = {ContactsContract.CommonDataKinds.Im.DATA};
String selection = new StringBuilder()
.append(ContactsContract.Data.CONTACT_ID).append(" = ? AND ")
.append(ContactsContract.Data.MIMETYPE).append(" = ? ")
.append(" AND lower(")
.append(ContactsContract.Data.MIMETYPE).append(" = '")
.append(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
.append("' AND lower(")
.append(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL)
.append(") = 'sip'").toString();
String[] selArgs = new String[] {id, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE};
Cursor c = this.getContentResolver().query(uri, null, selection, selArgs, null);
.append(") = 'sip'")
.toString();
Cursor c = getContentResolver().query(uri, projection, selection, new String[]{id}, null);
int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA);
while (c.moveToNext()) {
list.add("sip:" + c.getString(nbId));
}
c.close();
// Using the SIP contact field added in SDK 9
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
selection = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?";
String projection[] = new String[] {ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS};
selArgs = new String[] {id, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE};
c = this.getContentResolver().query(uri, projection, selection, selArgs, null);
selection = new StringBuilder()
.append(ContactsContract.Data.CONTACT_ID)
.append(" = ? AND ")
.append(ContactsContract.Data.MIMETYPE)
.append(" = '")
.append(ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
.append("'")
.toString();
projection = new String[] {ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS};
c = this.getContentResolver().query(uri, projection, selection, new String[]{id}, null);
nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS);
while (c.moveToNext()) {
list.add("sip:" + c.getString(nbId));
}
c.close();
}
@ -162,9 +179,10 @@ public class ContactPickerActivityNew extends AbstractContactPickerActivity {
private String retrieveContactName(String id) {
//Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[] {ContactsContract.Contacts.DISPLAY_NAME};
String selection = ContactsContract.Contacts._ID + " = ?";
String[] selArgs = new String[] {id};
Cursor c = this.getContentResolver().query(uri, null, selection, selArgs, null);
Cursor c = this.getContentResolver().query(uri, projection, selection, selArgs, null);
String name = "";
if (c.moveToFirst()) {
@ -199,4 +217,58 @@ public class ContactPickerActivityNew extends AbstractContactPickerActivity {
}
private static Uri retrievePhotoUri(ContentResolver resolver, Cursor c, String column) {
if (c == null) return null;
while (c.moveToNext()) {
long id = c.getLong(c.getColumnIndex(column));
Uri picture = retrievePhotoUri(resolver, id);
if (picture != null) {
c.close();
return picture;
}
}
c.close();
return null;
}
public static Uri findUriPictureOfContact(ContentResolver resolver, String username, String domain) {
Uri retrievedPictureUri = null;
String sipUri = username + "@" + domain;
// Try first using sip field
Uri uri = ContactsContract.Data.CONTENT_URI;
String[] projection = {ContactsContract.Data.CONTACT_ID};
String selection = new StringBuilder()
.append(ContactsContract.CommonDataKinds.Im.DATA).append(" = ? AND ")
.append(ContactsContract.Data.MIMETYPE)
.append(" = '")
.append(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
.append("' AND lower(")
.append(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL)
.append(") = 'sip'").toString();
Cursor c = resolver.query(uri, projection, selection, new String[] {sipUri}, null);
retrievedPictureUri = retrievePhotoUri(resolver, c, ContactsContract.Data.CONTACT_ID);
if (retrievedPictureUri != null) return retrievedPictureUri;
// Then using custom SIP field
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
selection = new StringBuilder()
.append(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS)
.append(" = ? AND ")
.append(ContactsContract.Data.MIMETYPE)
.append(" = '")
.append(ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
.append("'")
.toString();
c = resolver.query(uri, projection, selection, new String[] {sipUri}, null);
retrievedPictureUri = retrievePhotoUri(resolver, c, ContactsContract.Data.CONTACT_ID);
if (retrievedPictureUri != null) return retrievedPictureUri;
}
// Finally using phone number
Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(username));
projection = new String[]{PhoneLookup._ID};
c = resolver.query(lookupUri, projection, null, null, null);
return retrievePhotoUri(resolver, c, PhoneLookup._ID);
}
}

View file

@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
package org.linphone;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Intent;
import android.database.Cursor;
@ -91,4 +92,8 @@ public class ContactPickerActivityOld extends Activity {
LinphoneActivity.instance().getTabHost().setCurrentTabByTag(LinphoneActivity.DIALER_TAB);
}
}
public static Uri findUriPictureOfContact(ContentResolver resolver, String username, String domain) {
throw new RuntimeException("not implemented");
}
}

View file

@ -137,7 +137,10 @@ public class DialerActivity extends Activity implements LinphoneGuiListener, Lin
mInCallAddressLayout = findViewById(R.id.IncallAddressLayout);
mInCallAddressLayout.setVisibility(View.GONE);
if (useIncallActivity) {
if (useConferenceActivity) {
mHangup = findViewById(R.id.HangUp);
((HangCallButton)mHangup).setTerminateAllCalls(true);
} else if (useIncallActivity) {
mHangup = findViewById(R.id.HangUp);
} else {
mMute = (MuteMicButton) findViewById(R.id.mic_mute_button);

View file

@ -18,17 +18,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone;
import static android.view.View.VISIBLE;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.Log;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.Html.ImageGetter;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
@ -42,6 +47,7 @@ public class IncomingCallActivity extends Activity implements OnClickListener {
private TextView mNameView;
private TextView mNumberView;
private ImageView mPictureView;
private LinphoneCall mCall;
private void findIncomingCall(Intent intent) {
@ -62,6 +68,7 @@ public class IncomingCallActivity extends Activity implements OnClickListener {
mNameView = (TextView) findViewById(R.id.incoming_caller_name);
mNumberView = (TextView) findViewById(R.id.incoming_caller_number);
mPictureView = (ImageView) findViewById(R.id.incoming_picture);
findViewById(R.id.Decline).setOnClickListener(this);
findViewById(R.id.Answer).setOnClickListener(this);
@ -84,6 +91,11 @@ public class IncomingCallActivity extends Activity implements OnClickListener {
String from = LinphoneManager.extractADisplayName(getResources(), address);
mNameView.setText(from);
mNumberView.setText(address.asStringUriOnly());
String username = address.getUserName();
String domain = address.getDomain();
// May be greatly sped up using a drawable cache
Uri uri = LinphoneUtils.findPictureOfContact(getContentResolver(), username, domain);
LinphoneUtils.setImagePictureFromUri(mPictureView, uri, R.drawable.unknown_person);
super.onResume();
}

View file

@ -18,15 +18,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import org.linphone.core.Log;
import org.linphone.mediastream.Version;
import org.linphone.mediastream.video.capture.hwconf.Hacks;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.view.KeyEvent;
import android.widget.ImageView;
/**
* Helper to handle softvolume.
* Helpers.
* @author Guillaume Beraudo
*
*/
@ -63,5 +74,50 @@ public final class LinphoneUtils {
}
return !preventVolumeBarToDisplay;
}
/**
* @param contact sip uri
* @return url/uri of the resource
*/
public static Uri findPictureOfContact(ContentResolver resolver, String username, String domain) {
if (Version.sdkAboveOrEqual(Version.API06_ECLAIR_20)) {
return ContactPickerActivityNew.findUriPictureOfContact(resolver, username, domain);
} else {
return ContactPickerActivityOld.findUriPictureOfContact(resolver, username, domain);
}
}
public static Bitmap downloadBitmap(Uri uri) {
URL url;
InputStream is = null;
try {
url = new URL(uri.toString());
is = url.openStream();
return BitmapFactory.decodeStream(is);
} catch (MalformedURLException e) {
Log.e(e, e.getMessage());
} catch (IOException e) {
Log.e(e, e.getMessage());
} finally {
try {is.close();} catch (IOException x) {}
}
return null;
}
public static void setImagePictureFromUri(ImageView view, Uri uri, int notFoundResource) {
if (uri == null) {
view.setImageResource(notFoundResource);
return;
}
if (uri.getScheme().startsWith("http")) {
Bitmap bm = downloadBitmap(uri);
if (bm == null) view.setImageResource(notFoundResource);
view.setImageBitmap(bm);
} else {
view.setImageURI(uri);
}
}
}

View file

@ -29,6 +29,9 @@ import android.widget.ImageButton;
public class HangCallButton extends ImageButton implements OnClickListener {
private boolean terminateAllCalls;
public void setTerminateAllCalls(boolean all) {terminateAllCalls = all;}
private OnClickListener externalClickListener;
public void setExternalClickListener(OnClickListener e) {externalClickListener = e;}
@ -39,7 +42,11 @@ public class HangCallButton extends ImageButton implements OnClickListener {
public void onClick(View v) {
LinphoneCore lc = LinphoneManager.getLc();
if (terminateAllCalls) {
lc.terminateAllCalls();
} else {
lc.terminateCall(lc.getCurrentCall());
}
if (externalClickListener != null) externalClickListener.onClick(v);
}