diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 270d32c36..64166c3fd 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3,11 +3,12 @@ package="org.linphone" android:versionCode="1104" android:versionName="1.1.4" android:installLocation="auto"> - + + + - + + + + + + + @@ -53,7 +61,12 @@ - + + + + + + diff --git a/res/layout/contact_picker.xml b/res/layout/contact_picker.xml new file mode 100644 index 000000000..9ad7a12e1 --- /dev/null +++ b/res/layout/contact_picker.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/src/org/linphone/ContactPickerActivityNew.java b/src/org/linphone/ContactPickerActivityNew.java new file mode 100644 index 000000000..e3a06fe60 --- /dev/null +++ b/src/org/linphone/ContactPickerActivityNew.java @@ -0,0 +1,271 @@ +/* +ContactPickerActivity.java +Copyright (C) 2010 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package org.linphone; + +import java.util.ArrayList; +import java.util.List; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.ContactsContract; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.FilterQueryProvider; +import android.widget.ListView; +import android.widget.SimpleCursorAdapter; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.AdapterView.OnItemClickListener; + + +/** + * Activity for retrieving a phone number / SIP address to call. + *
+ * + * The cinematic is: + *
    + *
  • Select contact (either through native or custom way)
  • + *
  • Select phone number or SIP address + *
  • Back to dialer
  • + *
+ * + * @author Guillaume Beraudo + * + */ +public class ContactPickerActivityNew extends Activity implements FilterQueryProvider { + + private ListView mContactList; + private EditText mcontactFilter; + + private SimpleCursorAdapter adapter; + private boolean useNativePicker; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + useNativePicker = getResources().getBoolean(R.bool.use_android_contact_picker); + + if (!useNativePicker) { + setContentView(R.layout.contact_picker); + createPicker(); + } + } + + + + private void createPicker() { + mContactList = (ListView) findViewById(R.id.contactList); + + mcontactFilter = (EditText) findViewById(R.id.contactFilter); + mcontactFilter.addTextChangedListener(new TextWatcher() { + public void onTextChanged(CharSequence s, int start, int b, int c) {} + public void beforeTextChanged(CharSequence s, int st, int c, int a) {} + + public void afterTextChanged(Editable s) { + adapter.runQueryOnBackgroundThread(s); + adapter.getFilter().filter(s.toString()); + } + }); + + + // Populate the contact list + String[] from = new String[] {ContactsContract.Data.DISPLAY_NAME}; + int[] to = new int[] {android.R.id.text1}; + int layout = android.R.layout.simple_list_item_1; + adapter = new SimpleCursorAdapter(this, layout, runQuery(null), from, to); + adapter.setFilterQueryProvider(this); + mContactList.setAdapter(adapter); + + mContactList.setOnItemClickListener(new OnItemClickListener() { + public void onItemClick(AdapterView parent, View view, int position, long id) { + final CharSequence contactName = ((TextView) view.findViewById(android.R.id.text1)).getText(); + choosePhoneNumberAndDial(contactName, String.valueOf(id)); + } + }); + } + + + + private void choosePhoneNumberAndDial(final CharSequence contactName, final String id) { + List phones = extractPhones(id); + phones.addAll(extractSipNumbers(id)); + + switch (phones.size()) { + case 0: + String msg = String.format(getString(R.string.no_phone_numbers), contactName); + Toast.makeText(ContactPickerActivityNew.this, msg, Toast.LENGTH_LONG).show(); + break; + case 1: + returnSelectedValues(phones.get(0), contactName.toString()); + break; + default: + AlertDialog.Builder builder = new AlertDialog.Builder(ContactPickerActivityNew.this); + + final ArrayAdapter pAdapter = new ArrayAdapter(ContactPickerActivityNew.this, + android.R.layout.simple_dropdown_item_1line, phones); + + builder.setTitle(String.format(getString(R.string.title_numbers_dialog),contactName)); + builder.setAdapter(pAdapter, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + returnSelectedValues(pAdapter.getItem(which), contactName.toString()); + } + }); + builder.setCancelable(true); + builder.setNeutralButton("cancel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }); + AlertDialog dialog = builder.create(); + dialog.show(); + } + } + + private void returnSelectedValues(String number, String name) { +/* if (getCallingActivity() != null) { + setResult(RESULT_OK, new Intent() + .putExtra(Intent.EXTRA_PHONE_NUMBER, number) + .putExtra(EXTRA_CONTACT_NAME, name)); + finish(); + }*/ + + LinphoneActivity.setAddressAndGoToDialer(number, name); + } + + + private List extractPhones(String id) { + List list = new ArrayList(); + Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI; + String selection = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?"; + String[] selArgs = new String[] {id}; + Cursor c = this.getContentResolver().query(uri, null, selection, selArgs, null); + + int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER); + + while (c.moveToNext()) { + list.add(c.getString(nbId)); + } + + c.close(); + + return list; + } + + private List extractSipNumbers(String id) { + List list = new ArrayList(); + Uri uri = ContactsContract.Data.CONTENT_URI; + 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); + + int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA); + + while (c.moveToNext()) { + list.add("sip:" + c.getString(nbId)); + } + + c.close(); + + return list; + } + + @Override + protected void onResume() { + super.onResume(); + + if (useNativePicker) { + Uri uri = ContactsContract.Contacts.CONTENT_URI; + //ContactsContract.CommonDataKinds.Phone.CONTENT_URI + startActivityForResult(new Intent(Intent.ACTION_PICK, uri), 0); + } + } + + protected void onActivityResult(int reqCode, int resultCode, Intent intent) { + // If using native picker + if (reqCode == 0) { + if (resultCode == RESULT_OK) { + String id = intent.getData().getLastPathSegment(); + String contactName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); + if (contactName == null) + contactName = retrieveContactName(id); + choosePhoneNumberAndDial(contactName, id); + } + } + + LinphoneActivity.instance().getTabHost().setCurrentTabByTag(LinphoneActivity.DIALER_TAB); + } + + + private String retrieveContactName(String id) { + Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI; + String selection = ContactsContract.CommonDataKinds.Phone._ID + " = ?"; + String[] selArgs = new String[] {id}; + Cursor c = this.getContentResolver().query(uri, null, selection, selArgs, null); + + String name = ""; + if (c.moveToFirst()) { + name = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); + } + c.close(); + + return name; + } + + + + public Cursor runQuery(CharSequence constraint) { + // Run query + Uri uri = ContactsContract.Contacts.CONTENT_URI; + String[] projection = new String[] { + ContactsContract.Contacts._ID, + ContactsContract.Contacts.DISPLAY_NAME + }; + String selection = + ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '1' and " + + ContactsContract.Contacts.HAS_PHONE_NUMBER + " = '1'"; + String[] selectionArgs = null; + if (!TextUtils.isEmpty(constraint)) { + // FIXME absolutely unsecure + selection += " and " + ContactsContract.Contacts.DISPLAY_NAME + " ilike '%"+mcontactFilter.getText()+"%'"; + } + + String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; + + return managedQuery(uri, projection, selection, selectionArgs, sortOrder); + } + + +} diff --git a/src/org/linphone/ContactPickerActivity.java b/src/org/linphone/ContactPickerActivityOld.java similarity index 96% rename from src/org/linphone/ContactPickerActivity.java rename to src/org/linphone/ContactPickerActivityOld.java index 99604ef6c..943587781 100644 --- a/src/org/linphone/ContactPickerActivity.java +++ b/src/org/linphone/ContactPickerActivityOld.java @@ -25,8 +25,8 @@ import android.os.Bundle; import android.provider.Contacts; import android.provider.Contacts.People; - -public class ContactPickerActivity extends Activity { +@SuppressWarnings("deprecation") +public class ContactPickerActivityOld extends Activity { static final int PICK_CONTACT_REQUEST = 0; static final int PICK_PHONE_NUMBER_REQUEST = 1; diff --git a/src/org/linphone/HistoryActivity.java b/src/org/linphone/HistoryActivity.java index 86eb2bc82..a4d958e12 100644 --- a/src/org/linphone/HistoryActivity.java +++ b/src/org/linphone/HistoryActivity.java @@ -59,12 +59,12 @@ public class HistoryActivity extends ListActivity { TextView lSecondLineView = (TextView) v.findViewById(R.id.history_cell_second_line); if (lSecondLineView.getVisibility() == View.GONE) { // no display name - DialerActivity.instance().setContactAddress(lFirstLineView.getText().toString(), null); + LinphoneActivity.setAddressAndGoToDialer(lFirstLineView.getText().toString(), null); } else { - DialerActivity.instance().setContactAddress(lSecondLineView.getText().toString() - ,lFirstLineView.getText().toString()); + LinphoneActivity.setAddressAndGoToDialer( + lSecondLineView.getText().toString(), + lFirstLineView.getText().toString()); } - LinphoneActivity.instance().getTabHost().setCurrentTabByTag(LinphoneActivity.DIALER_TAB); } diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index 3999e2d90..8a44b9ac6 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -1,5 +1,5 @@ /* -LinphoneActivity.java +iLinphoneActivity.java Copyright (C) 2010 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or @@ -74,6 +74,7 @@ public class LinphoneActivity extends TabActivity { private FrameLayout mMainFrame; private SensorManager mSensorManager; private static SensorEventListener mSensorEventListener; + private static String TAG = LinphoneManager.TAG; private static final String SCREEN_IS_HIDDEN ="screen_is_hidden"; @@ -155,7 +156,7 @@ public class LinphoneActivity extends TabActivity { } }); } catch (LinphoneCoreException e) { - Log.e(LinphoneManager.TAG, "Unable to calibrate EC", e); + Log.e(TAG, "Unable to calibrate EC", e); } fillTabHost(); @@ -197,7 +198,8 @@ public class LinphoneActivity extends TabActivity { // Contact picker - tabIntent = new Intent().setClass(this, ContactPickerActivity.class); + tabIntent = new Intent().setClass(this, Version.sdkAboveOrEqual(5) ? + ContactPickerActivityNew.class : ContactPickerActivityOld.class); indicator = getString(R.string.tab_contact); tabDrawable = getResources().getDrawable(R.drawable.contact_orange); spec = lTabHost.newTabSpec("contact") @@ -212,14 +214,17 @@ public class LinphoneActivity extends TabActivity { @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); - if (intent.getData() != null) { - if (DialerActivity.instance() != null) { - DialerActivity.instance().newOutgoingCall(intent); - } else { - Toast.makeText(this, getString(R.string.dialer_null_on_new_intent), Toast.LENGTH_LONG).show(); - } - } + if (intent.getData() == null) { + Log.e(TAG, "LinphoneActivity received an intent without data, discarding"); + return; + } + + if (DialerActivity.instance() != null) { + DialerActivity.instance().newOutgoingCall(intent); + } else { + Toast.makeText(this, getString(R.string.dialer_null_on_new_intent), Toast.LENGTH_LONG).show(); + } } @Override protected void onPause() { @@ -264,7 +269,7 @@ public class LinphoneActivity extends TabActivity { startActivity(new Intent(ACTION_MAIN) .setClass(this, AboutActivity.class)); default: - Log.e(LinphoneManager.TAG, "Unknown menu item ["+item+"]"); + Log.e(TAG, "Unknown menu item ["+item+"]"); break; } @@ -293,14 +298,14 @@ public class LinphoneActivity extends TabActivity { synchronized void startProxymitySensor() { if (mSensorEventListener != null) { - Log.i(LinphoneManager.TAG, "proximity sensor already active"); + Log.i(TAG, "proximity sensor already active"); return; } List lSensorList = mSensorManager.getSensorList(Sensor.TYPE_PROXIMITY); mSensorEventListener = new SensorEventListener() { public void onSensorChanged(SensorEvent event) { if (event.timestamp == 0) return; //just ignoring for nexus 1 - Log.d(LinphoneManager.TAG, "Proximity sensor report ["+event.values[0]+"] , for max range ["+event.sensor.getMaximumRange()+"]"); + Log.d(TAG, "Proximity sensor report ["+event.values[0]+"] , for max range ["+event.sensor.getMaximumRange()+"]"); if (event.values[0] != event.sensor.getMaximumRange() ) { instance().hideScreen(true); @@ -313,7 +318,7 @@ public class LinphoneActivity extends TabActivity { }; if (lSensorList.size() >0) { mSensorManager.registerListener(mSensorEventListener,lSensorList.get(0),SensorManager.SENSOR_DELAY_UI); - Log.i(LinphoneManager.TAG, "Proximity sensor detected, registering"); + Log.i(TAG, "Proximity sensor detected, registering"); } } @@ -420,5 +425,10 @@ public class LinphoneActivity extends TabActivity { builder.create().show(); } + + public static void setAddressAndGoToDialer(String number, String name) { + DialerActivity.instance().setContactAddress(number, name); + instance.getTabHost().setCurrentTabByTag(DIALER_TAB); + } }