Merge branch 'master' of git.linphone.org:linphone-android

This commit is contained in:
Erwan Croze 2016-08-08 12:28:14 +02:00
commit b9b8e5e419
47 changed files with 360 additions and 1576 deletions

View file

@ -207,8 +207,8 @@
<intent-filter><action android:name="android.intent.action.PHONE_STATE" /></intent-filter>
</receiver>
<receiver android:name="KeepAliveHandler" >
</receiver>
<!-- This one needs to be registered from application -->
<receiver android:name="KeepAliveReceiver"/>
<!-- Needed for push notification -->
<receiver android:name="org.linphone.gcm.GCMReceiver" android:permission="com.google.android.c2dm.permission.SEND" >

15
README
View file

@ -7,8 +7,8 @@ COMPILATION INSTRUCTIONS
To build liblinphone for Android, you must:
-------------------------------------------
0) download the Android sdk with platform-tools and tools updated to latest revision (at least API 16 is needed), then add both 'tools' and 'platform-tools' folders in your path.
1) download the Android ndk (version r11) from google and add it to your path (no symlink !!!).
0) download the Android sdk (API 23 at least) with platform-tools and tools updated to latest revision, then add both 'tools' and 'platform-tools' folders in your path.
1) download the Android ndk (version r11c or 12b) from google and add it to your path (no symlink !!!).
2) install yasm, nasm, ant, python, cmake and vim-common
On 64 bits linux systems you'll need the ia32-libs package
With the latest Debian (multiarch), you need this:
@ -27,11 +27,12 @@ To build liblinphone for Android, you must:
$ make mediastreamer2-sdk
8) (Optional) To generate a signed apk to publish on the Google Play, run
$ make release
Make sure you filled the ant.properties values for version.name, key.store and key.alias in order to correctly sign the generated apk.
You also may want to create a file name ant_password.properties with the following:
key.store.password=[your_password]
key.alias.password=[your_password]
If you don't, the passwords will be asked at the signing phase.
Make sure you filled the ant.properties values for version.name, key.store and key.alias in order to correctly sign the generated apk.
You also may want to create a file name ant_password.properties with the following:
key.store.password=[your_password]
key.alias.password=[your_password]
If you don't, the passwords will be asked at the signing phase.
9) (Optional) Once you compiled the libraries succesfully with 'make', you can reduce the compilation time using 'make quick': it will only generate a new APK from java files.
To run the tutorials:
--------------------

View file

@ -48,7 +48,7 @@
</condition>
<exec executable="bash" unless:set="has.crashed">
<arg value="-c"/>
<arg value="adb shell run-as org.linphone.tester cat /data/data/org.linphone.tester/files/junit-report.xml > liblinphone-junit-report.xml"/>
<arg value="adb shell cat /data/data/org.linphone.tester/files/junit-report.xml > liblinphone-junit-report.xml"/>
</exec>
<zip destfile="${archive.name}.zip">

View file

@ -136,6 +136,7 @@
android:inputType="textPersonName|textCapWords"/>
<TextView
android:id="@+id/contactOrganizationTitle"
android:text="@string/contact_organization"
style="@style/font13"
android:textAllCaps="true"

View file

@ -68,6 +68,8 @@
<bool name="allow_only_one_phone_number">false</bool>
<bool name="allow_only_one_sip_address">false</bool>
<bool name="display_contact_organization">true</bool>
<bool name="setup_cancel_move_to_back">false</bool>
<bool name="enable_call_notification">true</bool>

View file

@ -205,4 +205,5 @@
<string name="pref_use_lime_encryption_key">pref_use_lime_encryption_key</string>
<string name="pref_device_ringtone_key">pref_device_ringtone_key</string>
<string name="pref_auto_answer_key">pref_auto_answer_key</string>
<string name="pref_android_app_settings_key">pref_android_app_settings_key</string>
</resources>

View file

@ -313,6 +313,7 @@
<string name="pref_autostart">Start at boot time</string>
<string name="pref_incoming_call_timeout_title">Incoming call hangup (in seconds)</string>
<string name="pref_remote_provisioning_title">Remote provisioning</string>
<string name="pref_android_app_settings_title">Android app settings</string>
<string name="pref_primary_account_title">Primary account</string>
<string name="pref_display_name_title">Display name</string>
<string name="pref_user_name_title">Username</string>

View file

@ -3,7 +3,7 @@
<ContactsSource
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Change package ! -->
<!-- Change package, leave vnd.android.cursor.item/ before and .profile at the end. -->
<ContactsDataKind
android:mimeType="vnd.android.cursor.item/org.linphone.profile"
android:icon="@drawable/linphone_logo"

View file

@ -350,6 +350,11 @@
android:key="@string/pref_remote_provisioning_key"
android:inputType="textUri"
android:persistent="false"/>
<Preference
android:title="@string/pref_android_app_settings_title"
android:key="@string/pref_android_app_settings_key"
android:persistent="false"/>
</PreferenceCategory>

View file

