diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 2228c435e..5f3d7662b 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -61,7 +61,8 @@ + android:theme="@android:style/Theme.NoTitleBar.Fullscreen" + android:screenOrientation="portrait"> diff --git a/res/drawable-hdpi/unknown_person.png b/res/drawable-hdpi/unknown_person.png new file mode 100644 index 000000000..0e5179932 Binary files /dev/null and b/res/drawable-hdpi/unknown_person.png differ diff --git a/res/drawable-ldpi/unknown_person.png b/res/drawable-ldpi/unknown_person.png new file mode 100644 index 000000000..4425150f2 Binary files /dev/null and b/res/drawable-ldpi/unknown_person.png differ diff --git a/res/drawable-mdpi/unknown_person.png b/res/drawable-mdpi/unknown_person.png new file mode 100644 index 000000000..ed45aedcd Binary files /dev/null and b/res/drawable-mdpi/unknown_person.png differ diff --git a/res/drawable/unknown_person.png b/res/drawable/unknown_person.png index ac5ea1616..d66515187 100644 Binary files a/res/drawable/unknown_person.png and b/res/drawable/unknown_person.png differ diff --git a/res/layout/conferencing.xml b/res/layout/conferencing.xml index 61791955b..42781aeb8 100644 --- a/res/layout/conferencing.xml +++ b/res/layout/conferencing.xml @@ -54,6 +54,15 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" /> + + + diff --git a/res/layout/incoming.xml b/res/layout/incoming.xml index 4b0f71816..aab32ea21 100644 --- a/res/layout/incoming.xml +++ b/res/layout/incoming.xml @@ -13,6 +13,11 @@ + extractPhones(String id) { List list = new ArrayList(); 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 extractSipNumbers(String id) { List list = new ArrayList(); 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.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(ContactsContract.Data.CONTACT_ID).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 = 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,13 +179,14 @@ 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()) { - name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); + name = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); } c.close(); @@ -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); + } } diff --git a/src/org/linphone/ContactPickerActivityOld.java b/src/org/linphone/ContactPickerActivityOld.java index cf7489816..38c939ce5 100644 --- a/src/org/linphone/ContactPickerActivityOld.java +++ b/src/org/linphone/ContactPickerActivityOld.java @@ -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"); + } } diff --git a/src/org/linphone/DialerActivity.java b/src/org/linphone/DialerActivity.java index f81a701d8..fbc1183d4 100644 --- a/src/org/linphone/DialerActivity.java +++ b/src/org/linphone/DialerActivity.java @@ -137,8 +137,11 @@ public class DialerActivity extends Activity implements LinphoneGuiListener, Lin mInCallAddressLayout = findViewById(R.id.IncallAddressLayout); mInCallAddressLayout.setVisibility(View.GONE); - if (useIncallActivity) { - mHangup = findViewById(R.id.HangUp); + 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); mSpeaker = (SpeakerButton) findViewById(R.id.speaker_button); diff --git a/src/org/linphone/IncomingCallActivity.java b/src/org/linphone/IncomingCallActivity.java index 5e3bccc3f..5beb9bfbb 100644 --- a/src/org/linphone/IncomingCallActivity.java +++ b/src/org/linphone/IncomingCallActivity.java @@ -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(); } diff --git a/src/org/linphone/LinphoneUtils.java b/src/org/linphone/LinphoneUtils.java index a9c884892..7234b0758 100644 --- a/src/org/linphone/LinphoneUtils.java +++ b/src/org/linphone/LinphoneUtils.java @@ -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); + } + } + } diff --git a/src/org/linphone/ui/HangCallButton.java b/src/org/linphone/ui/HangCallButton.java index 706df35ec..9194c844d 100644 --- a/src/org/linphone/ui/HangCallButton.java +++ b/src/org/linphone/ui/HangCallButton.java @@ -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(); - lc.terminateCall(lc.getCurrentCall()); + if (terminateAllCalls) { + lc.terminateAllCalls(); + } else { + lc.terminateCall(lc.getCurrentCall()); + } if (externalClickListener != null) externalClickListener.onClick(v); }