allows to insert in the native contact of android its presence sip address from the phone number

X
This commit is contained in:
Claire Rosset 2019-06-07 11:32:06 +02:00 committed by rosset claire
parent 8ff286983a
commit 734b69c619
19 changed files with 344 additions and 66 deletions

View file

@ -50,6 +50,7 @@ import org.linphone.call.CallManager;
import org.linphone.contacts.ContactsManager;
import org.linphone.core.AccountCreator;
import org.linphone.core.AccountCreatorListenerStub;
import org.linphone.core.BuildConfig;
import org.linphone.core.Call;
import org.linphone.core.Call.State;
import org.linphone.core.ConfiguringState;

View file

@ -34,13 +34,14 @@ import java.io.Serializable;
import java.util.ArrayList;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.core.PresenceBasicStatus;
import org.linphone.core.PresenceModel;
import org.linphone.core.tools.Log;
class AndroidContact implements Serializable {
String mAndroidId;
private String mAndroidRawId;
private boolean isAndroidRawIdLinphone;
private final transient ArrayList<ContentProviderOperation> mChangesToCommit;
AndroidContact() {
@ -128,6 +129,7 @@ class AndroidContact implements Serializable {
RawContacts.AGGREGATION_MODE_DEFAULT)
.build());
isAndroidRawIdLinphone = true;
} else {
Log.i("[Contact] Creating contact using default account type");
addChangesToCommit(
@ -208,6 +210,75 @@ class AndroidContact implements Serializable {
}
}
public void updateNativeContactWithPresenceInfo(LinphoneContact contact) {
// creation of the raw contact with the presence information (tablet)
createRawLinphoneContactFromExistingAndroidContactIfNeeded();
for (LinphoneNumberOrAddress noa : contact.getNumbersOrAddresses()) {
String value = noa.getValue();
if (value == null || value.isEmpty()) {
return;
}
// Test presence of the value
PresenceModel pm = contact.getFriend().getPresenceModelForUriOrTel(value);
// If presence is not null
if (pm != null && pm.getBasicStatus().equals(PresenceBasicStatus.Open)) {
Boolean action = hasLinphoneAddressMimeType();
// do the action on the contact only once if it has not been done
if (action) {
if (!noa.isSIPAddress()) {
addChangesToCommit(
ContentProviderOperation.newInsert(Data.CONTENT_URI)
.withValue(
ContactsContract.Data.RAW_CONTACT_ID, mAndroidRawId)
.withValue(
Data.MIMETYPE,
ContactsManager.getInstance()
.getString(
R.string
.linphone_address_mime_type))
.withValue("data1", value) // phone number
.withValue(
"data2",
ContactsManager.getInstance()
.getString(R.string.app_name)) // Summary
.withValue("data3", value) // Detail
.build());
saveChangesCommited();
}
}
}
}
}
private Boolean hasLinphoneAddressMimeType() {
Boolean action = true;
ContentResolver resolver = LinphoneService.instance().getContentResolver();
String[] projection = {"data1", "data3"};
String selection =
ContactsContract.Data.RAW_CONTACT_ID + "= ? AND " + Data.MIMETYPE + "= ?";
Cursor c =
resolver.query(
ContactsContract.Data.CONTENT_URI,
projection,
selection,
new String[] {
mAndroidRawId,
ContactsManager.getInstance()
.getString(R.string.linphone_address_mime_type)
},
null);
if (c != null) {
if (c.moveToFirst()) {
action = false;
}
c.close();
}
return action;
}
void addNumberOrAddress(String value, String oldValueToReplace, boolean isSIP) {
if (value == null || value.isEmpty()) {
Log.e("[Contact] Can't add null or empty number or address");

View file

@ -0,0 +1,23 @@
package org.linphone.contacts;
import android.os.AsyncTask;
public class AsyncContactPresence extends AsyncTask<Void, AndroidContact, Void> {
private LinphoneContact linphoneContact;
public AsyncContactPresence(LinphoneContact linphoneContact) {
this.linphoneContact = linphoneContact;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... voids) {
linphoneContact.updateNativeContactWithPresenceInfo(linphoneContact);
return null;
}
}

View file

@ -202,7 +202,7 @@ public class ContactDetailsFragment extends Fragment implements ContactsUpdatedL
if (mContact == null) return;
ContactAvatar.displayAvatar(mContact, view.findViewById(R.id.avatar_layout));
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
boolean isOrgVisible = LinphonePreferences.instance().isDisplayContactOrganization();
if (mContact != null
&& mContact.getOrganization() != null
&& !mContact.getOrganization().isEmpty()

View file

@ -55,6 +55,7 @@ import java.util.List;
import org.linphone.R;
import org.linphone.core.tools.Log;
import org.linphone.mediastream.Version;
import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.FileUtils;
import org.linphone.utils.LinphoneUtils;
import org.linphone.views.ContactAvatar;
@ -172,11 +173,13 @@ public class ContactEditorFragment extends Fragment {
}
if (noa.isSIPAddress()) {
noa.setValue(
LinphoneUtils.getFullAddressFromUsername(
noa.getValue()));
}
Log.i("[Contact Editor] Adding new number " + noa.getValue());
mContact.addOrUpdateNumberOrAddress(noa);
}
}
@ -413,7 +416,7 @@ public class ContactEditorFragment extends Fragment {
}
private void displayContact() {
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
boolean isOrgVisible = LinphonePreferences.instance().isDisplayContactOrganization();
if (!isOrgVisible) {
mOrganization.setVisibility(View.GONE);
mView.findViewById(R.id.contactOrganizationTitle).setVisibility(View.GONE);

View file

@ -142,7 +142,6 @@ public class ContactsActivity extends MainActivity {
}
} else if (extras.containsKey("Contact")) {
LinphoneContact contact = (LinphoneContact) extras.get("Contact");
if (extras.containsKey("Edit")) {
showContactEdit(contact, extras, true);
} else {

View file

@ -31,6 +31,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.linphone.R;
import org.linphone.settings.LinphonePreferences;
import org.linphone.utils.SelectableAdapter;
import org.linphone.utils.SelectableHelper;
import org.linphone.views.ContactAvatar;
@ -87,8 +88,7 @@ public class ContactsAdapter extends SelectableAdapter<ContactViewHolder>
ContactAvatar.displayAvatar(contact, holder.avatarLayout);
boolean isOrgVisible =
mContext.getResources().getBoolean(R.bool.display_contact_organization);
boolean isOrgVisible = LinphonePreferences.instance().isDisplayContactOrganization();
String org = contact.getOrganization();
if (org != null && !org.isEmpty() && isOrgVisible) {
holder.organization.setText(org);

View file

@ -288,7 +288,6 @@ public class ContactsFragment extends Fragment
mContactAdapter = new ContactsAdapter(mContext, listContact, this, mSelectionHelper);
mContactAdapter.setIsSearchMode(true);
// mContactsList.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
mSelectionHelper.setAdapter(mContactAdapter);
if (isEditionEnabled) {
mSelectionHelper.enterEditionMode();

View file

@ -426,7 +426,6 @@ public class ContactsManager extends ContentObserver implements FriendListListen
}
c.close();
// SIP addresses
projection = new String[] {ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS};
c = resolver.query(contactUri, projection, null, null, null);
if (c != null) {
@ -444,11 +443,21 @@ public class ContactsManager extends ContentObserver implements FriendListListen
private synchronized boolean refreshSipContact(Friend lf) {
LinphoneContact contact = (LinphoneContact) lf.getUserData();
if (contact != null) {
if (LinphoneService.instance().getResources().getBoolean(R.bool.use_linphone_tag)) {
// Inserting Linphone information in Android contact if the parameter is enabled
if (LinphonePreferences.instance()
.isPresenceStorageInNativeAndroidContactEnabled()) {
// add presence to native contact
AsyncContactPresence asyncContactPresence = new AsyncContactPresence(contact);
asyncContactPresence.execute();
}
}
if (!mSipContacts.contains(contact)) {
mSipContacts.add(contact);
return true;
}
}
@ -505,7 +514,6 @@ public class ContactsManager extends ContentObserver implements FriendListListen
boolean updated = false;
for (Friend lf : friends) {
boolean newContact = refreshSipContact(lf);
if (newContact) {

View file

@ -209,22 +209,28 @@ public class LinphoneContact extends AndroidContact
private synchronized void addNumberOrAddress(LinphoneNumberOrAddress noa) {
if (noa == null) return;
if (noa.isSIPAddress()) {
mHasSipAddress = true;
boolean found = false;
// Check for duplicated phone numbers but with different formats
for (LinphoneNumberOrAddress number : mAddresses) {
if ((!noa.isSIPAddress()
&& !number.isSIPAddress()
&& noa.getNormalizedPhone().equals(number.getNormalizedPhone()))
|| (noa.isSIPAddress()
&& !number.isSIPAddress()
&& noa.getValue().equals(number.getNormalizedPhone()))
|| (number.getValue().equals(noa.getNormalizedPhone())
|| !number.isSIPAddress())) {
found = true;
break;
}
}
if (!found) {
if (noa.isSIPAddress()) {
mHasSipAddress = true;
}
mAddresses.add(noa);
} else {
boolean found = false;
// Check for duplicated phone numbers but with different formats
for (LinphoneNumberOrAddress number : mAddresses) {
if (!number.isSIPAddress()
&& noa.getNormalizedPhone().equals(number.getNormalizedPhone())) {
found = true;
break;
}
}
if (!found) {
mAddresses.add(noa);
}
}
}
@ -541,7 +547,6 @@ public class LinphoneContact extends AndroidContact
|| LinphoneService.instance()
.getString(R.string.linphone_address_mime_type)
.equals(mime)) {
addNumberOrAddress(new LinphoneNumberOrAddress(data1, true));
} else if (ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE.equals(mime)) {
setOrganization(data1, false);

View file

@ -41,12 +41,7 @@ public class AdvancedSettingsFragment extends SettingsFragment {
private View mRootView;
private LinphonePreferences mPrefs;
private SwitchSetting mDebug,
mJavaLogger,
mFriendListSubscribe,
mBackgroundMode,
mStartAtBoot,
mDarkMode;
private SwitchSetting mDebug, mJavaLogger, mBackgroundMode, mStartAtBoot, mDarkMode;
private TextSetting mRemoteProvisioningUrl, mDisplayName, mUsername, mDeviceName, mLogUploadUrl;
private BasicSetting mAndroidAppSettings;
@ -81,8 +76,6 @@ public class AdvancedSettingsFragment extends SettingsFragment {
mLogUploadUrl = mRootView.findViewById(R.id.pref_log_collection_upload_server_url);
mLogUploadUrl.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
mFriendListSubscribe = mRootView.findViewById(R.id.pref_friendlist_subscribe);
mBackgroundMode = mRootView.findViewById(R.id.pref_background_mode);
mStartAtBoot = mRootView.findViewById(R.id.pref_autostart);
@ -127,14 +120,6 @@ public class AdvancedSettingsFragment extends SettingsFragment {
}
});
mFriendListSubscribe.setListener(
new SettingListenerBase() {
@Override
public void onBoolValueChanged(boolean newValue) {
mPrefs.enabledFriendlistSubscription(newValue);
}
});
mBackgroundMode.setListener(
new SettingListenerBase() {
@Override
@ -219,8 +204,6 @@ public class AdvancedSettingsFragment extends SettingsFragment {
mLogUploadUrl.setValue(mPrefs.getLogCollectionUploadServerUrl());
mFriendListSubscribe.setChecked(mPrefs.isFriendlistsubscriptionEnabled());
mBackgroundMode.setChecked(mPrefs.getServiceNotificationVisibility());
mStartAtBoot.setChecked(mPrefs.isAutoStartEnabled());

View file

@ -40,7 +40,6 @@ import org.linphone.settings.widget.TextSetting;
public class ChatSettingsFragment extends SettingsFragment {
private View mRootView;
private LinphonePreferences mPrefs;
private TextSetting mSharingServer, mMaxSizeForAutoDownloadIncomingFiles;
private BasicSetting mAndroidNotificationSettings;
private ListSetting mAutoDownloadIncomingFilesPolicy;

View file

@ -0,0 +1,110 @@
package org.linphone.settings;
/*
ContactSettingsFragment.java
Copyright (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import org.linphone.R;
import org.linphone.settings.widget.SettingListenerBase;
import org.linphone.settings.widget.SwitchSetting;
public class ContactSettingsFragment extends SettingsFragment {
private View mContactView;
private SwitchSetting mContactPresenceNativeContact,
mFriendListSubscribe,
mDisplayDetailContact;
private LinphonePreferences mPrefs;
@Override
public View onCreateView(
LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
mContactView = inflater.inflate(R.layout.settings_contact, container, false);
loadSettings();
return mContactView;
}
@Override
public void onResume() {
super.onResume();
mPrefs = LinphonePreferences.instance();
updateValues();
}
private void loadSettings() {
mFriendListSubscribe = mContactView.findViewById(R.id.pref_friendlist_subscribe);
mContactPresenceNativeContact =
mContactView.findViewById(R.id.pref_contact_presence_native_contact);
mDisplayDetailContact = mContactView.findViewById(R.id.pref_contact_organization);
}
private void updateValues() {
setListeners();
mFriendListSubscribe.setChecked(mPrefs.isFriendlistsubscriptionEnabled());
mContactPresenceNativeContact.setChecked(
mPrefs.isPresenceStorageInNativeAndroidContactEnabled());
if (getResources().getBoolean(R.bool.display_contact_organization)) {
mDisplayDetailContact.setChecked(mPrefs.isDisplayContactOrganization());
} else {
mDisplayDetailContact.setVisibility(View.INVISIBLE);
}
}
private void setListeners() {
mContactPresenceNativeContact.setListener(
new SettingListenerBase() {
@Override
public void onBoolValueChanged(boolean newValue) {
mPrefs.enabledPresenceStorageInNativeAndroidContact(newValue);
}
});
mFriendListSubscribe.setListener(
new SettingListenerBase() {
@Override
public void onBoolValueChanged(boolean newValue) {
mPrefs.enabledFriendlistSubscription(newValue);
// Synchronization of the buttons between them, possibility to click on :
// "presence information"... only if "is friends subscript on enabled" is
// active
mContactPresenceNativeContact.setEnabled(
mPrefs.isFriendlistsubscriptionEnabled());
if (!newValue) {
mContactPresenceNativeContact.setChecked(false);
}
}
});
mDisplayDetailContact.setListener(
new SettingListenerBase() {
@Override
public void onBoolValueChanged(boolean newValue) {
mPrefs.enabledDisplayContactOrganization(newValue);
}
});
}
}

View file

@ -233,19 +233,6 @@ public class LinphonePreferences {
return (proxyConf != null) ? proxyConf.getDomain() : "";
}
public boolean isFriendlistsubscriptionEnabled() {
if (getConfig().getBool("app", "friendlist_subscription_enabled", false)) {
// Old setting, do migration
getConfig().setBool("app", "friendlist_subscription_enabled", false);
enabledFriendlistSubscription(true);
}
return getLc().isFriendListSubscriptionEnabled();
}
public void enabledFriendlistSubscription(boolean enabled) {
getLc().enableFriendListSubscription(enabled);
}
public int getDefaultAccountIndex() {
if (getLc() == null) return -1;
ProxyConfig defaultPrxCfg = getLc().getDefaultProxyConfig();
@ -429,6 +416,41 @@ public class LinphonePreferences {
}
// End of video settings
// Contact settings
public boolean isFriendlistsubscriptionEnabled() {
if (getConfig().getBool("app", "friendlist_subscription_enabled", false)) {
// Old setting, do migration
getConfig().setBool("app", "friendlist_subscription_enabled", false);
enabledFriendlistSubscription(true);
}
return getLc().isFriendListSubscriptionEnabled();
}
public void enabledFriendlistSubscription(boolean enabled) {
getLc().enableFriendListSubscription(enabled);
}
public boolean isPresenceStorageInNativeAndroidContactEnabled() {
return getConfig().getBool("app", "store_presence_in_native_contact", false);
}
public void enabledPresenceStorageInNativeAndroidContact(boolean enabled) {
getConfig().setBool("app", "store_presence_in_native_contact", enabled);
}
public boolean isDisplayContactOrganization() {
return getConfig()
.getBool(
"app",
"display_contact_organization",
mContext.getResources().getBoolean(R.bool.display_contact_organization));
}
public void enabledDisplayContactOrganization(boolean enabled) {
getConfig().setBool("app", "display_contact_organization", enabled);
}
// End of contact settings
// Call settings
public boolean acceptIncomingEarlyMedia() {
return getConfig().getBool("sip", "incoming_calls_early_media", false);
@ -880,7 +902,6 @@ public class LinphonePreferences {
}
// End of tunnel settings
public boolean adaptiveRateControlEnabled() {
if (getLc() == null) return false;
return getLc().adaptiveRateControlEnabled();

View file

@ -37,7 +37,7 @@ import org.linphone.utils.LinphoneUtils;
public class MenuSettingsFragment extends SettingsFragment {
private View mRootView;
private BasicSetting mTunnel, mAudio, mVideo, mCall, mChat, mNetwork, mAdvanced;
private BasicSetting mTunnel, mAudio, mVideo, mCall, mChat, mNetwork, mAdvanced, mContact;
private LinearLayout mAccounts;
private TextView mAccountsHeader;
@ -77,6 +77,8 @@ public class MenuSettingsFragment extends SettingsFragment {
mNetwork = mRootView.findViewById(R.id.pref_network);
mAdvanced = mRootView.findViewById(R.id.pref_advanced);
mContact = mRootView.findViewById(R.id.pref_contact);
}
private void setListeners() {
@ -156,6 +158,17 @@ public class MenuSettingsFragment extends SettingsFragment {
getString(R.string.pref_advanced_title));
}
});
mContact.setListener(
new SettingListenerBase() {
@Override
public void onClicked() {
((SettingsActivity) getActivity())
.showSettings(
new ContactSettingsFragment(),
getString(R.string.pref_contact_title));
}
});
}
private void updateValues() {

View file

@ -71,12 +71,20 @@
android:layout_height="wrap_content"
linphone:title="@string/pref_network_title"/>
<org.linphone.settings.widget.BasicSetting
android:id="@+id/pref_contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
linphone:title="@string/pref_contact_title"/>
<org.linphone.settings.widget.BasicSetting
android:id="@+id/pref_advanced"
android:layout_width="match_parent"
android:layout_height="wrap_content"
linphone:title="@string/pref_advanced_title"/>
</LinearLayout>
</ScrollView>

View file

@ -23,12 +23,6 @@
android:layout_height="wrap_content"
linphone:title="@string/pref_java_debug" />
<org.linphone.settings.widget.SwitchSetting
android:id="@+id/pref_friendlist_subscribe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
linphone:title="@string/pref_friendlist_subscribe" />
<org.linphone.settings.widget.SwitchSetting
android:id="@+id/pref_background_mode"
android:layout_width="match_parent"

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:linphone="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:orientation="vertical">
<org.linphone.settings.widget.SwitchSetting
android:id="@+id/pref_friendlist_subscribe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
linphone:title="@string/pref_friendlist_subscribe" />
<org.linphone.settings.widget.SwitchSetting
android:id="@+id/pref_contact_presence_native_contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
linphone:title="@string/pref_contact_sync_title"
linphone:subtitle="@string/pref_contact_sync_subtitle"/>
<org.linphone.settings.widget.SwitchSetting
android:id="@+id/pref_contact_organization"
android:layout_width="match_parent"
android:layout_height="wrap_content"
linphone:title="@string/pref_contact_display_contact_organization_title" />
</LinearLayout>
</ScrollView>

View file

@ -430,6 +430,12 @@
<string name="pref_bandwidth_limit">Bandwidth limit in kbits/s</string>
<string name="pref_video_codecs_title">Codecs</string>
<!-- Contact settings -->
<string name="pref_contact_sync_title">Presence information in native contact</string>
<string name="pref_contact_sync_subtitle">Inserting information shortcuts from the Linphone contact into native Android contacts</string>
<string name="pref_contact_title">Contact</string>
<string name="pref_contact_display_contact_organization_title">Display contact organization</string>
<!-- Call settings -->
<string name="pref_call_title">Call</string>
<string name="pref_device_ringtone">Use device ringtone</string>