@ -69,11 +69,11 @@ public class AboutFragment extends Fragment implements OnClickListener {
sendLogButton = view.findViewById(R.id.send_log);
sendLogButton.setOnClickListener(this);
sendLogButton.setVisibility(org.linphone.LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE);
sendLogButton.setVisibility(LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE);
resetLogButton = view.findViewById(R.id.reset_log);
resetLogButton.setOnClickListener(this);
resetLogButton.setVisibility(org.linphone.LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE);
resetLogButton.setVisibility(LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE);
mListener = new LinphoneCoreListenerBase() {
@Override
@ -145,7 +145,7 @@ public class AboutFragment extends Fragment implements OnClickListener {
lc.addListener(mListener);
}
if (org.linphone.LinphoneActivity.isInstanciated()) {
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().selectMenu(FragmentsAvailable.ABOUT);
}
@ -154,8 +154,8 @@ public class AboutFragment extends Fragment implements OnClickListener {
@Override
public void onClick(View v) {
if (org.linphone.LinphoneActivity.isInstanciated()) {
LinphoneCore lc = org.linphone.LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (LinphoneActivity.isInstanciated()) {
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (v == sendLogButton) {
if (lc != null) {
lc.uploadLogCollection();
@ -174,6 +174,4 @@ public class AboutFragment extends Fragment implements OnClickListener {
public void onDestroy() {
super.onDestroy();
}
}

View file

@ -53,8 +53,7 @@ public class AccountPreferencesFragment extends PreferencesListFragment {
mPrefs = LinphonePreferences.instance();
}
public void onCreate(Bundle savedInstanceState)
{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PreferenceScreen screen = getPreferenceScreen();
@ -69,7 +68,7 @@ public class AccountPreferencesFragment extends PreferencesListFragment {
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
}
public static boolean isEditTextEmpty(String s){
public static boolean isEditTextEmpty(String s) {
return s.equals(""); // really empty.
}

View file

@ -19,7 +19,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import java.util.List;
import org.linphone.compatibility.Compatibility;
import org.linphone.mediastream.Log;
import android.annotation.TargetApi;
@ -68,31 +67,31 @@ public class BluetoothManager extends BroadcastReceiver {
public BluetoothManager() {
isBluetoothConnected = false;
if (!ensureInit()) {
Log.w("BluetoothManager tried to init but LinphoneService not ready yet...");
Log.w("[Bluetooth] Manager tried to init but LinphoneService not ready yet...");
}
instance = this;
}
public void initBluetooth() {
if (!ensureInit()) {
Log.w("BluetoothManager tried to init bluetooth but LinphoneService not ready yet...");
Log.w("[Bluetooth] Manager tried to init bluetooth but LinphoneService not ready yet...");
return;
}
IntentFilter filter = new IntentFilter();
filter.addCategory(BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY + "." + BluetoothAssignedNumbers.PLANTRONICS);
filter.addAction(Compatibility.getAudioManagerEventForBluetoothConnectionStateChangedEvent());
filter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT);
mContext.registerReceiver(this, filter);
Log.d("Bluetooth receiver started");
Log.d("[Bluetooth] Receiver started");
startBluetooth();
}
private void startBluetooth() {
if (isBluetoothConnected) {
Log.e("Bluetooth already started");
Log.e("[Bluetooth] Already started, skipping...");
return;
}
@ -100,14 +99,14 @@ public class BluetoothManager extends BroadcastReceiver {
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
if (mProfileListener != null) {
Log.w("Bluetooth headset profile was already opened, let's close it");
Log.w("[Bluetooth] Headset profile was already opened, let's close it");
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
}
mProfileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
Log.d("Bluetooth headset connected");
Log.d("[Bluetooth] Headset connected");
mBluetoothHeadset = (BluetoothHeadset) proxy;
isBluetoothConnected = true;
}
@ -116,17 +115,17 @@ public class BluetoothManager extends BroadcastReceiver {
if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = null;
isBluetoothConnected = false;
Log.d("Bluetooth headset disconnected");
Log.d("[Bluetooth] Headset disconnected");
LinphoneManager.getInstance().routeAudioToReceiver();
}
}
};
boolean success = mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET);
if (!success) {
Log.e("Bluetooth getProfileProxy failed !");
Log.e("[Bluetooth] getProfileProxy failed !");
}
} else {
Log.w("Bluetooth interface disabled on device");
Log.w("[Bluetooth] Interface disabled on device");
}
}
@ -153,7 +152,7 @@ public class BluetoothManager extends BroadcastReceiver {
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled() && mAudioManager != null && mAudioManager.isBluetoothScoAvailableOffCall()) {
if (isBluetoothHeadsetAvailable()) {
if (mAudioManager != null && !mAudioManager.isBluetoothScoOn()) {
Log.d("Bluetooth sco off, let's start it");
Log.d("[Bluetooth] SCO off, let's start it");
mAudioManager.setBluetoothScoOn(true);
mAudioManager.startBluetoothSco();
}
@ -180,12 +179,12 @@ public class BluetoothManager extends BroadcastReceiver {
}
if (ok) {
if (retries > 0) {
Log.d("Bluetooth route ok after " + retries + " retries");
Log.d("[Bluetooth] Audio route ok after " + retries + " retries");
} else {
Log.d("Bluetooth route ok");
Log.d("[Bluetooth] Audio route ok");
}
} else {
Log.d("Bluetooth still not ok...");
Log.d("[Bluetooth] Audio route still not ok...");
}
return ok;
@ -212,7 +211,7 @@ public class BluetoothManager extends BroadcastReceiver {
break;
}
}
Log.d(isHeadsetConnected ? "Headset found, bluetooth audio route available" : "No headset found, bluetooth audio route unavailable");
Log.d(isHeadsetConnected ? "[Bluetooth] Headset found, bluetooth audio route available" : "[Bluetooth] No headset found, bluetooth audio route unavailable");
}
return isHeadsetConnected;
}
@ -237,12 +236,12 @@ public class BluetoothManager extends BroadcastReceiver {
mAudioManager.stopBluetoothSco();
mAudioManager.setBluetoothScoOn(false);
}
Log.w("Bluetooth sco disconnected!");
Log.w("[Bluetooth] SCO disconnected!");
}
}
public void stopBluetooth() {
Log.w("Stopping bluetooth...");
Log.w("[Bluetooth] Stopping...");
isBluetoothConnected = false;
disableBluetoothSCO();
@ -253,7 +252,7 @@ public class BluetoothManager extends BroadcastReceiver {
}
mBluetoothDevice = null;
Log.w("Bluetooth stopped!");
Log.w("[Bluetooth] Stopped!");
if (LinphoneManager.isInstanciated()) {
LinphoneManager.getInstance().routeAudioToReceiver();
@ -266,7 +265,7 @@ public class BluetoothManager extends BroadcastReceiver {
try {
mContext.unregisterReceiver(this);
Log.d("Bluetooth receiver stopped");
Log.d("[Bluetooth] Receiver stopped");
} catch (Exception e) {}
} catch (Exception e) {
Log.e(e);
@ -278,30 +277,30 @@ public class BluetoothManager extends BroadcastReceiver {
return;
String action = intent.getAction();
if (Compatibility.getAudioManagerEventForBluetoothConnectionStateChangedEvent().equals(action)) {
if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(action)) {
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 0);
if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
Log.d("Bluetooth sco state => connected");
Log.d("[Bluetooth] SCO state: connected");
// LinphoneManager.getInstance().audioStateChanged(AudioState.BLUETOOTH);
isScoConnected = true;
} else if (state == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
Log.d("Bluetooth sco state => disconnected");
Log.d("[Bluetooth] SCO state: disconnected");
// LinphoneManager.getInstance().audioStateChanged(AudioState.SPEAKER);
isScoConnected = false;
} else {
Log.d("Bluetooth sco state => " + state);
Log.d("[Bluetooth] SCO state: " + state);
}
}
else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, BluetoothAdapter.STATE_DISCONNECTED);
if (state == 0) {
Log.d("Bluetooth state => disconnected");
Log.d("[Bluetooth] State: disconnected");
stopBluetooth();
} else if (state == 2) {
Log.d("Bluetooth state => connected");
Log.d("[Bluetooth] State: connected");
startBluetooth();
} else {
Log.d("Bluetooth state => " + state);
Log.d("[Bluetooth] State: " + state);
}
}
else if (intent.getAction().equals(BluetoothHeadset.ACTION_VENDOR_SPECIFIC_HEADSET_EVENT)) {
@ -314,7 +313,7 @@ public class BluetoothManager extends BroadcastReceiver {
if (eventName.equals("BUTTON") && args.length >= 3) {
Integer buttonID = (Integer) args[1];
Integer mode = (Integer) args[2];
Log.d("Bluetooth event: " + command + " : " + eventName + ", id = " + buttonID + " (" + mode + ")");
Log.d("[Bluetooth] Event: " + command + " : " + eventName + ", id = " + buttonID + " (" + mode + ")");
}
}
}

View file

@ -119,6 +119,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
private boolean isConferenceRunning = false;
private LinphoneCoreListenerBase mListener;
private DrawerLayout sideMenu;
private boolean mProximitySensingEnabled;
public static CallActivity instance() {
return instance;
@ -800,8 +801,22 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
}
}
private void enableProximitySensing(boolean enable){
if (enable){
if (!mProximitySensingEnabled){
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
mProximitySensingEnabled = true;
}
}else{
if (mProximitySensingEnabled){
mSensorManager.unregisterListener(this);
mProximitySensingEnabled = false;
}
}
}
private void showAudioView() {
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
enableProximitySensing(true);
replaceFragmentVideoByAudio();
displayAudioCall();
showStatusBar();
@ -816,7 +831,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
}
refreshInCallActions();
mSensorManager.unregisterListener(this);
enableProximitySensing(false);
replaceFragmentAudioByVideo();
hideStatusBar();
}
@ -1173,7 +1188,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
handleViewIntent();
if (!isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
enableProximitySensing(true);
removeCallbacks();
}
}
@ -1223,10 +1238,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
mControlsHandler.removeCallbacks(mControls);
}
mControls = null;
if (!isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
mSensorManager.unregisterListener(this);
}
enableProximitySensing(false);
}
@Override
@ -1239,7 +1251,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
mControls = null;
mControlsHandler = null;
mSensorManager.unregisterListener(this);
enableProximitySensing(false);
unbindDrawables(findViewById(R.id.topLayout));
instance = null;
@ -1510,7 +1522,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
private void displayConference(boolean isInConf){
if(isInConf) {
mControlsLayout.setVisibility(View.VISIBLE);
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
enableProximitySensing(true);
mActiveCallHeader.setVisibility(View.GONE);
mNoCurrentCall.setVisibility(View.GONE);
conferenceList.removeAllViews();

View file

@ -44,6 +44,8 @@ import android.app.Activity;
import android.app.Dialog;
import android.app.Fragment;
import android.app.ProgressDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@ -387,7 +389,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
if(isEditMode) {
deleteChatBubble.setVisibility(View.VISIBLE);
if(message.isOutgoing()){
if (message.isOutgoing()) {
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
layoutParams.setMargins(100, 10, 10, 10);
@ -419,7 +421,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
}
});
if(messagesList.isItemChecked(position)) {
if (messagesList.isItemChecked(position)) {
deleteChatBubble.setChecked(true);
} else {
deleteChatBubble.setChecked(false);
@ -427,7 +429,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
rlayout.addView(v);
} else {
if(message.isOutgoing()){
if (message.isOutgoing()) {
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
layoutParams.setMargins(100, 10, 10, 10);
@ -448,7 +450,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
LinphoneAddress lAddress = null;
if(sipUri == null){
if (sipUri == null) {
initNewChatConversation();
} else {
try {
@ -477,7 +479,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
}
private void displayMessageList() {
if(chatRoom != null) {
if (chatRoom != null) {
if (adapter != null) {
adapter.refreshHistory();
} else {
@ -488,7 +490,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
}
private void displayChatHeader(LinphoneAddress address) {
if(contact != null) {
if (contact != null) {
contactName.setText(contact.getFullName());
} else if(address != null){
contactName.setText(LinphoneUtils.getAddressDisplayName(address));
@ -618,7 +620,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
String draft = getArguments().getString("messageDraft");
message.setText(draft);
if(!newChatConversation) {
if (!newChatConversation) {
initChatRoom(sipUri);
searchContactField.setVisibility(View.GONE);
resultContactsSearch.setVisibility(View.GONE);
@ -626,10 +628,10 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
}
}
private void selectAllList(boolean isSelectAll){
private void selectAllList(boolean isSelectAll) {
int size = messagesList.getAdapter().getCount();
for(int i=0; i<size; i++) {
messagesList.setItemChecked(i,isSelectAll);
for (int i = 0; i < size; i++) {
messagesList.setItemChecked(i, isSelectAll);
}
}
@ -642,8 +644,8 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
private void removeChats(){
int size = messagesList.getAdapter().getCount();
for(int i=0; i<size; i++) {
if(messagesList.isItemChecked(i)){
for (int i = 0; i < size; i++) {
if (messagesList.isItemChecked(i)) {
LinphoneChatMessage message = (LinphoneChatMessage) messagesList.getAdapter().getItem(i);
chatRoom.deleteMessage(message);
}
@ -827,7 +829,9 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
txt = message.getText();
}
if (txt != null) {
Compatibility.copyTextToClipboard(getActivity(), txt);
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = android.content.ClipData.newPlainText("Message", txt);
clipboard.setPrimaryClip(clip);
LinphoneActivity.instance().displayCustomToast(getString(R.string.text_copied_to_clipboard), Toast.LENGTH_SHORT);
}
}

View file

@ -1,117 +0,0 @@
package org.linphone;
import org.linphone.core.LinphoneChatMessage;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
/*
ChatMessage.java
Copyright (C) 2012 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.
*/
/**
* @author Sylvain Berfini
* @deprecated
*/
public class ChatMessage {
private String message;
private String timestamp;
private String url;
private boolean incoming;
private int status;
private int id;
private Bitmap image;
private boolean isRead;
public ChatMessage(int id, String message, byte[] rawImage, String timestamp, boolean incoming, int status, boolean read) {
super();
this.id = id;
this.message = message;
this.timestamp = timestamp;
this.incoming = incoming;
this.status = status;
this.image = rawImage != null ? BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length) : null;
this.isRead = read;
}
public ChatMessage(int id, String message, Bitmap image, String timestamp, boolean incoming, int status, boolean read) {
super();
this.id = id;
this.message = message;
this.timestamp = timestamp;
this.incoming = incoming;
this.status = status;
this.image = image;
this.isRead = read;
}
public int getId() {
return id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public boolean isIncoming() {
return incoming;
}
public void setIncoming(boolean incoming) {
this.incoming = incoming;
}
public void setStatus(int status) {
this.status = status;
}
public LinphoneChatMessage.State getStatus() {
return LinphoneChatMessage.State.fromInt(status);
}
public Bitmap getImage() {
return image;
}
public boolean isRead() {
return isRead;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String toString() {
return this.id + " : " + this.message + " (" + this.url + ") @ " + this.timestamp + ", read= " + this.isRead + ", incoming= " + this.incoming + ", status = " + this.status;
}
}

View file

@ -1,139 +0,0 @@
package org.linphone;
/*
Contact.java
Copyright (C) 2012 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 java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneFriend;
import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.net.Uri;
/**
* @author Sylvain Berfini
* @deprecated
*/
public class Contact implements Serializable {
private static final long serialVersionUID = 3790717505065723499L;
private String id;
private String name;
private transient Uri photoUri;
private transient Uri thumbnailUri;
private transient Bitmap photo;
private List<String> numbersOrAddresses;
private boolean hasFriends;
private LinphoneAddress address;
public Contact(String id, String name) {
super();
this.id = id;
this.name = name;
this.photoUri = null;
this.thumbnailUri = null;
this.hasFriends = false;
this.address = null;
}
public Contact(String id, LinphoneAddress address) {
super();
this.id = id;
this.name = LinphoneUtils.getAddressDisplayName(address);
this.photoUri = null;
this.thumbnailUri = null;
this.address = address;
}
public Contact(String id, String name, Uri photo, Uri thumbnail) {
super();
this.id = id;
this.name = name;
this.photoUri = photo;
this.thumbnailUri = thumbnail;
this.photo = null;
this.hasFriends = false;
this.address = null;
}
public Contact(String id, String name, Uri photo, Uri thumbnail, Bitmap picture) {
super();
this.id = id;
this.name = name;
this.photoUri = photo;
this.thumbnailUri = thumbnail;
this.photo = picture;
this.hasFriends = false;
this.address = null;
}
public boolean hasFriends() {
return hasFriends;
}
public String getID() {
return id;
}
public String getName() {
return name;
}
public LinphoneAddress getLinphoneAddress() {
return address;
}
public Uri getPhotoUri() {
return photoUri;
}
public Uri getThumbnailUri() {
return thumbnailUri;
}
public Bitmap getPhoto() {
return photo;
}
public List<String> getNumbersOrAddresses() {
if (numbersOrAddresses == null)
numbersOrAddresses = new ArrayList<String>();
return numbersOrAddresses;
}
public void refresh(ContentResolver cr) {
this.numbersOrAddresses = Compatibility.extractContactNumbersAndAddresses(id, cr);
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if(lc != null && lc.getFriendList() != null) {
for (LinphoneFriend friend :lc.getFriendList()){
if (id.equals(friend.getRefKey())) {
hasFriends = true;
this.numbersOrAddresses.add(friend.getAddress().asStringUriOnly());
}
}
}
this.name = Compatibility.refreshContactName(cr, id);
}
}

View file

@ -78,8 +78,9 @@ public class ContactDetailsFragment extends Fragment implements OnClickListener
deleteContact.setOnClickListener(this);
organization = (TextView) view.findViewById(R.id.contactOrganization);
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
String org = contact.getOrganization();
if (org != null && !org.isEmpty()) {
if (org != null && !org.isEmpty() && isOrgVisible) {
organization.setText(org);
} else {
organization.setVisibility(View.GONE);

View file

@ -204,9 +204,16 @@ public class ContactEditorFragment extends Fragment {
}
});
organization = (EditText) view.findViewById(R.id.contactOrganization);
if (!isNewContact) {
organization.setText(contact.getOrganization());
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
if (!isOrgVisible) {
organization.setVisibility(View.GONE);
view.findViewById(R.id.contactOrganizationTitle).setVisibility(View.GONE);
} else {
if (!isNewContact) {
organization.setText(contact.getOrganization());
}
}
if (!isNewContact) {

View file

@ -501,8 +501,9 @@ public class ContactsListFragment extends Fragment implements OnClickListener, O
}
TextView organization = (TextView) view.findViewById(R.id.contactOrganization);
boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization);
String org = contact.getOrganization();
if (org != null && !org.isEmpty()) {
if (org != null && !org.isEmpty() && isOrgVisible) {
organization.setText(org);
organization.setVisibility(View.VISIBLE);
} else {

View file

@ -21,10 +21,11 @@ package org.linphone;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneFriend;
@ -38,11 +39,13 @@ import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.Data;
interface ContactsUpdatedListener {
@ -228,14 +231,13 @@ public class ContactsManager extends ContentObserver {
contactsFetchTask.execute();
}
private class ContactsFetchTask extends AsyncTask<Void, List<LinphoneContact>, List<LinphoneContact>> {
@SuppressWarnings("unchecked")
protected List<LinphoneContact> doInBackground(Void... params) {
List<LinphoneContact> contacts = new ArrayList<LinphoneContact>();
if (hasContactsAccess()) {
Cursor c = Compatibility.getContactsCursor(contentResolver, null);
Cursor c = getContactsCursor(contentResolver);
if (c != null) {
while (c.moveToNext()) {
String id = c.getString(c.getColumnIndex(Data.CONTACT_ID));
@ -247,34 +249,37 @@ public class ContactsManager extends ContentObserver {
}
}
for (LinphoneFriend friend : LinphoneManager.getLc().getFriendList()) {
String refkey = friend.getRefKey();
if (refkey != null) {
boolean found = false;
for (LinphoneContact contact : contacts) {
if (refkey.equals(contact.getAndroidId())) {
// Native matching contact found, link the friend to it
contact.setFriend(friend);
found = true;
break;
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
for (LinphoneFriend friend : lc.getFriendList()) {
String refkey = friend.getRefKey();
if (refkey != null) {
boolean found = false;
for (LinphoneContact contact : contacts) {
if (refkey.equals(contact.getAndroidId())) {
// Native matching contact found, link the friend to it
contact.setFriend(friend);
found = true;
break;
}
}
}
if (!found) {
if (hasContactAccess) {
// If refkey != null and hasContactAccess but there isn't a native contact with this value, then this contact has been deleted. Let's do the same with the LinphoneFriend
LinphoneManager.getLc().removeFriend(friend);
} else {
// Refkey not null but no contact access => can't link it to native contact so display it on is own
LinphoneContact contact = new LinphoneContact();
contact.setFriend(friend);
contacts.add(contact);
if (!found) {
if (hasContactAccess) {
// If refkey != null and hasContactAccess but there isn't a native contact with this value, then this contact has been deleted. Let's do the same with the LinphoneFriend
lc.removeFriend(friend);
} else {
// Refkey not null but no contact access => can't link it to native contact so display it on is own
LinphoneContact contact = new LinphoneContact();
contact.setFriend(friend);
contacts.add(contact);
}
}
} else {
// No refkey so it's a standalone contact
LinphoneContact contact = new LinphoneContact();
contact.setFriend(friend);
contacts.add(contact);
}
} else {
// No refkey so it's a standalone contact
LinphoneContact contact = new LinphoneContact();
contact.setFriend(friend);
contacts.add(contact);
}
}
@ -364,4 +369,38 @@ public class ContactsManager extends ContentObserver {
public String getString(int resourceID) {
return context.getString(resourceID);
}
private Cursor getContactsCursor(ContentResolver cr) {
String req = "(" + Data.MIMETYPE + " = '" + CommonDataKinds.Phone.CONTENT_ITEM_TYPE
+ "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL "
+ " OR (" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL))";
String[] projection = new String[] { Data.CONTACT_ID, Data.DISPLAY_NAME };
String query = Data.DISPLAY_NAME + " IS NOT NULL AND (" + req + ")";
Cursor cursor = cr.query(Data.CONTENT_URI, projection, query, null, " lower(" + Data.DISPLAY_NAME + ") COLLATE UNICODE ASC");
if (cursor == null) {
return cursor;
}
MatrixCursor result = new MatrixCursor(cursor.getColumnNames());
Set<String> groupBy = new HashSet<String>();
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(Data.DISPLAY_NAME));
if (!groupBy.contains(name)) {
groupBy.add(name);
Object[] newRow = new Object[cursor.getColumnCount()];
int contactID = cursor.getColumnIndex(Data.CONTACT_ID);
int displayName = cursor.getColumnIndex(Data.DISPLAY_NAME);
newRow[contactID] = cursor.getString(contactID);
newRow[displayName] = cursor.getString(displayName);
result.addRow(newRow);
}
}
cursor.close();
return result;
}
}

View file

@ -1,47 +0,0 @@
package org.linphone;
/*
KeepAliveHandler.java
Copyright (C) 2013 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 org.linphone.core.LinphoneCoreFactory;
import org.linphone.mediastream.Log;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class KeepAliveHandler extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled();
LinphoneCoreFactory.instance().enableLogCollection(isDebugEnabled);
LinphoneCoreFactory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name));
Log.i("Keep alive handler invoked");
if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) {
//first refresh registers
LinphoneManager.getLc().refreshRegisters();
//make sure iterate will have enough time, device will not sleep until exit from this method
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
//Log.e("Cannot sleep for 2s", e); //TODO FIXME Crash since the log rework
}
}
}
}

View file

@ -18,12 +18,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.linphone;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.mediastream.Log;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
/*
* Purpose of this receiver is to disable keep alives when screen is off
@ -32,13 +36,37 @@ public class KeepAliveReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (!LinphoneService.isReady()) {
Log.i("Keep alive broadcast received while Linphone service not ready");
return;
} else {
if (intent.getAction().equalsIgnoreCase(Intent.ACTION_SCREEN_ON)) {
LinphoneManager.getLc().enableKeepAlive(true);
} else if (intent.getAction().equalsIgnoreCase(Intent.ACTION_SCREEN_OFF)) {
LinphoneManager.getLc().enableKeepAlive(false);
boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled();
LinphoneCoreFactory.instance().enableLogCollection(isDebugEnabled);
LinphoneCoreFactory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name));
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc == null) return;
String action = intent.getAction();
if (action == null) {
Log.i("[KeepAlive] Refresh registers");
lc.refreshRegisters();
//make sure iterate will have enough time, device will not sleep until exit from this method
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Log.e("Cannot sleep for 2s", e);
} finally {
//make sure the application will at least wakes up every 10 mn
Intent newIntent = new Intent(context, KeepAliveReceiver.class);
PendingIntent keepAlivePendingIntent = PendingIntent.getBroadcast(context, 0, newIntent, PendingIntent.FLAG_ONE_SHOT);
((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP
, SystemClock.elapsedRealtime() + 600000
, keepAlivePendingIntent);
}
} else if (action.equalsIgnoreCase(Intent.ACTION_SCREEN_ON)) {
Log.i("[KeepAlive] Screen is on, enable");
lc.enableKeepAlive(true);
} else if (action.equalsIgnoreCase(Intent.ACTION_SCREEN_OFF)) {
Log.i("[KeepAlive] Screen is off, disable");
lc.enableKeepAlive(false);
}
}
}

View file

@ -1166,6 +1166,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
checkAndRequestPermission(Manifest.permission.READ_CONTACTS, PERMISSIONS_REQUEST_CONTACTS);
}
private boolean willContactsPermissionBeAsked() {
return LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.READ_CONTACTS) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS);
}
public void checkAndRequestWriteContactsPermission() {
checkAndRequestPermission(Manifest.permission.WRITE_CONTACTS, 0);
}
@ -1274,6 +1278,9 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
ContactsManager.getInstance().enableContactsAccess();
ContactsManager.getInstance().fetchContactsAsync();
fetchedContactsOnce = true;
} else if (contacts != PackageManager.PERMISSION_GRANTED && !willContactsPermissionBeAsked()) {
ContactsManager.getInstance().fetchContactsAsync();
fetchedContactsOnce = true;
} else {
checkAndRequestReadContactsPermission();
}

View file

@ -419,6 +419,7 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
friend.edit();
friend.setFamilyName(lastName);
friend.setGivenName(firstName);
friend.setName(fullName);
for (LinphoneAddress address : friend.getAddresses()) {
friend.removeAddress(address);
@ -443,23 +444,21 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
friend.addPhoneNumber(noa.getValue());
}
}
friend.setName(fullName);
friend.done();
if (friend.getAddress() != null) {
if (lc.findFriendByAddress(friend.getAddress().asString()) == null) {
try {
lc.addFriend(friend);
if (!ContactsManager.getInstance().hasContactsAccess()) {
// This refresh is only needed if app has no contacts permission to refresh the list of LinphoneFriends.
// Otherwise contacts will be refreshed due to changes in native contact and the handler in ContactsManager
ContactsManager.getInstance().fetchContactsAsync();
}
} catch (LinphoneCoreException e) {
Log.e(e);
}
if (!friend.isAlreadyPresentInFriendList()) {
try {
LinphoneManager.getLcIfManagerNotDestroyedOrNull().addFriend(friend);
} catch (LinphoneCoreException e) {
Log.e(e);
}
}
if (!ContactsManager.getInstance().hasContactsAccess()) {
// This refresh is only needed if app has no contacts permission to refresh the list of LinphoneFriends.
// Otherwise contacts will be refreshed due to changes in native contact and the handler in ContactsManager
ContactsManager.getInstance().fetchContactsAsync();
}
}
public void save() {

View file

@ -36,10 +36,7 @@ import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.CallDirection;
import org.linphone.core.OpenH264DownloadHelperAction;
import org.linphone.core.OpenH264DownloadHelperListener;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneBuffer;
import org.linphone.core.LinphoneCall;
@ -57,13 +54,13 @@ import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreFactoryImpl;
import org.linphone.core.LinphoneCoreListener;
import org.linphone.core.LinphoneEvent;
import org.linphone.core.LinphoneFriend;
import org.linphone.core.LinphoneFriendList;
import org.linphone.core.LinphoneInfoMessage;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.core.OpenH264DownloadHelperListener;
import org.linphone.core.PayloadType;
import org.linphone.core.PresenceActivityType;
import org.linphone.core.PresenceModel;
@ -85,7 +82,6 @@ import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager.NameNotFoundException;
@ -105,8 +101,6 @@ import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.Vibrator;
import android.preference.CheckBoxPreference;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.telephony.TelephonyManager;
@ -150,6 +144,8 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
private boolean echoTesterIsRunning;
private int mLastNetworkType=-1;
private ConnectivityManager mConnectivityManager;
private BroadcastReceiver mKeepAliveReceiver;
private IntentFilter mKeepAliveIntentFilter;
private Handler mHandler = new Handler();
private WakeLock mIncallWakeLock;
private static List<LinphoneChatMessage> mPendingChatFileMessage;
@ -210,11 +206,8 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
private final String mErrorToneFile;
private final String mUserCertificatePath;
private ByteArrayInputStream mUploadingImageStream;
private Timer mTimer;
private BroadcastReceiver mKeepAliveReceiver = new KeepAliveReceiver();
private void routeAudioToSpeakerHelper(boolean speakerOn) {
Log.w("Routing audio to " + (speakerOn ? "speaker" : "earpiece") + ", disabling bluetooth audio route");
BluetoothManager.getInstance().disableBluetoothSCO();
@ -661,11 +654,12 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
public void restartLinphoneCore() {
destroyLinphoneCore();
startLibLinphone(mServiceContext);
IntentFilter lFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
lFilter.addAction(Intent.ACTION_SCREEN_OFF);
mServiceContext.registerReceiver(mKeepAliveReceiver, lFilter);
/*
You cannot receive this through components declared in manifests, only
by explicitly registering for it with Context.registerReceiver(). This is a protected intent that can only
be sent by the system.
*/
mServiceContext.registerReceiver(mKeepAliveReceiver, mKeepAliveIntentFilter);
sExited = false;
}
@ -698,6 +692,32 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
Log.e(e, "Cannot start linphone");
}
}
private void initPushNotificationsService() {
try {
Class<?> GCMRegistrar = Class.forName("com.google.android.gcm.GCMRegistrar");
GCMRegistrar.getMethod("checkDevice", Context.class).invoke(null, mServiceContext);
try {
GCMRegistrar.getMethod("checkManifest", Context.class).invoke(null, mServiceContext);
} catch (IllegalStateException e) {
Log.e("[Push Notification] No receiver found", e);
}
final String regId = (String)GCMRegistrar.getMethod("getRegistrationId", Context.class).invoke(null, mServiceContext);
String newPushSenderID = mServiceContext.getString(R.string.push_sender_id);
String currentPushSenderID = LinphonePreferences.instance().getPushNotificationRegistrationID();
if (regId.equals("") || currentPushSenderID == null || !currentPushSenderID.equals(newPushSenderID)) {
GCMRegistrar.getMethod("register", Context.class, String[].class).invoke(null, mServiceContext, new String[]{newPushSenderID});
Log.i("[Push Notification] Storing current sender id = " + newPushSenderID);
} else {
Log.i("[Push Notification] Already registered with id = " + regId);
LinphonePreferences.instance().setPushNotificationRegistrationID(regId);
}
} catch (java.lang.UnsupportedOperationException e) {
Log.i("[Push Notification] Not activated");
} catch (Exception e1) {
Log.i("[Push Notification] Assuming GCM jar is not provided.");
}
}
private synchronized void initLiblinphone(LinphoneCore lc) throws LinphoneCoreException {
mLc = lc;
@ -752,12 +772,18 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
mLc.migrateCallLogs();
if (mServiceContext.getResources().getBoolean(R.bool.enable_push_id)) {
Compatibility.initPushNotificationService(mServiceContext);
initPushNotificationsService();
}
IntentFilter lFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
lFilter.addAction(Intent.ACTION_SCREEN_OFF);
mServiceContext.registerReceiver(mKeepAliveReceiver, lFilter);
/*
You cannot receive this through components declared in manifests, only
by explicitly registering for it with Context.registerReceiver(). This is a protected intent that can only
be sent by the system.
*/
mKeepAliveIntentFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
mKeepAliveIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
mKeepAliveReceiver = new KeepAliveReceiver();
mServiceContext.registerReceiver(mKeepAliveReceiver, mKeepAliveIntentFilter);
updateNetworkReachability();
@ -1024,7 +1050,16 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
}
return null;
}
public void setAudioManagerInCallMode() {
if (mAudioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) {
Log.w("[AudioManager] already in MODE_IN_COMMUNICATION, skipping...");
return;
}
Log.d("[AudioManager] Mode: MODE_IN_COMMUNICATION");
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
}
@SuppressLint("Wakelock")
public void callState(final LinphoneCore lc,final LinphoneCall call, final State state, final String message) {
Log.i("New call state [",state,"]");
@ -1060,7 +1095,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
if (state == State.Connected) {
if (mLc.getCallsNb() == 1) {
requestAudioFocus();
Compatibility.setAudioManagerInCallMode(mAudioManager);
setAudioManagerInCallMode();
}
if (Hacks.needSoftvolume()) {
@ -1070,7 +1105,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
}
if (state == State.OutgoingEarlyMedia) {
Compatibility.setAudioManagerInCallMode(mAudioManager);
setAudioManagerInCallMode();
}
if (state == State.CallReleased || state == State.Error) {
@ -1150,7 +1185,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
public void startEcCalibration(LinphoneCoreListener l) throws LinphoneCoreException {
routeAudioToSpeaker();
Compatibility.setAudioManagerInCallMode((AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE));
setAudioManagerInCallMode();
Log.i("Set audio mode on 'Voice Communication'");
int oldVolume = mAudioManager.getStreamVolume(STREAM_VOICE_CALL);
int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
@ -1161,7 +1196,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
public int startEchoTester() throws LinphoneCoreException {
routeAudioToSpeaker();
Compatibility.setAudioManagerInCallMode((AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE));
setAudioManagerInCallMode();
Log.i("Set audio mode on 'Voice Communication'");
int oldVolume = mAudioManager.getStreamVolume(STREAM_VOICE_CALL);
int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL);
@ -1368,93 +1403,10 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
mAudioManager.adjustStreamVolume(LINPHONE_VOLUME_STREAM, i < 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
}
public static Boolean isProximitySensorNearby(final SensorEvent event) {
float threshold = 4.001f; // <= 4 cm is near
final float distanceInCm = event.values[0];
final float maxDistance = event.sensor.getMaximumRange();
Log.d("Proximity sensor report [",distanceInCm,"] , for max range [",maxDistance,"]");
if (maxDistance <= threshold) {
// Case binary 0/1 and short sensors
threshold = maxDistance;
}
return distanceInCm < threshold;
}
private static boolean sLastProximitySensorValueNearby;
private static Set<Activity> sProximityDependentActivities = new HashSet<Activity>();
private static SensorEventListener sProximitySensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.timestamp == 0) return; //just ignoring for nexus 1
sLastProximitySensorValueNearby = isProximitySensorNearby(event);
proximityNearbyChanged();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
};
private static void simulateProximitySensorNearby(Activity activity, boolean nearby) {
final Window window = activity.getWindow();
WindowManager.LayoutParams params = window.getAttributes();
View view = ((ViewGroup) window.getDecorView().findViewById(android.R.id.content)).getChildAt(0);
if (nearby) {
params.screenBrightness = 0.1f;
view.setVisibility(View.INVISIBLE);
Compatibility.hideNavigationBar(activity);
} else {
params.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
view.setVisibility(View.VISIBLE);
Compatibility.showNavigationBar(activity);
}
window.setAttributes(params);
}
private static void proximityNearbyChanged() {
boolean nearby = sLastProximitySensorValueNearby;
for (Activity activity : sProximityDependentActivities) {
simulateProximitySensorNearby(activity, nearby);
}
}
public static synchronized void startProximitySensorForActivity(Activity activity) {
if (sProximityDependentActivities.contains(activity)) {
Log.i("proximity sensor already active for " + activity.getLocalClassName());
return;
}
if (sProximityDependentActivities.isEmpty()) {
SensorManager sm = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
Sensor s = sm.getDefaultSensor(Sensor.TYPE_PROXIMITY);
if (s != null) {
sm.registerListener(sProximitySensorListener,s,SensorManager.SENSOR_DELAY_UI);
Log.i("Proximity sensor detected, registering");
}
} else if (sLastProximitySensorValueNearby){
simulateProximitySensorNearby(activity, true);
}
sProximityDependentActivities.add(activity);
}
public static synchronized void stopProximitySensorForActivity(Activity activity) {
sProximityDependentActivities.remove(activity);
simulateProximitySensorNearby(activity, false);
if (sProximityDependentActivities.isEmpty()) {
SensorManager sm = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
sm.unregisterListener(sProximitySensorListener);
sLastProximitySensorValueNearby = false;
}
}
public static synchronized LinphoneCore getLcIfManagerNotDestroyedOrNull() {
if (sExited || instance == null) {
// Can occur if the UI thread play a posted event but in the meantime the LinphoneManager was destroyed
// Ex: stop call and quickly terminate application.
Log.w("Trying to get linphone core while LinphoneManager already destroyed or not created");
return null;
}
return getLc();

View file

@ -114,7 +114,6 @@ public final class LinphoneService extends Service {
private Notification mCustomNotif;
private int mMsgNotifCount;
private PendingIntent mNotifContentIntent;
private PendingIntent mkeepAlivePendingIntent;
private String mNotificationTitle;
private boolean mDisableRegistrationStatus;
private LinphoneCoreListenerBase mListener;
@ -287,12 +286,11 @@ public final class LinphoneService extends Service {
}
//make sure the application will at least wakes up every 10 mn
Intent intent = new Intent(this, KeepAliveHandler.class);
mkeepAlivePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
((AlarmManager) this.getSystemService(Context.ALARM_SERVICE)).setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP
, SystemClock.elapsedRealtime()+600000
, 600000
, mkeepAlivePendingIntent);
Intent intent = new Intent(this, KeepAliveReceiver.class);
PendingIntent keepAlivePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
((AlarmManager) this.getSystemService(Context.ALARM_SERVICE)).setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP
, SystemClock.elapsedRealtime() + 600000
, keepAlivePendingIntent);
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
}
@ -622,6 +620,7 @@ public final class LinphoneService extends Service {
}
instance = null;
getContentResolver().unregisterContentObserver(ContactsManager.getInstance());
LinphoneManager.destroy();
// Make sure our notification is gone.
@ -629,8 +628,6 @@ public final class LinphoneService extends Service {
mNM.cancel(INCALL_NOTIF_ID);
mNM.cancel(MESSAGE_NOTIF_ID);
((AlarmManager) this.getSystemService(Context.ALARM_SERVICE)).cancel(mkeepAlivePendingIntent);
getContentResolver().unregisterContentObserver(ContactsManager.getInstance());
super.onDestroy();
}

View file

@ -431,7 +431,7 @@ public final class LinphoneUtils {
StringBuilder sb = new StringBuilder();
try {
p = Runtime.getRuntime().exec(new String[] { "logcat", "-d", "|", "grep", "`adb shell ps | grep org.linphone | cut -c10-15`" });
p = Runtime.getRuntime().exec(new String[] { "logcat", "-d", "|", "grep", "`adb shell ps | grep " + context.getPackageName() + " | cut -c10-15`" });
br = new BufferedReader(new InputStreamReader(p.getInputStream()), 2048);
String line;

View file

@ -1,6 +0,0 @@
package org.linphone;
public class OpenGLESDisplay {
public static native void init(int ptr, int width, int height);
public static native void render(int ptr);
}

View file

@ -35,8 +35,8 @@ import org.linphone.core.PayloadType;
import org.linphone.mediastream.Log;
import org.linphone.mediastream.Version;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
import org.linphone.tools.OpenH264DownloadHelper;
import org.linphone.purchase.InAppPurchaseActivity;
import org.linphone.tools.OpenH264DownloadHelper;
import org.linphone.ui.LedPreference;
import org.linphone.ui.PreferencesListFragment;
@ -44,11 +44,14 @@ import android.app.AlertDialog;
import android.app.FragmentManager;
import android.content.DialogInterface;
import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.preference.CheckBoxPreference;
@ -59,6 +62,7 @@ import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.provider.Settings;
/**
* @author Sylvain Berfini
@ -713,7 +717,7 @@ public class SettingsFragment extends PreferencesListFragment {
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean enable = (Boolean) newValue;
try {
if (enable && Version.getCpuAbis().contains("armeabi-v7a") && !Version.getCpuAbis().contains("x86")
if (enable && Version.getCpuAbis().contains("armeabi-v7a") && !Version.getCpuAbis().contains("x86")
&& pt.getMime().equals("H264") && !mCodecDownloader.isCodecFound()) {
mCodecDownloader.setOpenH264HelperListener(LinphoneManager.getInstance().getOpenH264HelperListener());
mCodecDownloader.setUserData(0,LinphoneManager.getInstance().getContext());
@ -721,18 +725,17 @@ public class SettingsFragment extends PreferencesListFragment {
AlertDialog.Builder builder = new AlertDialog.Builder(LinphoneManager.getInstance().getContext());
builder.setCancelable(false);
AlertDialog.Builder show = builder.setMessage("Do you agree to download "
+ mCodecDownloader.getLicenseMessage()).setPositiveButton("Yes", new DialogInterface.OnClickListener(){
builder.setMessage("Do you agree to download " + mCodecDownloader.getLicenseMessage()).setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE)
mCodecDownloader.downloadCodec();
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener(){
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_NEGATIVE){
if (which == DialogInterface.BUTTON_NEGATIVE) {
// Disable H264
}
}
@ -1025,7 +1028,6 @@ public class SettingsFragment extends PreferencesListFragment {
// Disable UPnP if ICE si enabled, or disable ICE if UPnP is enabled
CheckBoxPreference ice = (CheckBoxPreference) findPreference(getString(R.string.pref_ice_enable_key));
CheckBoxPreference turn = (CheckBoxPreference) findPreference(getString(R.string.pref_turn_enable_key));
CheckBoxPreference upnp = (CheckBoxPreference) findPreference(getString(R.string.pref_upnp_enable_key));
ice.setChecked(mPrefs.isIceEnabled());
turn.setChecked(mPrefs.isTurnEnabled());
@ -1067,8 +1069,6 @@ public class SettingsFragment extends PreferencesListFragment {
findPreference(getString(R.string.pref_ice_enable_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
CheckBoxPreference upnp = (CheckBoxPreference) findPreference(getString(R.string.pref_upnp_enable_key));
boolean value = (Boolean) newValue;
mPrefs.setIceEnabled((Boolean) newValue);
return true;
}
@ -1077,8 +1077,6 @@ public class SettingsFragment extends PreferencesListFragment {
findPreference(getString(R.string.pref_turn_enable_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
CheckBoxPreference upnp = (CheckBoxPreference) findPreference(getString(R.string.pref_upnp_enable_key));
boolean value = (Boolean) newValue;
mPrefs.setTurnEnabled((Boolean) newValue);
return true;
}
@ -1087,7 +1085,6 @@ public class SettingsFragment extends PreferencesListFragment {
findPreference(getString(R.string.pref_upnp_enable_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
CheckBoxPreference ice = (CheckBoxPreference) findPreference(getString(R.string.pref_ice_enable_key));
boolean value = (Boolean) newValue;
mPrefs.setUpnpEnabled(value);
return true;
@ -1197,6 +1194,24 @@ public class SettingsFragment extends PreferencesListFragment {
return true;
}
});
findPreference(getString(R.string.pref_android_app_settings_key)).setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
synchronized (SettingsFragment.this) {
Context context = SettingsFragment.this.getActivity();
Intent i = new Intent();
i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setData(Uri.parse("package:" + context.getPackageName()));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(i);
}
return true;
}
});
findPreference(getString(R.string.pref_display_name_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override

View file

@ -19,6 +19,13 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.OpenH264DownloadHelperListener;
import org.linphone.core.PayloadType;
import org.linphone.tools.OpenH264DownloadHelper;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Handler;
@ -29,15 +36,6 @@ import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.OpenH264DownloadHelperListener;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.PayloadType;
import org.linphone.tools.OpenH264DownloadHelper;
/**
* @author Erwan CROZE
*/

View file

@ -18,11 +18,11 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import org.linphone.R;
import org.linphone.compatibility.Compatibility;
import android.app.Fragment;
import android.os.Bundle;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
@ -53,7 +53,7 @@ public class LinphoneLoginFragment extends Fragment implements OnClickListener,
password = (EditText) view.findViewById(R.id.assistant_password);
password.addTextChangedListener(this);
forgotPassword = (TextView) view.findViewById(R.id.forgot_password);
forgotPassword.setText(Html.fromHtml("<a href=\"" + url + "\"'>"+ getString(R.string.forgot_password) + "</a>"));
forgotPassword.setText(Compatibility.fromHtml("<a href=\"" + url + "\"'>"+ getString(R.string.forgot_password) + "</a>"));
forgotPassword.setMovementMethod(LinkMovementMethod.getInstance());
displayName = (EditText) view.findViewById(R.id.assistant_display_name);
apply = (Button) view.findViewById(R.id.assistant_apply);

View file

@ -1,68 +0,0 @@
package org.linphone.compatibility;
import org.linphone.LinphonePreferences;
import org.linphone.R;
import org.linphone.mediastream.Log;
import android.annotation.TargetApi;
import android.content.Context;
import android.media.AudioManager;
/*
ApiEightPlus.java
Copyright (C) 2012 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.
*/
/**
* @author Sylvain Berfini
*/
@TargetApi(8)
public class ApiEightPlus {
public static void initPushNotificationService(Context context) {
try {
Class<?> GCMRegistrar = Class.forName("com.google.android.gcm.GCMRegistrar");
// Starting the push notification service
GCMRegistrar.getMethod("checkDevice", Context.class).invoke(null, context);
try {
GCMRegistrar.getMethod("checkManifest", Context.class).invoke(null, context);
} catch (IllegalStateException e){
Log.e("Push notification: No receiver found",e);
}
final String regId = (String)GCMRegistrar.getMethod("getRegistrationId", Context.class).invoke(null, context);
String newPushSenderID = context.getString(R.string.push_sender_id);
String currentPushSenderID = LinphonePreferences.instance().getPushNotificationRegistrationID();
if (regId.equals("") || currentPushSenderID == null || !currentPushSenderID.equals(newPushSenderID)) {
GCMRegistrar.getMethod("register", Context.class, String[].class).invoke(null, context, new String[]{newPushSenderID});
Log.d("Push Notification: storing current sender id = " + newPushSenderID);
} else {
Log.d("Push Notification: already registered with id = " + regId);
LinphonePreferences.instance().setPushNotificationRegistrationID(regId);
}
} catch (java.lang.UnsupportedOperationException e) {
Log.i("Push Notification: not activated");
} catch (Exception e1) {
//assume the jar is not provided
Log.i("Push Notification: assuming GCM jar is not provided.");
}
}
@SuppressWarnings("deprecation")
public static String getAudioManagerEventForBluetoothConnectionStateChangedEvent() {
return AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED;
}
}

View file

@ -3,19 +3,15 @@ package org.linphone.compatibility;
import java.util.ArrayList;
import org.linphone.R;
import org.linphone.mediastream.Log;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
@ -119,21 +115,6 @@ public class ApiElevenPlus {
return notif;
}
public static void copyTextToClipboard(Context context, String msg) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = android.content.ClipData.newPlainText("Message", msg);
clipboard.setPrimaryClip(clip);
}
public static void setAudioManagerInCallMode(AudioManager manager) {
if (manager.getMode() == AudioManager.MODE_IN_COMMUNICATION) {
Log.w("---AudioManager: already in MODE_IN_COMMUNICATION, skipping...");
return;
}
Log.d("---AudioManager: set mode to MODE_IN_COMMUNICATION");
manager.setMode(AudioManager.MODE_IN_COMMUNICATION);
}
public static Intent prepareAddContactIntent(String displayName, String sipUri) {
Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);

View file

@ -1,406 +0,0 @@
package org.linphone.compatibility;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.linphone.LinphoneContact;
import org.linphone.R;
import org.linphone.core.LinphoneAddress;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.media.AudioManager;
import android.net.Uri;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.support.v4.app.NotificationCompat;
import android.text.ClipboardManager;
import android.text.TextUtils;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
/*
ApiFivePlus.java
Copyright (C) 2012 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.
*/
/**
* @author Sylvain Berfini
*/
@SuppressWarnings("deprecation")
@TargetApi(5)
public class ApiFivePlus {
public static void overridePendingTransition(Activity activity, int idAnimIn, int idAnimOut) {
activity.overridePendingTransition(idAnimIn, idAnimOut);
}
public static Intent prepareAddContactIntent(String displayName, String sipUri) {
Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
intent.putExtra(ContactsContract.Intents.Insert.NAME, displayName);
// VoIP field not available, we store the address in the IM field
intent.putExtra(ContactsContract.Intents.Insert.IM_HANDLE, sipUri);
intent.putExtra(ContactsContract.Intents.Insert.IM_PROTOCOL, "sip");
return intent;
}
public static Intent prepareEditContactIntent(int id) {
Intent intent = new Intent(Intent.ACTION_EDIT, Contacts.CONTENT_URI);
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id);
intent.setData(contactUri);
return intent;
}
public static Intent prepareEditContactIntentWithSipAddress(int id, String sipUri) {
Intent intent = new Intent(Intent.ACTION_EDIT, Contacts.CONTENT_URI);
Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id);
intent.setData(contactUri);
// VoIP field not available, we store the address in the IM field
intent.putExtra(ContactsContract.Intents.Insert.IM_HANDLE, sipUri);
intent.putExtra(ContactsContract.Intents.Insert.IM_PROTOCOL, "sip");
return intent;
}
public static List<String> extractContactNumbersAndAddresses(String id, ContentResolver cr) {
List<String> list = new ArrayList<String>();
Uri uri = Data.CONTENT_URI;
String[] projection = {ContactsContract.CommonDataKinds.Im.DATA};
// IM addresses
String selection = new StringBuilder()
.append(Data.CONTACT_ID).append(" = ? AND ")
.append(Data.MIMETYPE).append(" = '")
.append(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
.append("' AND lower(")
.append(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL)
.append(") = 'sip'")
.toString();
Cursor c = cr.query(uri, projection, selection, new String[]{id}, null);
if (c != null) {
int nbId = c.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA);
while (c.moveToNext()) {
list.add("sip:" + c.getString(nbId));
}
c.close();
}
// Phone Numbers
c = cr.query(Phone.CONTENT_URI, new String[]{Phone.NUMBER}, Phone.CONTACT_ID + " = " + id, null, null);
if (c != null) {
while (c.moveToNext()) {
String number = c.getString(c.getColumnIndex(Phone.NUMBER));
list.add(number);
}
c.close();
}
return list;
}
public static Cursor getContactsCursor(ContentResolver cr, List<String> ids) {
String req = Data.MIMETYPE + " = '" + CommonDataKinds.Phone.CONTENT_ITEM_TYPE
+ "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL";
req += " OR (" + Contacts.Data.MIMETYPE + " = '" + CommonDataKinds.Im.CONTENT_ITEM_TYPE
+ "' AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip')";
if(ids != null){
String s = TextUtils.join(",", ids);
req += " OR (" + Data.CONTACT_ID + " IN (" + s + "))";
}
return getGeneralContactCursor(cr, req, true);
}
public static Cursor getSIPContactsCursor(ContentResolver cr, List<String> ids) {
String req = null;
req = Contacts.Data.MIMETYPE + " = '" + CommonDataKinds.Im.CONTENT_ITEM_TYPE
+ "' AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip'";
if(ids != null){
String s = TextUtils.join(",", ids);
req += " OR (" + Data.CONTACT_ID + " IN (" + s + "))";
}
return getGeneralContactCursor(cr, req, true);
}
private static Cursor getSIPContactCursor(ContentResolver cr, String id) {
String req = null;
req = Contacts.Data.MIMETYPE + " = '" + CommonDataKinds.Im.CONTENT_ITEM_TYPE
+ " AND lower(" + CommonDataKinds.Im.CUSTOM_PROTOCOL + ") = 'sip' AND "
+ android.provider.ContactsContract.CommonDataKinds.Im.DATA + " LIKE '" + id + "'";
return getGeneralContactCursor(cr, req, false);
}
public static Cursor getGeneralContactCursor(ContentResolver cr, String select, boolean shouldGroupBy) {
String[] projection = new String[] { Data.CONTACT_ID, Data.DISPLAY_NAME };
String query;
query = Data.DISPLAY_NAME + " IS NOT NULL AND (" + select + ")";
Cursor cursor = cr.query(Data.CONTENT_URI, projection, query, null, " lower(" + Data.DISPLAY_NAME + ") COLLATE UNICODE ASC");
if (!shouldGroupBy || cursor == null) {
return cursor;
}
MatrixCursor result = new MatrixCursor(cursor.getColumnNames());
Set<String> groupBy = new HashSet<String>();
while (cursor.moveToNext()) {
String name = cursor.getString(getCursorDisplayNameColumnIndex(cursor));
if (!groupBy.contains(name)) {
groupBy.add(name);
Object[] newRow = new Object[cursor.getColumnCount()];
int contactID = cursor.getColumnIndex(Data.CONTACT_ID);
int displayName = cursor.getColumnIndex(Data.DISPLAY_NAME);
newRow[contactID] = cursor.getString(contactID);
newRow[displayName] = cursor.getString(displayName);
result.addRow(newRow);
}
}
cursor.close();
return result;
}
public static int getCursorDisplayNameColumnIndex(Cursor cursor) {
return cursor.getColumnIndex(Data.DISPLAY_NAME);
}
public static LinphoneContact getContact(ContentResolver cr, Cursor cursor, int position) {
try {
if(cursor != null) {
cursor.moveToFirst();
boolean success = cursor.move(position);
if (!success)
return null;
String id = cursor.getString(cursor.getColumnIndex(Data.CONTACT_ID));
String name = getContactDisplayName(cursor);
Uri thumbnail = getContactPictureUri(id);
Uri photo = getContactPhotoUri(id);
InputStream input = getContactPictureInputStream(cr, id);
LinphoneContact contact = new LinphoneContact();
contact.setAndroidId(id);
contact.setFullName(name);
if (input != null) {
contact.setPhotoUri(photo);
contact.setThumbnailUri(thumbnail);
}
return contact;
} else {
return null;
}
} catch (Exception e) {
}
return null;
}
public static InputStream getContactPictureInputStream(ContentResolver cr, String id) {
Uri person = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(id));
return Contacts.openContactPhotoInputStream(cr, person);
}
private static String getContactDisplayName(Cursor cursor) {
return cursor.getString(cursor.getColumnIndex(Data.DISPLAY_NAME));
}
private static Uri getContactPictureUri(String id) {
Uri person = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(id));
return Uri.withAppendedPath(person, Contacts.Photo.CONTENT_DIRECTORY);
}
private static Uri getContactPhotoUri(String id) {
Uri person = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(id));
return Uri.withAppendedPath(person, Contacts.Photo.DISPLAY_PHOTO);
}
public static Uri findUriPictureOfContactAndSetDisplayName(LinphoneAddress address, ContentResolver cr) {
String username = address.getUserName();
String domain = address.getDomain();
String sipUri = username + "@" + domain;
Cursor cursor = getSIPContactCursor(cr, sipUri);
if(cursor != null) {
LinphoneContact contact = getContact(cr, cursor, 0);
if (contact != null && contact.getNumbersOrAddresses().contains(sipUri)) {
address.setDisplayName(contact.getFullName());
cursor.close();
return contact.getPhotoUri();
}
cursor.close();
}
return null;
}
public static String refreshContactName(ContentResolver cr, String id) {
Cursor cursor = getGeneralContactCursor(cr, Data.CONTACT_ID + " = '" + id + "'", false);
if (cursor != null && cursor.moveToFirst()) {
String contactDisplayName = getContactDisplayName(cursor);
cursor.close();
return contactDisplayName;
}
return null;
}
public static Notification createMessageNotification(Context context, String title, String msg, PendingIntent intent) {
Notification notif = new Notification();
notif.icon = R.drawable.topbar_chat_notification;
notif.iconLevel = 0;
notif.when = System.currentTimeMillis();
notif.flags &= Notification.FLAG_ONGOING_EVENT;
notif.defaults |= Notification.DEFAULT_VIBRATE;
notif.defaults |= Notification.DEFAULT_SOUND;
notif.defaults |= Notification.DEFAULT_LIGHTS;
return notif;
}
public static Notification createInCallNotification(Context context, String title, String msg, int iconID, PendingIntent intent) {
NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(iconID)
.setContentTitle(title)
.setContentText(msg)
.setContentIntent(intent);
return notifBuilder.build();
}
public static void setPreferenceChecked(Preference preference, boolean checked) {
((CheckBoxPreference) preference).setChecked(checked);
}
public static boolean isPreferenceChecked(Preference preference) {
return ((CheckBoxPreference) preference).isChecked();
}
public static void copyTextToClipboard(Context context, String msg) {
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setText(msg);
}
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress) {
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Im.DATA, sipAddress)
.withValue(ContactsContract.CommonDataKinds.Im.TYPE, ContactsContract.CommonDataKinds.Im.TYPE_CUSTOM)
.withValue(ContactsContract.CommonDataKinds.Im.LABEL, context.getString(R.string.addressbook_label))
.build()
);
}
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress, String rawContactID) {
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactID)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Im.DATA, sipAddress)
.withValue(ContactsContract.CommonDataKinds.Im.TYPE, ContactsContract.CommonDataKinds.Im.TYPE_CUSTOM)
.withValue(ContactsContract.CommonDataKinds.Im.LABEL, context.getString(R.string.addressbook_label))
.build()
);
}
public static void updateSipAddressForContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String newSipAddress, String contactID) {
String select = ContactsContract.Data.CONTACT_ID + "=? AND "
+ ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE + "' AND "
+ ContactsContract.CommonDataKinds.Im.DATA + "=?";
String[] args = new String[] { String.valueOf(contactID), oldSipAddress };
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(select, args)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Im.DATA, newSipAddress)
.build()
);
}
public static void deleteSipAddressFromContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String contactID) {
String select = ContactsContract.Data.CONTACT_ID + "=? AND "
+ ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE + "' AND "
+ ContactsContract.CommonDataKinds.Im.DATA + "=?";
String[] args = new String[] { String.valueOf(contactID), oldSipAddress };
ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
.withSelection(select, args)
.build()
);
}
public static void removeGlobalLayoutListener(ViewTreeObserver viewTreeObserver, OnGlobalLayoutListener keyboardListener) {
viewTreeObserver.removeGlobalOnLayoutListener(keyboardListener);
}
public static void setAudioManagerInCallMode(AudioManager manager) {
/* Do not use MODE_IN_CALL, because it is reserved to GSM. This is causing conflicts on audio system resulting in silenced audio.*/
//manager.setMode(AudioManager.MODE_IN_CALL);
}
public static Notification createNotification(Context context, String title, String message, int icon, int level, PendingIntent intent, boolean isOngoingEvent) {
NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(icon, level)
.setContentTitle(title)
.setContentText(message)
.setContentIntent(intent);
return notifBuilder.build();
}
public static Notification createSimpleNotification(Context context, String title, String text, PendingIntent intent) {
NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.linphone_logo)
.setContentTitle(title)
.setContentText(text)
.setContentIntent(intent);
Notification notif = notifBuilder.build();
notif.defaults |= Notification.DEFAULT_VIBRATE;
notif.defaults |= Notification.DEFAULT_SOUND;
notif.defaults |= Notification.DEFAULT_LIGHTS;
return notif;
}
}

View file

@ -1,53 +0,0 @@
package org.linphone.compatibility;
import android.annotation.TargetApi;
import android.app.Activity;
import android.media.AudioManager;
import android.preference.Preference;
import android.preference.TwoStatePreference;
import android.view.View;
/*
ApiFourteenPlus.java
Copyright (C) 2012 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.
*/
/**
* @author Sylvain Berfini
*/
@TargetApi(14)
public class ApiFourteenPlus {
public static void setPreferenceChecked(Preference preference, boolean checked) {
((TwoStatePreference) preference).setChecked(checked);
}
public static boolean isPreferenceChecked(Preference preference) {
return ((TwoStatePreference) preference).isChecked();
}
public static void hideNavigationBar(Activity activity) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
public static void showNavigationBar(Activity activity) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
public static String getAudioManagerEventForBluetoothConnectionStateChangedEvent() {
return AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED;
}
}

View file

@ -1,195 +0,0 @@
package org.linphone.compatibility;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneContact;
import org.linphone.R;
import org.linphone.core.LinphoneAddress;
import android.annotation.TargetApi;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.text.TextUtils;
/*
ApiNinePlus.java
Copyright (C) 2012 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.
*/
/**
* @author Sylvain Berfini
*/
@TargetApi(9)
public class ApiNinePlus {
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress) {
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.SipAddress.DATA, sipAddress)
.withValue(CommonDataKinds.SipAddress.TYPE, CommonDataKinds.SipAddress.TYPE_CUSTOM)
.withValue(CommonDataKinds.SipAddress.LABEL, context.getString(R.string.addressbook_label))
.build()
);
}
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress, String rawContactID) {
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactID)
.withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.SipAddress.DATA, sipAddress)
.withValue(CommonDataKinds.SipAddress.TYPE, CommonDataKinds.SipAddress.TYPE_CUSTOM)
.withValue(CommonDataKinds.SipAddress.LABEL, context.getString(R.string.addressbook_label))
.build()
);
}
public static void updateSipAddressForContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String newSipAddress, String contactID) {
String select = ContactsContract.Data.CONTACT_ID + "=? AND "
+ ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' AND "
+ ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + "=?";
String[] args = new String[] { String.valueOf(contactID), oldSipAddress };
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(select, args)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS, newSipAddress)
.build()
);
}
public static void deleteSipAddressFromContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String contactID) {
String select = ContactsContract.Data.CONTACT_ID + "=? AND "
+ ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' AND "
+ ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + "=? ";
String[] args = new String[] { String.valueOf(contactID), oldSipAddress };
ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
.withSelection(select, args)
.build()
);
}
public static List<String> extractContactNumbersAndAddresses(String id, ContentResolver cr) {
List<String> list = new ArrayList<String>();
Uri uri = Data.CONTENT_URI;
String[] projection;
// SIP addresses
String selection2 = new StringBuilder()
.append(Data.CONTACT_ID)
.append(" = ? AND ")
.append(Data.MIMETYPE)
.append(" = '")
.append(ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
.append("'")
.toString();
projection = new String[] {ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS};
Cursor c = cr.query(uri, projection, selection2, new String[]{id}, null);
if (c != null) {
int nbid = c.getColumnIndex(ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS);
while (c.moveToNext()) {
list.add("sip:" + c.getString(nbid));
}
c.close();
}
// Phone Numbers
c = cr.query(Phone.CONTENT_URI, new String[] { Phone.NUMBER }, Phone.CONTACT_ID + " = " + id, null, null);
if (c != null) {
while (c.moveToNext()) {
String number = c.getString(c.getColumnIndex(Phone.NUMBER));
list.add(number);
}
c.close();
}
return list;
}
public static Cursor getContactsCursor(ContentResolver cr, String search, List<String> ids) {
String req;
if(ids != null && ids.size() > 0) {
req = "(" + Data.MIMETYPE + " = '" + CommonDataKinds.Phone.CONTENT_ITEM_TYPE
+ "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL "
+ " OR (" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL)"
+ " OR (" + Data.CONTACT_ID + " IN (" + TextUtils.join(" , ", ids) + ")))";
} else {
req = "(" + Data.MIMETYPE + " = '" + CommonDataKinds.Phone.CONTENT_ITEM_TYPE
+ "' AND " + CommonDataKinds.Phone.NUMBER + " IS NOT NULL "
+ " OR (" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL))";
}
if (search != null) {
req += " AND " + Data.DISPLAY_NAME + " LIKE '%" + search + "%'";
}
return ApiFivePlus.getGeneralContactCursor(cr, req, true);
}
public static Cursor getSIPContactsCursor(ContentResolver cr, String search, List<String> ids) {
String req = "(" + Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " IS NOT NULL) ";
if(ids != null && ids.size() > 0) {
req += " OR (" + Data.CONTACT_ID + " IN (" + TextUtils.join(" , ", ids) + "))";
}
if (search != null) {
req += " AND " + Data.DISPLAY_NAME + " LIKE '%" + search + "%'";
}
return ApiFivePlus.getGeneralContactCursor(cr, req, true);
}
private static Cursor getSIPContactCursor(ContentResolver cr, String id) {
String req = null;
req = Contacts.Data.MIMETYPE + " = '" + CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
+ "' AND " + ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS + " LIKE '" + id + "'";
return ApiFivePlus.getGeneralContactCursor(cr, req, false);
}
public static Uri findUriPictureOfContactAndSetDisplayName(LinphoneAddress address, ContentResolver cr) {
String username = address.getUserName();
String domain = address.getDomain();
String sipUri = username + "@" + domain;
Cursor cursor = getSIPContactCursor(cr, sipUri);
LinphoneContact contact = ApiFivePlus.getContact(cr, cursor, 0);
if (contact != null && contact.getNumbersOrAddresses().contains(sipUri)) {
address.setDisplayName(contact.getFullName());
cursor.close();
return contact.getPhotoUri();
}
cursor.close();
return null;
}
}

View file

@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@TargetApi(16)
public class ApiSixteenPlus {
@SuppressWarnings("deprecation")
public static Notification createMessageNotification(Context context,
int msgCount, String msgSender, String msg, Bitmap contactIcon,
PendingIntent intent) {

View file

@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@TargetApi(21)
public class ApiTwentyOnePlus {
@SuppressWarnings("deprecation")
public static Notification createMessageNotification(Context context,
int msgCount, String msgSender, String msg, Bitmap contactIcon,
PendingIntent intent) {

View file

@ -17,191 +17,54 @@ 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 java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.linphone.LinphoneContact;
import org.linphone.core.LinphoneAddress;
import org.linphone.mediastream.Version;
import android.app.Activity;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.Uri;
import android.os.PowerManager;
import android.preference.Preference;
import android.provider.Settings;
import android.text.Html;
import android.text.Spanned;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
/**
* @author Sylvain Berfini
*/
public class Compatibility {
public static void overridePendingTransition(Activity activity, int idAnimIn, int idAnimOut) {
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
ApiFivePlus.overridePendingTransition(activity, idAnimIn, idAnimOut);
}
}
public static Intent prepareAddContactIntent(String displayName, String sipUri) {
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
return ApiElevenPlus.prepareAddContactIntent(displayName, sipUri);
} else {
return ApiFivePlus.prepareAddContactIntent(displayName, sipUri);
}
}
public static Intent prepareEditContactIntent(int id) {
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
return ApiFivePlus.prepareEditContactIntent(id);
}
return null;
}
public static Intent prepareEditContactIntentWithSipAddress(int id, String sipAddress) {
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
return ApiElevenPlus.prepareEditContactIntentWithSipAddress(id, sipAddress);
} else {
return ApiFivePlus.prepareEditContactIntent(id);
}
}
public static List<String> extractContactNumbersAndAddresses(String id, ContentResolver cr) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
return ApiNinePlus.extractContactNumbersAndAddresses(id, cr);
} else {
return ApiFivePlus.extractContactNumbersAndAddresses(id, cr);
}
}
public static List<String> extractContactImAddresses(String id, ContentResolver cr) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
return ApiFivePlus.extractContactNumbersAndAddresses(id, cr);
} else {
return null;
}
}
public static Cursor getContactsCursor(ContentResolver cr, List<String> contactsId) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
return ApiNinePlus.getContactsCursor(cr, null, contactsId);
} else {
return ApiFivePlus.getContactsCursor(cr, contactsId);
}
}
public static Cursor getContactsCursor(ContentResolver cr, String search, List<String> contactsId) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
return ApiNinePlus.getContactsCursor(cr, search, contactsId);
} else {
return ApiFivePlus.getContactsCursor(cr, contactsId);
}
}
public static Cursor getSIPContactsCursor(ContentResolver cr, List<String> contactsId) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
return ApiNinePlus.getSIPContactsCursor(cr, null, contactsId);
} else {
return ApiFivePlus.getSIPContactsCursor(cr, contactsId);
}
}
public static Cursor getSIPContactsCursor(ContentResolver cr, String search, List<String> contactsId) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
return ApiNinePlus.getSIPContactsCursor(cr, search, contactsId);
} else {
return ApiFivePlus.getSIPContactsCursor(cr, contactsId);
}
}
public static Cursor getImContactsCursor(ContentResolver cr) {
return ApiFivePlus.getSIPContactsCursor(cr,null);
}
public static int getCursorDisplayNameColumnIndex(Cursor cursor) {
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
return ApiFivePlus.getCursorDisplayNameColumnIndex(cursor);
}
return -1;
}
public static LinphoneContact getContact(ContentResolver cr, Cursor cursor, int position) {
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
return ApiFivePlus.getContact(cr, cursor, position);
}
return null;
}
public static InputStream getContactPictureInputStream(ContentResolver cr, String id) {
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
return ApiFivePlus.getContactPictureInputStream(cr, id);
}
return null;
}
public static Uri findUriPictureOfContactAndSetDisplayName(LinphoneAddress address, ContentResolver cr) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
return ApiNinePlus.findUriPictureOfContactAndSetDisplayName(address, cr);
} else {
return ApiFivePlus.findUriPictureOfContactAndSetDisplayName(address, cr);
}
}
public static Notification createSimpleNotification(Context context, String title, String text, PendingIntent intent) {
Notification notif = null;
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
return ApiTwentyOnePlus.createSimpleNotification(context, title, text, intent);
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
notif = ApiSixteenPlus.createSimpleNotification(context, title, text, intent);
} else if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
notif = ApiElevenPlus.createSimpleNotification(context, title, text, intent);
} else {
notif = ApiFivePlus.createSimpleNotification(context, title, text, intent);
notif = ApiElevenPlus.createSimpleNotification(context, title, text, intent);
}
return notif;
}
public static Notification createMessageNotification(Context context, int msgCount, String msgSender, String msg, Bitmap contactIcon, PendingIntent intent) {
Notification notif = null;
String title;
if (msgCount == 1) {
title = "Unread message from %s".replace("%s", msgSender);
} else {
title = "%i unread messages".replace("%i", String.valueOf(msgCount));
}
Notification notif = null;
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
return ApiTwentyOnePlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
notif = ApiSixteenPlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
} else if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
notif = ApiElevenPlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
} else {
notif = ApiFivePlus.createMessageNotification(context, title, msg, intent);
notif = ApiElevenPlus.createMessageNotification(context, msgCount, msgSender, msg, contactIcon, intent);
}
return notif;
}
public static Notification createInCallNotification(Context context, String title, String msg, int iconID, Bitmap contactIcon, String contactName, PendingIntent intent) {
Notification notif = null;
if (Version.sdkAboveOrEqual(Version.API21_LOLLIPOP_50)) {
return ApiTwentyOnePlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
notif = ApiSixteenPlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
} else if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
notif = ApiElevenPlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
} else {
notif = ApiFivePlus.createInCallNotification(context, title, msg, iconID, intent);
notif = ApiElevenPlus.createInCallNotification(context, title, msg, iconID, contactIcon, contactName, intent);
}
return notif;
}
@ -211,20 +74,11 @@ public class Compatibility {
return ApiTwentyOnePlus.createNotification(context, title, message, icon, iconLevel, largeIcon, intent, isOngoingEvent,priority);
} else if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
return ApiSixteenPlus.createNotification(context, title, message, icon, iconLevel, largeIcon, intent, isOngoingEvent,priority);
} else if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
return ApiElevenPlus.createNotification(context, title, message, icon, iconLevel, largeIcon, intent, isOngoingEvent);
} else {
return ApiFivePlus.createNotification(context, title, message, icon, iconLevel, intent, isOngoingEvent);
return ApiElevenPlus.createNotification(context, title, message, icon, iconLevel, largeIcon, intent, isOngoingEvent);
}
}
public static String refreshContactName(ContentResolver cr, String id) {
if (Version.sdkAboveOrEqual(Version.API05_ECLAIR_20)) {
return ApiFivePlus.refreshContactName(cr, id);
}
return null;
}
public static CompatibilityScaleGestureDetector getScaleGestureDetector(Context context, CompatibilityScaleGestureListener listener) {
if (Version.sdkAboveOrEqual(Version.API08_FROYO_22)) {
CompatibilityScaleGestureDetector csgd = new CompatibilityScaleGestureDetector(context);
@ -233,109 +87,13 @@ public class Compatibility {
}
return null;
}
public static void setPreferenceChecked(Preference preference, boolean checked) {
if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) {
ApiFourteenPlus.setPreferenceChecked(preference, checked);
} else {
ApiFivePlus.setPreferenceChecked(preference, checked);
}
}
public static boolean isPreferenceChecked(Preference preference) {
if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) {
return ApiFourteenPlus.isPreferenceChecked(preference);
} else {
return ApiFivePlus.isPreferenceChecked(preference);
}
}
public static void initPushNotificationService(Context context) {
if (Version.sdkAboveOrEqual(Version.API08_FROYO_22)) {
ApiEightPlus.initPushNotificationService(context);
}
}
public static void copyTextToClipboard(Context context, String msg) {
if(Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
ApiElevenPlus.copyTextToClipboard(context, msg);
} else {
ApiFivePlus.copyTextToClipboard(context, msg);
}
}
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
ApiNinePlus.addSipAddressToContact(context, ops, sipAddress);
} else {
ApiFivePlus.addSipAddressToContact(context, ops, sipAddress);
}
}
public static void addSipAddressToContact(Context context, ArrayList<ContentProviderOperation> ops, String sipAddress, String rawContactID) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
ApiNinePlus.addSipAddressToContact(context, ops, sipAddress, rawContactID);
} else {
ApiFivePlus.addSipAddressToContact(context, ops, sipAddress, rawContactID);
}
}
public static void updateSipAddressForContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String newSipAddress, String contactID) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
ApiNinePlus.updateSipAddressForContact(ops, oldSipAddress, newSipAddress, contactID);
} else {
ApiFivePlus.updateSipAddressForContact(ops, oldSipAddress, newSipAddress, contactID);
}
}
public static void deleteSipAddressFromContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String contactID) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
ApiNinePlus.deleteSipAddressFromContact(ops, oldSipAddress, contactID);
} else {
ApiFivePlus.deleteSipAddressFromContact(ops, oldSipAddress, contactID);
}
}
public static void deleteImAddressFromContact(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String contactID) {
ApiFivePlus.deleteSipAddressFromContact(ops, oldSipAddress, contactID);
}
@SuppressWarnings("deprecation")
public static void removeGlobalLayoutListener(ViewTreeObserver viewTreeObserver, OnGlobalLayoutListener keyboardListener) {
if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
ApiSixteenPlus.removeGlobalLayoutListener(viewTreeObserver, keyboardListener);
} else {
ApiFivePlus.removeGlobalLayoutListener(viewTreeObserver, keyboardListener);
}
}
public static void hideNavigationBar(Activity activity)
{
if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) {
ApiFourteenPlus.hideNavigationBar(activity);
}
}
public static void showNavigationBar(Activity activity)
{
if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) {
ApiFourteenPlus.showNavigationBar(activity);
}
}
public static void setAudioManagerInCallMode(AudioManager manager) {
if (Version.sdkAboveOrEqual(Version.API11_HONEYCOMB_30)) {
ApiElevenPlus.setAudioManagerInCallMode(manager);
} else {
ApiFivePlus.setAudioManagerInCallMode(manager);
}
}
public static String getAudioManagerEventForBluetoothConnectionStateChangedEvent() {
if (Version.sdkAboveOrEqual(Version.API14_ICE_CREAM_SANDWICH_40)) {
return ApiFourteenPlus.getAudioManagerEventForBluetoothConnectionStateChangedEvent();
} else {
return ApiEightPlus.getAudioManagerEventForBluetoothConnectionStateChangedEvent();
viewTreeObserver.removeGlobalOnLayoutListener(keyboardListener);
}
}
@ -354,4 +112,12 @@ public class Compatibility {
return pm.isScreenOn();
}
}
@SuppressWarnings("deprecation")
public static Spanned fromHtml(String text) {
/*if (Version.sdkAboveOrEqual(Version.API24_NOUGAT_70)) {
return Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY);
}*/
return Html.fromHtml(text);
}
}

View file

@ -53,13 +53,13 @@ public class GCMService extends GCMBaseIntentService {
@Override
protected void onError(Context context, String errorId) {
initLogger(context);
Log.e("Error while registering push notification : " + errorId);
Log.e("[Push Notification] Error while registering: " + errorId);
}
@Override
protected void onMessage(Context context, Intent intent) {
initLogger(context);
Log.d("Push notification received");
Log.d("[Push Notification] Received");
if (!LinphoneService.isReady()) {
startService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class));
@ -79,7 +79,7 @@ public class GCMService extends GCMBaseIntentService {
@Override
protected void onRegistered(Context context, String regId) {
initLogger(context);
Log.d("Registered push notification : " + regId);
Log.d("[Push Notification] Registered: " + regId);
LinphonePreferences.instance().setPushNotificationRegistrationID(regId);
}
@ -87,7 +87,7 @@ public class GCMService extends GCMBaseIntentService {
@Override
protected void onUnregistered(Context context, String regId) {
initLogger(context);
Log.w("Unregistered push notification : " + regId);
Log.w("[Push Notification] Unregistered: " + regId);
LinphonePreferences.instance().setPushNotificationRegistrationID(null);
}

View file

@ -162,8 +162,7 @@ public class TutorialCardDavSync extends Activity implements OnClickListener, Li
}
@Override
public void onLinphoneFriendSyncStatusChanged(LinphoneFriendList list,
org.linphone.core.LinphoneFriendList.State status, String message) {
public void onLinphoneFriendSyncStatusChanged(LinphoneFriendList list, LinphoneFriendList.State status, String message) {
// TODO Auto-generated method stub
String msg = "Sync status changed: " + status.toString() + " (" + message + ")";
myLog(msg);

View file

@ -31,6 +31,7 @@ import org.linphone.LinphoneContact;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneUtils;
import org.linphone.R;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.LinphoneBuffer;
import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatMessage.State;
@ -52,7 +53,6 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
@ -312,7 +312,7 @@ public class BubbleChat implements LinphoneChatMessage.LinphoneChatMessageListen
text = text.replaceFirst(link, "<a href=\"" + link + "\">" + linkWithoutScheme + "</a>");
}
return Html.fromHtml(text);
return Compatibility.fromHtml(text);
}
public String getTextMessage() {

@ -1 +1 @@
Subproject commit 9daabd3dbfc72d6799f6bd54474a8f262e6716f2
Subproject commit 921a21332c327ae99900267950be0bfd2d7c6126

@ -1 +1 @@
Subproject commit 086bb16bd79180265136ed9d4a89661049c95016
Subproject commit b553f58c3f23633b9c183af5784b2170b6b4aa91

@ -1 +1 @@
Subproject commit 6d4281181addb913e851622e6d9b04d093c869d4
Subproject commit f4eac4803eee43de3efa96ecca9450ba4f2bc7dc

@ -1 +1 @@
Subproject commit 976f38cc0865e106a27b6f74bdfde0fb368624b7
Subproject commit 6f1e96c8f60576fb1cfe9750612f9fdb7c134c54

View file

@ -40,7 +40,7 @@
</condition>
<exec executable="bash" unless:set="has.crashed">
<arg value="-c"/>
<arg value="adb shell run-as org.linphone cat /data/data/org.linphone/files/junit-report.xml > linphone-junit-report-${test.size}.xml"/>
<arg value="adb shell cat /data/data/org.linphone/files/junit-report.xml > linphone-junit-report-${test.size}.xml"/>
</exec>
<zip destfile="${archive.name}.zip">