Merge remote-tracking branch 'origin/master' into dev_codec_downloader

This commit is contained in:
Erwan Croze 2016-07-18 15:46:46 +02:00
commit e3f6137c5d
40 changed files with 1130 additions and 1003 deletions

6
.gitmodules vendored
View file

@ -38,9 +38,6 @@
[submodule "submodules/mssilk"]
path = submodules/mssilk
url = git://git.linphone.org/mssilk.git
[submodule "submodules/externals/vo-amrwbenc"]
path = submodules/externals/vo-amrwbenc
url = git://git.linphone.org/vo-amrwbenc.git
[submodule "submodules/bcg729"]
path = submodules/bcg729
url = git://git.linphone.org/bcg729.git
@ -104,3 +101,6 @@
[submodule "submodules/bcunit"]
path = submodules/bcunit
url = git://git.linphone.org/bcunit.git
[submodule "submodules/externals/vo-amrwbenc"]
path = submodules/externals/vo-amrwbenc
url = git://git.linphone.org/vo-amrwbenc.git

View file

@ -27,6 +27,7 @@
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- Needed to store received images if the user wants to -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- Needed to use our own Contact editor -->
@ -43,6 +44,8 @@
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
<!-- Needed for in-app purchase -->
<uses-permission android:name="com.android.vending.BILLING" />
<!-- Needed for overlay widget -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true"/>
@ -75,7 +78,7 @@
</intent-filter>
<intent-filter>
<data android:mimeType="vnd.android.cursor.item/org.linphone.profile" /> <!-- Change package ! -->
<data android:mimeType="@string/sync_mimetype" /> <!-- Change package in res/values/non_localizable_custom.xml ! -->
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
@ -94,7 +97,6 @@
<activity android:name=".CallIncomingActivity"
android:theme="@style/NoTitle"
android:noHistory="true"
android:launchMode="singleTop"
android:screenOrientation="behind">
<intent-filter>
@ -104,7 +106,6 @@
<activity android:name=".CallOutgoingActivity"
android:theme="@style/NoTitle"
android:noHistory="true"
android:launchMode="singleTop"
android:screenOrientation="behind">
<intent-filter>

View file

@ -8,50 +8,6 @@
failonerror="false" />
</target>
<target name="javah" depends="-set-debug-mode,-compile">
<echo level="info">Generate JNI header</echo>
<javah outputfile="gen/linphonecore_jni.h">
<classpath>
<pathelement location="${out.classes.absolute.dir}" />
</classpath>
<class name="org.linphone.core.LinphoneAddressImpl" />
<class name="org.linphone.core.LinphoneAuthInfoImpl" />
<class name="org.linphone.core.LinphoneCallImpl" />
<class name="org.linphone.core.LinphoneCallLogImpl" />
<class name="org.linphone.core.LinphoneCallParamsImpl" />
<class name="org.linphone.core.LinphoneCallStatsImpl" />
<class name="org.linphone.core.LinphoneChatMessageImpl" />
<class name="org.linphone.core.LinphoneChatRoomImpl" />
<class name="org.linphone.core.LinphoneCoreFactoryImpl" />
<class name="org.linphone.core.LinphoneCoreImpl" />
<class name="org.linphone.core.LinphoneFriendImpl" />
<class name="org.linphone.core.LinphoneProxyConfigImpl" />
<class name="org.linphone.core.PayloadTypeImpl" />
<class name="org.linphone.core.LpConfigImpl" />
<class name="org.linphone.core.LinphoneInfoMessageImpl" />
<class name="org.linphone.core.LinphoneEventImpl" />
<class name="org.linphone.core.PresenceActivityImpl" />
<class name="org.linphone.core.PresenceModelImpl" />
<class name="org.linphone.core.PresenceNoteImpl" />
<class name="org.linphone.core.PresencePersonImpl" />
<class name="org.linphone.core.PresenceServiceImpl" />
<class name="org.linphone.core.ErrorInfoImpl" />
<class name="org.linphone.core.TunnelConfigImpl" />
</javah>
<javah outputfile="gen/xml2lpc_jni.h">
<classpath>
<pathelement location="${out.classes.absolute.dir}" />
</classpath>
<class name="org.linphone.tools.Xml2Lpc" />
</javah>
<javah outputfile="gen/lpc2xml_jni.h">
<classpath>
<pathelement location="${out.classes.absolute.dir}" />
</classpath>
<class name="org.linphone.tools.Lpc2Xml" />
</javah>
</target>
<target name="partial-clean">
<delete file="bin/${ant.project.name}.ap_" />
</target>

View file

@ -287,6 +287,12 @@ generate-mediastreamer2-apk: java-clean build copy-libs update-mediastreamer2-pr
\techo "version.name=$(LINPHONE_ANDROID_VERSION)" > default.properties && \\
\tant debug
quick:
\tant clean
\tant debug
\tant installd
\tant run
install-apk:
\tant installd
@ -328,7 +334,6 @@ run-all-tests: update-project
\tant partial-clean
\t$(MAKE) -C tests run-all-tests ANT_SILENT=$(ANT_SILENT)
pull-transifex:
\ttx pull -af

View file

@ -78,6 +78,13 @@
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
<TextView
android:id="@+id/forgot_password"
android:layout_gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"/>
</LinearLayout>
</TableRow>

View file

@ -6,7 +6,7 @@
<string name="default_stun">stun.linphone.org</string>
<string name="sync_account_type">org.linphone</string> <!-- Change package ! -->
<string name="sync_mimetype">vnd.android.cursor.item/org.linphone.profile</string> <!-- Change package, leave .profile at the end ! -->
<string name="sync_mimetype">vnd.android.cursor.item/org.linphone.profile</string> <!-- Change package, leave .profile at the end. Also change res/xml/contacts.xml ! -->
<bool name="assistant_use_linphone_login_as_first_fragment">false</bool>
<bool name="hide_in_call_stats">false</bool>
@ -68,10 +68,8 @@
<string name="about_bugreport_email">linphone-android@belledonne-communications.com</string>
<bool name="use_linphonecore_ringing">false</bool>
<string name="temp_photo_name">linphone-android-photo-temp.jpg</string>
<string name="temp_photo_name_with_date">linphone-android-photo-%s.jpg</string>
<string name="temp_photo_name">linphone-android-photo-temp</string>
<string name="temp_photo_name_with_date">linphone-android-photo-%s</string>
<bool name="hide_phone_numbers_in_editor">false</bool>
<bool name="hide_sip_addresses_in_editor">false</bool>

View file

@ -59,6 +59,7 @@
<string name="pref_wifi_only_key">pref_wifi_only_key</string>
<string name="pref_overlay_key">pref_overlay_key</string>
<string name="pref_video_use_front_camera_key">pref_video_use_front_camera_key</string>
<string name="pref_video_codec_h263_key">pref_video_codec_h263_key</string>
<string name="pref_video_codec_mpeg4_key">pref_video_codec_mpeg4_key</string>
@ -71,6 +72,7 @@
<string name="pref_preferred_video_fps_key">pref_preferred_video_fps_key</string>
<string name="pref_bandwidth_limit_key">pref_bandwidth_limit_key</string>
<string name="pref_animation_enable_key">pref_animation_enable_key</string>
<string name="pref_service_notification_key">pref_service_notification_key</string>
<string name="pref_escape_plus_key">pref_escape_plus_key</string>
<string name="pref_friendlist_subscribe_key">pref_friendlist_subscribe_key</string>
<string name="pref_echo_cancellation_key">pref_echo_cancellation_key</string>
@ -197,4 +199,6 @@
<item>Send logs</item>
<item>Cancel</item>
</string-array>
<string name="pref_use_lime_encryption_key">pref_use_lime_encryption_key</string>
</resources>

View file

@ -20,7 +20,6 @@
<string name="messages_date_format">dd/MM, HH:mm</string>
<string name="messages_list_date_format">dd/MM</string>
<string name="today_date_format">HH:mm</string>
<string name="picture_name_format">linphone-mms-%s.jpg</string>
<!-- Common -->
<string name="username">Username</string>
@ -255,6 +254,8 @@
<!-- Video settings -->
<string name="pref_video_title">Video</string>
<string name="pref_overlay">Video overlay</string>
<string name="pref_overlay_summary">Display call video in overlay when outside the application</string>
<string name="pref_video_use_front_camera_title">Use front camera</string>
<string name="pref_video_initiate_call_with_video_title">Initiate video calls</string>
<string name="pref_video_initiate_call_with_video">Always send video requests</string>
@ -272,6 +273,15 @@
<string name="pref_rfc2833_dtmf">Send RFC2833 DTMFs</string>
<string name="pref_sipinfo_dtmf">Send SIP INFO DTMFs</string>
<string name="pref_voice_mail">Voice mail URI</string>
<!-- Chat settings -->
<string name="pref_chat_title">Chat</string>
<string name="pref_image_sharing_server_title">Sharing server</string>
<string name="pref_image_sharing_server_desc">Do not edit unless you know what you are doing!</string>
<string name="pref_use_lime_encryption">Use LIME encryption</string>
<string name="lime_encryption_entry_disabled">Disabled</string>
<string name="lime_encryption_entry_mandatory">Mandatory</string>
<string name="lime_encryption_entry_preferred">Preferred</string>
<!-- Network settings -->
<string name="pref_network_title">Network</string>
@ -294,9 +304,9 @@
<string name="pref_debug">Debug</string>
<string name="pref_background_mode">Background mode</string>
<string name="pref_animation_enable_title">Enable Animations</string>
<string name="pref_service_notification">Enable service notification</string>
<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_image_sharing_server_title">Sharing server</string>
<string name="pref_remote_provisioning_title">Remote provisioning</string>
<string name="pref_primary_account_title">Primary account</string>
<string name="pref_display_name_title">Display name</string>

View file

@ -111,12 +111,17 @@
android:title="@string/pref_bandwidth_limit"
android:key="@string/pref_bandwidth_limit_key"
android:numeric="integer" />
<CheckBoxPreference
android:title="@string/pref_overlay"
android:key="@string/pref_overlay_key"
android:summary="@string/pref_overlay_summary"/>
<PreferenceCategory
android:title="@string/pref_video_codecs_title"
android:key="@string/pref_video_codecs_key"
android:dependency="@string/pref_video_enable_key"
android:shouldDisableView="true"/>
<PreferenceCategory
android:title="@string/pref_video_codecs_title"
android:key="@string/pref_video_codecs_key"
android:dependency="@string/pref_video_enable_key"
android:shouldDisableView="true"/>
</PreferenceScreen>
@ -136,6 +141,20 @@
android:key="@string/pref_voice_mail_key"/>
</PreferenceScreen>
<PreferenceScreen
android:title="@string/pref_chat_title">
<EditTextPreference
android:title="@string/pref_image_sharing_server_title"
android:key="@string/pref_image_sharing_server_key"
android:summary="@string/pref_image_sharing_server_desc"/>
<ListPreference
android:title="@string/pref_use_lime_encryption"
android:key="@string/pref_use_lime_encryption_key"/>
</PreferenceScreen>
<PreferenceScreen
android:title="@string/pref_network_title">
@ -202,6 +221,10 @@
android:title="@string/pref_background_mode"
android:key="@string/pref_background_mode_key"/>
<CheckBoxPreference
android:title="@string/pref_service_notification"
android:key="@string/pref_service_notification_key"/>
<CheckBoxPreference
android:title="@string/pref_animation_enable_title"
android:key="@string/pref_animation_enable_key"/>
@ -215,10 +238,6 @@
android:key="@string/pref_incoming_call_timeout_key"
android:layout="@layout/hidden"/>
<EditTextPreference
android:title="@string/pref_image_sharing_server_title"
android:key="@string/pref_image_sharing_server_key"/>
<EditTextPreference
android:title="@string/pref_remote_provisioning_title"
android:key="@string/pref_remote_provisioning_key"/>

View file

@ -37,6 +37,7 @@ import org.linphone.ui.Numpad;
import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
@ -55,7 +56,6 @@ import android.os.CountDownTimer;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.app.Fragment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
@ -87,6 +87,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
private final static int SECONDS_BEFORE_DENYING_CALL_UPDATE = 30000;
private static final int PERMISSIONS_REQUEST_CAMERA = 202;
private static final int PERMISSIONS_ENABLED_CAMERA = 203;
private static final int PERMISSIONS_ENABLED_MIC = 204;
private static CallActivity instance;
@ -180,18 +181,14 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
if (state == State.IncomingReceived) {
startIncomingCallActivity();
return;
}
if (state == State.Paused || state == State.PausedByRemote || state == State.Pausing) {
} else if (state == State.Paused || state == State.PausedByRemote || state == State.Pausing) {
if(LinphoneManager.getLc().getCurrentCall() != null) {
enabledVideoButton(false);
}
if(isVideoEnabled(call)){
showAudioView();
}
}
if (state == State.Resuming) {
} else if (state == State.Resuming) {
if(LinphonePreferences.instance().isVideoEnabled()){
status.refreshStatusItems(call, isVideoEnabled(call));
if(call.getCurrentParamsCopy().getVideoEnabled()){
@ -201,9 +198,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
if(LinphoneManager.getLc().getCurrentCall() != null) {
enabledVideoButton(true);
}
}
if (state == State.StreamsRunning) {
} else if (state == State.StreamsRunning) {
switchVideo(isVideoEnabled(call));
enableAndRefreshInCallActions();
@ -211,9 +206,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
videoProgress.setVisibility(View.GONE);
status.refreshStatusItems(call, isVideoEnabled(call));
}
}
if (state == State.CallUpdatedByRemote) {
} else if (state == State.CallUpdatedByRemote) {
// If the correspondent proposes video while audio call
boolean videoEnabled = LinphonePreferences.instance().isVideoEnabled();
if (!videoEnabled) {
@ -454,21 +447,29 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
}
public void checkAndRequestPermission(String permission, int result) {
if (getPackageManager().checkPermission(permission, getPackageName()) != PackageManager.PERMISSION_GRANTED) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(this,permission)){
ActivityCompat.requestPermissions(this, new String[]{permission}, result);
int permissionGranted = getPackageManager().checkPermission(permission, getPackageName());
Log.i("[Permission] " + permission + " is " + (permissionGranted == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (permissionGranted != PackageManager.PERMISSION_GRANTED) {
if (LinphonePreferences.instance().firstTimeAskingForPermission(permission) || ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
Log.i("[Permission] Asking for " + permission);
ActivityCompat.requestPermissions(this, new String[] { permission }, result);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
public void onRequestPermissionsResult(int requestCode, String[] permissions, final int[] grantResults) {
for (int i = 0; i < permissions.length; i++) {
Log.i("[Permission] " + permissions[i] + " is " + (grantResults[i] == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
}
switch (requestCode) {
case PERMISSIONS_REQUEST_CAMERA:
UIThreadDispatcher.dispatch(new Runnable() {
@Override
public void run() {
acceptCallUpdate(true);
acceptCallUpdate(grantResults[0] == PackageManager.PERMISSION_GRANTED);
}
});
break;
@ -476,12 +477,21 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
UIThreadDispatcher.dispatch(new Runnable() {
@Override
public void run() {
enabledOrDisabledVideo(false);
disableVideo(grantResults[0] != PackageManager.PERMISSION_GRANTED);
}
});
break;
case PERMISSIONS_ENABLED_MIC:
UIThreadDispatcher.dispatch(new Runnable() {
@Override
public void run() {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
toggleMicro();
}
}
});
break;
}
LinphonePreferences.instance().neverAskCameraPerm();
}
public void createInCallStats() {
@ -527,6 +537,9 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
video.setImageResource(R.drawable.camera_button);
}
}
if (getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) != PackageManager.PERMISSION_GRANTED) {
video.setImageResource(R.drawable.camera_button);
}
if (isSpeakerEnabled) {
speaker.setImageResource(R.drawable.speaker_selected);
@ -534,6 +547,9 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
speaker.setImageResource(R.drawable.speaker_default);
}
if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) != PackageManager.PERMISSION_GRANTED) {
isMicMuted = true;
}
if (isMicMuted) {
micro.setImageResource(R.drawable.micro_selected);
} else {
@ -613,14 +629,28 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
}
if (id == R.id.video) {
if (getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) == PackageManager.PERMISSION_GRANTED) {
enabledOrDisabledVideo(isVideoEnabled(LinphoneManager.getLc().getCurrentCall()));
int camera = getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName());
Log.i("[Permission] Camera permission is " + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (camera == PackageManager.PERMISSION_GRANTED) {
disableVideo(isVideoEnabled(LinphoneManager.getLc().getCurrentCall()));
} else {
checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_ENABLED_CAMERA);
if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.CAMERA) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_ENABLED_CAMERA);
}
}
}
else if (id == R.id.micro) {
toggleMicro();
int recordAudio = getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName());
Log.i("[Permission] Record audio permission is " + (recordAudio == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (recordAudio == PackageManager.PERMISSION_GRANTED) {
toggleMicro();
} else {
if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.RECORD_AUDIO) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
checkAndRequestPermission(Manifest.permission.RECORD_AUDIO, PERMISSIONS_ENABLED_MIC);
}
}
}
else if (id == R.id.speaker) {
toggleSpeaker();
@ -727,13 +757,13 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
}
}
private void enabledOrDisabledVideo(final boolean isVideoEnabled) {
private void disableVideo(final boolean videoDisabled) {
final LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
if (call == null) {
return;
}
if (isVideoEnabled) {
if (videoDisabled) {
LinphoneCallParams params = LinphoneManager.getLc().createCallParams(call);
params.setVideoEnabled(false);
LinphoneManager.getLc().updateCall(call, params);
@ -1387,19 +1417,24 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve
delete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) == PackageManager.PERMISSION_GRANTED || LinphonePreferences.instance().cameraPermAsked()) {
int camera = getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName());
Log.i("[Permission] Camera permission is " + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (camera == PackageManager.PERMISSION_GRANTED) {
CallActivity.instance().acceptCallUpdate(true);
} else {
checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_REQUEST_CAMERA);
if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.CAMERA) || ActivityCompat.shouldShowRequestPermissionRationale(CallActivity.this, Manifest.permission.CAMERA)) {
checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_REQUEST_CAMERA);
} else {
CallActivity.instance().acceptCallUpdate(false);
}
}
dialog.dismiss();
}
});
cancel.setOnClickListener(new
OnClickListener() {
cancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick (View view){
if (CallActivity.isInstanciated()) {

View file

@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone;
import java.util.ArrayList;
import java.util.List;
import org.linphone.core.LinphoneAddress;
@ -29,12 +30,15 @@ import org.linphone.core.LinphoneCoreListenerBase;
import org.linphone.mediastream.Log;
import org.linphone.ui.LinphoneSliders.LinphoneSliderTriggered;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.support.v4.app.ActivityCompat;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@ -45,7 +49,6 @@ import android.widget.TextView;
import android.widget.Toast;
public class CallIncomingActivity extends Activity implements LinphoneSliderTriggered {
private static CallIncomingActivity instance;
private TextView name, number;
@ -186,9 +189,6 @@ public class CallIncomingActivity extends Activity implements LinphoneSliderTrig
}
});
mListener = new LinphoneCoreListenerBase(){
@Override
public void callState(LinphoneCore lc, LinphoneCall call, State state, String message) {
@ -202,7 +202,6 @@ public class CallIncomingActivity extends Activity implements LinphoneSliderTrig
}
};
super.onCreate(savedInstanceState);
instance = this;
}
@ -234,6 +233,8 @@ public class CallIncomingActivity extends Activity implements LinphoneSliderTrig
finish();
return;
}
LinphoneAddress address = mCall.getRemoteAddress();
LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(address);
if (contact != null) {
@ -244,6 +245,12 @@ public class CallIncomingActivity extends Activity implements LinphoneSliderTrig
}
number.setText(address.asStringUriOnly());
}
@Override
protected void onStart() {
super.onStart();
checkAndRequestCallPermissions();
}
@Override
protected void onPause() {
@ -320,4 +327,41 @@ public class CallIncomingActivity extends Activity implements LinphoneSliderTrig
public void onRightHandleTriggered() {
}
private void checkAndRequestCallPermissions() {
ArrayList<String> permissionsList = new ArrayList<String>();
int recordAudio = getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName());
Log.i("[Permission] Record audio permission is " + (recordAudio == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
int camera = getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName());
Log.i("[Permission] Camera permission is " + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (recordAudio != PackageManager.PERMISSION_GRANTED) {
if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.RECORD_AUDIO) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
Log.i("[Permission] Asking for record audio");
permissionsList.add(Manifest.permission.RECORD_AUDIO);
}
}
if (LinphonePreferences.instance().shouldInitiateVideoCall() || LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) {
if (camera != PackageManager.PERMISSION_GRANTED) {
if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.CAMERA) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
Log.i("[Permission] Asking for camera");
permissionsList.add(Manifest.permission.CAMERA);
}
}
}
if (permissionsList.size() > 0) {
String[] permissions = new String[permissionsList.size()];
permissions = permissionsList.toArray(permissions);
ActivityCompat.requestPermissions(this, permissions, 0);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
for (int i = 0; i < permissions.length; i++) {
Log.i("[Permission] " + permissions[i] + " is " + (grantResults[i] == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
}
}
}

View file

@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone;
import java.util.ArrayList;
import java.util.List;
import org.linphone.core.LinphoneAddress;
@ -26,20 +27,27 @@ import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCallParams;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreListenerBase;
import org.linphone.core.Reason;
import org.linphone.mediastream.Log;
import android.Manifest;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.KeyEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class CallOutgoingActivity extends Activity implements OnClickListener{
private static CallOutgoingActivity instance;
private TextView name, number;
@ -88,16 +96,8 @@ public class CallOutgoingActivity extends Activity implements OnClickListener{
mListener = new LinphoneCoreListenerBase(){
@Override
public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
if (LinphoneManager.getLc().getCallsNb() == 0) {
finish();
return;
}
if (call == mCall && State.CallEnd == state) {
finish();
}
if (call == mCall && (State.Connected == state)){
public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
if (call == mCall && State.Connected == state) {
if (!LinphoneActivity.isInstanciated()) {
return;
}
@ -109,6 +109,22 @@ public class CallOutgoingActivity extends Activity implements OnClickListener{
}
finish();
return;
} else if (state == State.Error) {
// Convert LinphoneCore message for internalization
if (message != null && call.getErrorInfo().getReason() == Reason.Declined) {
displayCustomToast(getString(R.string.error_call_declined), Toast.LENGTH_SHORT);
} else if (message != null && call.getErrorInfo().getReason() == Reason.NotFound) {
displayCustomToast(getString(R.string.error_user_not_found), Toast.LENGTH_SHORT);
} else if (message != null && call.getErrorInfo().getReason() == Reason.Media) {
displayCustomToast(getString(R.string.error_incompatible_media), Toast.LENGTH_SHORT);
} else if (message != null) {
displayCustomToast(getString(R.string.error_unknown) + " - " + message, Toast.LENGTH_SHORT);
}
}
if (LinphoneManager.getLc().getCallsNb() == 0) {
finish();
return;
}
}
};
@ -152,6 +168,12 @@ public class CallOutgoingActivity extends Activity implements OnClickListener{
}
number.setText(address.asStringUriOnly());
}
@Override
protected void onStart() {
super.onStart();
checkAndRequestCallPermissions();
}
@Override
protected void onPause() {
@ -204,7 +226,58 @@ public class CallOutgoingActivity extends Activity implements OnClickListener{
return super.onKeyDown(keyCode, event);
}
public void displayCustomToast(final String message, final int duration) {
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.toast, (ViewGroup) findViewById(R.id.toastRoot));
TextView toastText = (TextView) layout.findViewById(R.id.toastMessage);
toastText.setText(message);
final Toast toast = new Toast(getApplicationContext());
toast.setGravity(Gravity.CENTER, 0, 0);
toast.setDuration(duration);
toast.setView(layout);
toast.show();
}
private void decline() {
LinphoneManager.getLc().terminateCall(mCall);
}
private void checkAndRequestCallPermissions() {
ArrayList<String> permissionsList = new ArrayList<String>();
int recordAudio = getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName());
Log.i("[Permission] Record audio permission is " + (recordAudio == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
int camera = getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName());
Log.i("[Permission] Camera permission is " + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (recordAudio != PackageManager.PERMISSION_GRANTED) {
if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.RECORD_AUDIO) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
Log.i("[Permission] Asking for record audio");
permissionsList.add(Manifest.permission.RECORD_AUDIO);
}
}
if (LinphonePreferences.instance().shouldInitiateVideoCall() || LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) {
if (camera != PackageManager.PERMISSION_GRANTED) {
if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.CAMERA) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
Log.i("[Permission] Asking for camera");
permissionsList.add(Manifest.permission.CAMERA);
}
}
}
if (permissionsList.size() > 0) {
String[] permissions = new String[permissionsList.size()];
permissions = permissionsList.toArray(permissions);
ActivityCompat.requestPermissions(this, permissions, 0);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
for (int i = 0; i < permissions.length; i++) {
Log.i("[Permission] " + permissions[i] + " is " + (grantResults[i] == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
}
}
}

View file

@ -38,7 +38,7 @@ import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
//import android.opengl.GLSurfaceView;
import android.widget.RelativeLayout;
/**
* @author Sylvain Berfini
@ -52,6 +52,7 @@ public class CallVideoFragment extends Fragment implements OnGestureListener, On
private float mZoomCenterX, mZoomCenterY;
private CompatibilityScaleGestureDetector mScaleDetector;
private CallActivity inCallActivity;
private int previewX, previewY;
@SuppressWarnings("deprecation") // Warning useless because value is ignored and automatically set by new APIs.
@Override
@ -61,7 +62,7 @@ public class CallVideoFragment extends Fragment implements OnGestureListener, On
if (LinphoneManager.getLc().hasCrappyOpenGL()) {
view = inflater.inflate(R.layout.video_no_opengl, container, false);
} else {
view = inflater.inflate(R.layout.video, container, false);
view = inflater.inflate(R.layout.video, container, false);
}
mVideoView = (SurfaceView) view.findViewById(R.id.videoSurface);
@ -104,6 +105,30 @@ public class CallVideoFragment extends Fragment implements OnGestureListener, On
}
});
mCaptureView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
previewX = (int) motionEvent.getX();
previewY = (int) motionEvent.getY();
break;
case MotionEvent.ACTION_MOVE:
int x = (int) motionEvent.getX();
int y = (int) motionEvent.getY();
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)mCaptureView.getLayoutParams();
lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 0); // Clears the rule, as there is no removeRule until API 17.
lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
int left = lp.leftMargin + (x - previewX);
int top = lp.topMargin + (y - previewY);
lp.leftMargin = left;
lp.topMargin = top;
view.setLayoutParams(lp);
break;
}
return true;
}
});
return view;
}
@ -134,6 +159,9 @@ public class CallVideoFragment extends Fragment implements OnGestureListener, On
public void onResume() {
super.onResume();
if (LinphonePreferences.instance().isOverlayEnabled()) {
LinphoneService.instance().destroyOverlay();
}
if (androidVideoWindowImpl != null) {
synchronized (androidVideoWindowImpl) {
LinphoneManager.getLc().setVideoWindow(androidVideoWindowImpl);
@ -155,6 +183,9 @@ public class CallVideoFragment extends Fragment implements OnGestureListener, On
LinphoneManager.getLc().setVideoWindow(null);
}
}
if (LinphonePreferences.instance().isOverlayEnabled()) {
LinphoneService.instance().createOverlay();
}
super.onPause();
}

View file

@ -192,7 +192,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
@Override
public void onClick(View v) {
pickImage();
LinphoneActivity.instance().checkAndRequestCameraPermission();
LinphoneActivity.instance().checkAndRequestPermissionsToSendImage();
}
});
//registerForContextMenu(sendImage);
@ -482,7 +482,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
if (adapter != null) {
adapter.refreshHistory();
} else {
adapter = new ChatMessageAdapter(getActivity().getApplicationContext());
adapter = new ChatMessageAdapter(getActivity());
}
}
messagesList.setAdapter(adapter);
@ -710,7 +710,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
editList.setVisibility(View.VISIBLE);
isEditMode = true;
redrawMessageList();
//TODO refaire la liste
}
if(id == R.id.start_call){
LinphoneActivity.instance().setAddresGoToDialerAndCall(sipUri, LinphoneUtils.getUsernameFromAddress(sipUri), null);
@ -742,10 +741,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
chatRoom.sendChatMessage(message);
lAddress = chatRoom.getPeerAddress();
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().onMessageSent(sipUri, messageToSend);
}
message.setListener(LinphoneManager.getInstance());
if (newChatConversation) {
exitNewConversationMode(lAddress.asStringUriOnly());
@ -819,9 +814,21 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
}
private void copyTextMessageToClipboard(int id) {
String msg = LinphoneActivity.instance().getChatStorage().getTextMessageForId(chatRoom, id);
if (msg != null) {
Compatibility.copyTextToClipboard(getActivity(), msg);
LinphoneChatMessage message = null;
for (int i = 0; i < adapter.getCount(); i++) {
LinphoneChatMessage msg = adapter.getItem(i);
if (msg.getStorageId() == id) {
message = msg;
break;
}
}
String txt = null;
if (message != null) {
txt = message.getText();
}
if (txt != null) {
Compatibility.copyTextToClipboard(getActivity(), txt);
LinphoneActivity.instance().displayCustomToast(getString(R.string.text_copied_to_clipboard), Toast.LENGTH_SHORT);
}
}
@ -901,7 +908,12 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
}
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, stream);
String extension = LinphoneUtils.getExtensionFromFileName(path);
if (extension != null && extension.toLowerCase(Locale.getDefault()).equals("png")) {
bm.compress(Bitmap.CompressFormat.PNG, 100, stream);
} else {
bm.compress(Bitmap.CompressFormat.JPEG, 100, stream);
}
byte[] byteArray = stream.toByteArray();
return byteArray;
}
@ -913,8 +925,9 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC
}
mUploadingImageStream = new ByteArrayInputStream(result);
LinphoneContent content = LinphoneCoreFactory.instance().createLinphoneContent("image", "jpeg", result, null);
String fileName = path.substring(path.lastIndexOf("/") + 1);
String extension = LinphoneUtils.getExtensionFromFileName(fileName);
LinphoneContent content = LinphoneCoreFactory.instance().createLinphoneContent("image", extension, result, null);
content.setName(fileName);
LinphoneChatMessage message = chatRoom.createFileTransferMessage(content);

View file

@ -57,7 +57,7 @@ import android.widget.TextView;
*/
public class ChatListFragment extends Fragment implements OnClickListener, OnItemClickListener {
private LayoutInflater mInflater;
private List<String> mConversations, mDrafts;
private List<String> mConversations;
private ListView chatList;
private TextView noChatHistory;
private ImageView edit, selectAll, deselectAll, delete, newDiscussion, cancel, backInCall;
@ -164,7 +164,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
}
private void hideAndDisplayMessageIfNoChat() {
if (mConversations.size() == 0 && mDrafts.size() == 0) {
if (mConversations.size() == 0) {
noChatHistory.setVisibility(View.VISIBLE);
chatList.setVisibility(View.GONE);
edit.setEnabled(false);
@ -179,8 +179,6 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
public void refresh() {
mConversations = LinphoneActivity.instance().getChatList();
mDrafts = LinphoneActivity.instance().getDraftChatList();
mConversations.removeAll(mDrafts);
hideAndDisplayMessageIfNoChat();
}
@ -240,8 +238,6 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
LinphoneActivity.instance().removeFromChatList(sipUri);
mConversations = LinphoneActivity.instance().getChatList();
mDrafts = LinphoneActivity.instance().getDraftChatList();
mConversations.removeAll(mDrafts);
hideAndDisplayMessageIfNoChat();
return true;
}

View file

@ -1,409 +0,0 @@
package org.linphone;
/*
ChatStorage.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.
*/
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.mediastream.Log;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.preference.PreferenceManager;
/**
* @author Sylvain Berfini
*/
public class ChatStorage {
private static final int INCOMING = 1;
private static final int OUTGOING = 0;
private static final int READ = 1;
private static final int NOT_READ = 0;
private static ChatStorage instance;
private Context context;
private SQLiteDatabase db;
private boolean useNativeAPI;
private static final String TABLE_NAME = "chat";
private static final String DRAFT_TABLE_NAME = "chat_draft";
public synchronized static final ChatStorage getInstance() {
if (instance == null)
instance = new ChatStorage(LinphoneService.instance().getApplicationContext());
return instance;
}
public void restartChatStorage() {
if (instance != null)
instance.close();
instance = new ChatStorage(LinphoneService.instance().getApplicationContext());
}
private boolean isVersionUsingNewChatStorage() {
try {
return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode >= 2200;
} catch (NameNotFoundException e) {
Log.e(e);
}
return true;
}
private ChatStorage(Context c) {
context = c;
boolean useLinphoneStorage = true;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(LinphoneService.instance());
boolean updateNeeded = prefs.getBoolean(c.getString(R.string.pref_first_time_linphone_chat_storage), !LinphonePreferences.instance().isFirstLaunch());
updateNeeded = updateNeeded && !isVersionUsingNewChatStorage();
useNativeAPI = useLinphoneStorage && !updateNeeded;
Log.d("Using native API: " + useNativeAPI);
if (!useNativeAPI) {
ChatHelper chatHelper = new ChatHelper(context);
db = chatHelper.getWritableDatabase();
}
}
public void close() {
if (!useNativeAPI) {
db.close();
}
}
public void updateMessageStatus(String to, String message, int status) {
if (useNativeAPI) {
return;
}
String[] whereArgs = { String.valueOf(OUTGOING), to, message };
Cursor c = db.query(TABLE_NAME, null, "direction LIKE ? AND remoteContact LIKE ? AND message LIKE ?", whereArgs, null, null, "id DESC");
String id = null;
if (c.moveToFirst()) {
try {
id = c.getString(c.getColumnIndex("id"));
} catch (Exception e) {
Log.e(e);
}
}
c.close();
if (id != null && id.length() > 0) {
int intID = Integer.parseInt(id);
updateMessageStatus(to, intID, status);
}
}
public void updateMessageStatus(String to, int id, int status) {
if (useNativeAPI) {
return;
}
ContentValues values = new ContentValues();
values.put("status", status);
db.update(TABLE_NAME, values, "id LIKE " + id, null);
}
public int saveTextMessage(String from, String to, String message, long time) {
if (useNativeAPI) {
return -1;
}
ContentValues values = new ContentValues();
if (from.equals("")) {
values.put("localContact", from);
values.put("remoteContact", to);
values.put("direction", OUTGOING);
values.put("read", READ);
values.put("status", LinphoneChatMessage.State.InProgress.toInt());
} else if (to.equals("")) {
values.put("localContact", to);
values.put("remoteContact", from);
values.put("direction", INCOMING);
values.put("read", NOT_READ);
values.put("status", LinphoneChatMessage.State.Idle.toInt());
}
values.put("message", message);
values.put("time", time);
return (int) db.insert(TABLE_NAME, null, values);
}
public int saveImageMessage(String from, String to, Bitmap image, String url, long time) {
if (useNativeAPI) {
return -1;
}
ContentValues values = new ContentValues();
if (from.equals("")) {
values.put("localContact", from);
values.put("remoteContact", to);
values.put("direction", OUTGOING);
values.put("read", READ);
values.put("status", LinphoneChatMessage.State.InProgress.toInt());
} else if (to.equals("")) {
values.put("localContact", to);
values.put("remoteContact", from);
values.put("direction", INCOMING);
values.put("read", NOT_READ);
values.put("status", LinphoneChatMessage.State.Idle.toInt());
}
values.put("url", url);
if (image != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(CompressFormat.JPEG, 100, baos);
values.put("image", baos.toByteArray());
}
values.put("time", time);
return (int) db.insert(TABLE_NAME, null, values);
}
public void saveImage(int id, Bitmap image) {
if (useNativeAPI) {
//Handled before this point
return;
}
if (image == null)
return;
ContentValues values = new ContentValues();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(CompressFormat.JPEG, 100, baos);
values.put("image", baos.toByteArray());
db.update(TABLE_NAME, values, "id LIKE " + id, null);
}
public int saveDraft(String to, String message) {
if (useNativeAPI) {
//TODO
return -1;
}
ContentValues values = new ContentValues();
values.put("remoteContact", to);
values.put("message", message);
return (int) db.insert(DRAFT_TABLE_NAME, null, values);
}
public void updateDraft(String to, String message) {
if (useNativeAPI) {
//TODO
return;
}
ContentValues values = new ContentValues();
values.put("message", message);
db.update(DRAFT_TABLE_NAME, values, "remoteContact LIKE \"" + to + "\"", null);
}
public void deleteDraft(String to) {
if (useNativeAPI) {
//TODO
return;
}
db.delete(DRAFT_TABLE_NAME, "remoteContact LIKE \"" + to + "\"", null);
}
public String getDraft(String to) {
if (useNativeAPI) {
//TODO
return "";
}
Cursor c = db.query(DRAFT_TABLE_NAME, null, "remoteContact LIKE \"" + to + "\"", null, null, null, "id ASC");
String message = null;
while (c.moveToNext()) {
try {
message = c.getString(c.getColumnIndex("message"));
} catch (Exception e) {
Log.e(e);
}
}
c.close();
return message;
}
public List<String> getDrafts() {
List<String> drafts = new ArrayList<String>();
if (useNativeAPI) {
//TODO
} else {
Cursor c = db.query(DRAFT_TABLE_NAME, null, null, null, null, null, "id ASC");
while (c.moveToNext()) {
try {
String to = c.getString(c.getColumnIndex("remoteContact"));
drafts.add(to);
} catch (Exception e) {
Log.e(e);
}
}
c.close();
}
return drafts;
}
public String getTextMessageForId(LinphoneChatRoom chatroom, int id) {
String message = null;
if (useNativeAPI) {
LinphoneChatMessage msg = getMessage(chatroom, id);
if (msg != null) {
message = msg.getText();
}
} else {
Cursor c = db.query(TABLE_NAME, null, "id LIKE " + id, null, null, null, null);
if (c.moveToFirst()) {
try {
message = c.getString(c.getColumnIndex("message"));
} catch (Exception e) {
Log.e(e);
}
}
c.close();
}
return message;
}
public LinphoneChatMessage getMessage(LinphoneChatRoom chatroom, int id) {
LinphoneChatMessage[] history = chatroom.getHistory();
for (LinphoneChatMessage msg : history) {
if (msg.getStorageId() == id) {
return msg;
}
}
return null;
}
public void removeDiscussion(String correspondent) {
LinphoneChatRoom chatroom = LinphoneManager.getLc().getOrCreateChatRoom(correspondent);
chatroom.deleteHistory();
}
public ArrayList<String> getChatList() {
ArrayList<String> chatList = new ArrayList<String>();
LinphoneChatRoom[] chats = LinphoneManager.getLc().getChatRooms();
List<LinphoneChatRoom> rooms = new ArrayList<LinphoneChatRoom>();
for (LinphoneChatRoom chatroom : chats) {
if (chatroom.getHistorySize() > 0) {
rooms.add(chatroom);
}
}
if (rooms.size() > 1) {
Collections.sort(rooms, new Comparator<LinphoneChatRoom>() {
@Override
public int compare(LinphoneChatRoom a, LinphoneChatRoom b) {
LinphoneChatMessage[] messagesA = a.getHistory(1);
LinphoneChatMessage[] messagesB = b.getHistory(1);
long atime = messagesA[0].getTime();
long btime = messagesB[0].getTime();
if (atime > btime)
return -1;
else if (btime > atime)
return 1;
else
return 0;
}
});
}
for (LinphoneChatRoom chatroom : rooms) {
chatList.add(chatroom.getPeerAddress().asStringUriOnly());
}
return chatList;
}
public void deleteMessage(LinphoneChatRoom chatroom, int id) {
if (useNativeAPI) {
LinphoneChatMessage msg = getMessage(chatroom, id);
if (msg != null){
chatroom.deleteMessage(msg);
}
} else {
db.delete(TABLE_NAME, "id LIKE " + id, null);
}
}
public void markMessageAsRead(int id) {
if (!useNativeAPI) {
ContentValues values = new ContentValues();
values.put("read", READ);
db.update(TABLE_NAME, values, "id LIKE " + id, null);
}
}
public void markConversationAsRead(LinphoneChatRoom chatroom) {
if (useNativeAPI) {
chatroom.markAsRead();
}
}
class ChatHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 15;
private static final String DATABASE_NAME = "linphone-android";
ChatHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, localContact TEXT NOT NULL, remoteContact TEXT NOT NULL, direction INTEGER, message TEXT, image BLOB, url TEXT, time NUMERIC, read INTEGER, status INTEGER);");
db.execSQL("CREATE TABLE " + DRAFT_TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, remoteContact TEXT NOT NULL, message TEXT);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME + ";");
db.execSQL("DROP TABLE IF EXISTS " + DRAFT_TABLE_NAME + ";");
onCreate(db);
}
}
}

View file

@ -129,6 +129,9 @@ public class ContactDetailsFragment extends Fragment implements OnClickListener
if (displayednumberOrAddress.startsWith("sip:")) {
displayednumberOrAddress = displayednumberOrAddress.replace("sip:", "");
}
if (displayednumberOrAddress.contains("@")) {
displayednumberOrAddress = displayednumberOrAddress.split("@")[0];
}
TextView label = (TextView) v.findViewById(R.id.address_label);
if (noa.isSIPAddress()) {

View file

@ -25,6 +25,8 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.mediastream.Log;
import org.linphone.mediastream.Version;
@ -34,12 +36,14 @@ import android.app.Dialog;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.provider.ContactsContract.DisplayPhoto;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.InputType;
@ -122,6 +126,10 @@ public class ContactEditorFragment extends Fragment {
ok.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
LinphoneProxyConfig lpc = lc != null ? lc.getDefaultProxyConfig() : null;
String defaultDomain = lpc != null ? lpc.getDomain() : null;
if (isNewContact) {
boolean areAllFielsEmpty = true;
for (LinphoneNumberOrAddress nounoa : numbersAndAddresses) {
@ -140,8 +148,16 @@ public class ContactEditorFragment extends Fragment {
if (photoToAdd != null) {
contact.setPhoto(photoToAdd);
}
for (LinphoneNumberOrAddress numberOrAddress : numbersAndAddresses) {
contact.addOrUpdateNumberOrAddress(numberOrAddress);
for (LinphoneNumberOrAddress noa : numbersAndAddresses) {
if (noa.isSIPAddress() && noa.getValue() != null) {
if (!noa.getValue().contains("@") && defaultDomain != null) {
noa.setValue(noa.getValue() + "@" + defaultDomain);
}
if (!noa.getValue().startsWith("sip:")) {
noa.setValue("sip:" + noa.getValue());
}
}
contact.addOrUpdateNumberOrAddress(noa);
}
contact.save();
getFragmentManager().popBackStackImmediate();
@ -372,10 +388,31 @@ public class ContactEditorFragment extends Fragment {
image = BitmapFactory.decodeFile(filePath);
}
Bitmap scaledPhoto;
int size = getThumbnailSize();
if (size > 0) {
scaledPhoto = Bitmap.createScaledBitmap(image, size, size, false);
} else {
scaledPhoto = Bitmap.createBitmap(image);
}
image.recycle();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.PNG , 75, stream);
photoToAdd = stream.toByteArray();
contactPicture.setImageBitmap(image);
scaledPhoto.compress(Bitmap.CompressFormat.PNG , 0, stream);
contactPicture.setImageBitmap(scaledPhoto);
photoToAdd = stream.toByteArray();
}
private int getThumbnailSize() {
int value = -1;
Cursor c = LinphoneActivity.instance().getContentResolver().query(DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI, new String[] { DisplayPhoto.THUMBNAIL_MAX_DIM }, null, null, null);
try {
c.moveToFirst();
value = c.getInt(0);
} catch (Exception e) {
Log.e(e);
}
return value;
}
private LinearLayout initNumbersFields(final LinphoneContact contact) {
@ -449,6 +486,9 @@ public class ContactEditorFragment extends Fragment {
firstSipAddressIndex = controls.getChildCount();
}
numberOrAddress = numberOrAddress.replace("sip:", "");
if (numberOrAddress.contains("@")) {
numberOrAddress = numberOrAddress.split("@")[0];
}
}
if ((getResources().getBoolean(R.bool.hide_phone_numbers_in_editor) && !isSIP) || (getResources().getBoolean(R.bool.hide_sip_addresses_in_editor) && isSIP)) {
if (forceAddNumber)

View file

@ -174,7 +174,7 @@ public class ContactsManager extends ContentObserver {
}
public void initializeSyncAccount(Context context, ContentResolver contentResolver) {
initializeContactManager(context,contentResolver);
initializeContactManager(context, contentResolver);
AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
Account[] accounts = accountManager.getAccountsByType(context.getPackageName());
@ -236,7 +236,7 @@ public class ContactsManager extends ContentObserver {
public List<LinphoneContact> fetchContactsAsync() {
List<LinphoneContact> contacts = new ArrayList<LinphoneContact>();
if (mAccount != null && hasContactsAccess()) {
if (hasContactsAccess()) {
Cursor c = Compatibility.getContactsCursor(contentResolver, null);
if (c != null) {
while (c.moveToNext()) {
@ -330,6 +330,7 @@ public class ContactsManager extends ContentObserver {
Log.e(e);
}
}
public String getString(int resourceID) {
return context.getString(resourceID);
}

View file

@ -18,6 +18,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.mediastream.Log;
import android.content.BroadcastReceiver;
@ -25,10 +26,13 @@ import android.content.Context;
import android.content.Intent;
public class KeepAliveHandler extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//Log.i("Keep alive handler invoked"); //TODO FIXME Crash since the log rework
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();
@ -38,9 +42,6 @@ public class KeepAliveHandler extends BroadcastReceiver {
} catch (InterruptedException e) {
//Log.e("Cannot sleep for 2s", e); //TODO FIXME Crash since the log rework
}
}
}
}

View file

@ -29,10 +29,8 @@ import android.content.Intent;
* Purpose of this receiver is to disable keep alives when screen is off
* */
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;
@ -43,7 +41,5 @@ public class KeepAliveReceiver extends BroadcastReceiver {
LinphoneManager.getLc().enableKeepAlive(false);
}
}
}
}

View file

@ -23,11 +23,14 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.linphone.LinphoneManager.AddressType;
import org.linphone.assistant.AssistantActivity;
import org.linphone.assistant.RemoteProvisioningLoginActivity;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.CallDirection;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneAuthInfo;
@ -61,11 +64,11 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
@ -97,14 +100,10 @@ import android.widget.Toast;
public class LinphoneActivity extends Activity implements OnClickListener, ContactPicked, ActivityCompat.OnRequestPermissionsResultCallback {
public static final String PREF_FIRST_LAUNCH = "pref_first_launch";
private static final int SETTINGS_ACTIVITY = 123;
private static final int FIRST_LOGIN_ACTIVITY = 101;
private static final int REMOTE_PROVISIONING_LOGIN_ACTIVITY = 102;
private static final int CALL_ACTIVITY = 19;
private static final int PERMISSIONS_REQUEST_CONTACTS = 200;
private static final int PERMISSIONS_REQUEST_RECORD_AUDIO = 201;
private static final int PERMISSIONS_REQUEST_RECORD_AUDIO_INCOMING_CALL = 203;
private static final int PERMISSIONS_REQUEST_EXTERNAL_FILE_STORAGE = 204;
private static final int PERMISSIONS_REQUEST_CAMERA = 205;
private static final int PERMISSIONS_REQUEST_OVERLAY = 206;
private static final int PERMISSIONS_REQUEST_SYNC = 207;
private static final int PERMISSIONS_REQUEST_CONTACTS = 208;
private static LinphoneActivity instance;
@ -140,17 +139,6 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
return instance;
throw new RuntimeException("LinphoneActivity not instantiated yet");
}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putSerializable("CurrentFragment", currentFragment);
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -171,18 +159,29 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
Intent wizard = new Intent();
wizard.setClass(this, RemoteProvisioningLoginActivity.class);
wizard.putExtra("Domain", LinphoneManager.getInstance().wizardLoginViewDomain);
startActivityForResult(wizard, REMOTE_PROVISIONING_LOGIN_ACTIVITY);
} else if (savedInstanceState == null && (useFirstLoginActivity && LinphonePreferences.instance().isFirstLaunch() || LinphoneManager.getLc().getProxyConfigList().length == 0)) {
startActivity(wizard);
finish();
return;
} else if (savedInstanceState == null && (useFirstLoginActivity && LinphonePreferences.instance().isFirstLaunch())) {
if (LinphonePreferences.instance().getAccountCount() > 0) {
LinphonePreferences.instance().firstLaunchSuccessful();
} else {
startActivityForResult(new Intent().setClass(this, AssistantActivity.class), FIRST_LOGIN_ACTIVITY);
startActivity(new Intent().setClass(this, AssistantActivity.class));
finish();
return;
}
}
if (getIntent() != null && getIntent().getExtras() != null) {
newProxyConfig = getIntent().getExtras().getBoolean("isNewProxyConfig");
}
//TODO rework
if (getResources().getBoolean(R.bool.use_linphone_tag) && getPackageManager().checkPermission(Manifest.permission.WRITE_SYNC_SETTINGS, getPackageName()) == PackageManager.PERMISSION_GRANTED) {
ContactsManager.getInstance().initializeSyncAccount(getApplicationContext(), getContentResolver());
if (getResources().getBoolean(R.bool.use_linphone_tag)) {
if (getPackageManager().checkPermission(Manifest.permission.WRITE_SYNC_SETTINGS, getPackageName()) != PackageManager.PERMISSION_GRANTED) {
checkSyncPermission();
} else {
ContactsManager.getInstance().initializeSyncAccount(getApplicationContext(), getContentResolver());
}
} else {
ContactsManager.getInstance().initializeContactManager(getApplicationContext(), getContentResolver());
}
@ -198,8 +197,6 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
currentFragment = nextFragment = FragmentsAvailable.EMPTY;
if (savedInstanceState == null) {
changeCurrentFragment(FragmentsAvailable.DIALER, getIntent().getExtras());
} else {
changeCurrentFragment(((FragmentsAvailable)savedInstanceState.getSerializable("CurrentFragment")), getIntent().getExtras());
}
mListener = new LinphoneCoreListenerBase(){
@ -243,28 +240,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
@Override
public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
if (state == State.IncomingReceived) {
if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED || LinphonePreferences.instance().audioPermAsked()) {
startActivity(new Intent(LinphoneActivity.instance(), CallIncomingActivity.class));
} else {
checkAndRequestAudioPermission(true);
}
startActivity(new Intent(LinphoneActivity.instance(), CallIncomingActivity.class));
} else if (state == State.OutgoingInit || state == State.OutgoingProgress) {
if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED || LinphonePreferences.instance().audioPermAsked()) {
startActivity(new Intent(LinphoneActivity.instance(), CallOutgoingActivity.class));
} else {
checkAndRequestAudioPermission(false);
}
startActivity(new Intent(LinphoneActivity.instance(), CallOutgoingActivity.class));
} else if (state == State.CallEnd || state == State.Error || state == State.CallReleased) {
// Convert LinphoneCore message for internalization
if (message != null && call.getErrorInfo().getReason() == Reason.Declined) {
displayCustomToast(getString(R.string.error_call_declined), Toast.LENGTH_SHORT);
} else if (message != null && call.getErrorInfo().getReason() == Reason.NotFound) {
displayCustomToast(getString(R.string.error_user_not_found), Toast.LENGTH_SHORT);
} else if (message != null && call.getErrorInfo().getReason() == Reason.Media) {
displayCustomToast(getString(R.string.error_incompatible_media), Toast.LENGTH_SHORT);
} else if (message != null && state == State.Error) {
displayCustomToast(getString(R.string.error_unknown) + " - " + message, Toast.LENGTH_SHORT);
}
resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
}
@ -381,6 +360,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
newFragment = new HistoryDetailFragment();
break;
case CONTACTS_LIST:
checkAndRequestReadContactsPermission();
newFragment = new ContactsListFragment();
if (isTablet()) {
((ContactsListFragment) newFragment).displayFirstContact();
@ -826,43 +806,52 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
}
public List<String> getChatList() {
return getChatStorage().getChatList();
}
ArrayList<String> chatList = new ArrayList<String>();
public List<String> getDraftChatList() {
return getChatStorage().getDrafts();
LinphoneChatRoom[] chats = LinphoneManager.getLc().getChatRooms();
List<LinphoneChatRoom> rooms = new ArrayList<LinphoneChatRoom>();
for (LinphoneChatRoom chatroom : chats) {
if (chatroom.getHistorySize() > 0) {
rooms.add(chatroom);
}
}
if (rooms.size() > 1) {
Collections.sort(rooms, new Comparator<LinphoneChatRoom>() {
@Override
public int compare(LinphoneChatRoom a, LinphoneChatRoom b) {
LinphoneChatMessage[] messagesA = a.getHistory(1);
LinphoneChatMessage[] messagesB = b.getHistory(1);
long atime = messagesA[0].getTime();
long btime = messagesB[0].getTime();
if (atime > btime)
return -1;
else if (btime > atime)
return 1;
else
return 0;
}
});
}
for (LinphoneChatRoom chatroom : rooms) {
chatList.add(chatroom.getPeerAddress().asStringUriOnly());
}
return chatList;
}
public void removeFromChatList(String sipUri) {
getChatStorage().removeDiscussion(sipUri);
}
public void removeFromDrafts(String sipUri) {
getChatStorage().deleteDraft(sipUri);
LinphoneChatRoom chatroom = LinphoneManager.getLc().getOrCreateChatRoom(sipUri);
chatroom.deleteHistory();
}
public void updateMissedChatCount() {
displayMissedChats(getUnreadMessageCount());
}
public int onMessageSent(String to, String message) {
getChatStorage().deleteDraft(to);
return getChatStorage().saveTextMessage("", to, message, System.currentTimeMillis());
}
public int onMessageSent(String to, Bitmap image, String imageURL) {
getChatStorage().deleteDraft(to);
return getChatStorage().saveImageMessage("", to, image, imageURL, System.currentTimeMillis());
}
public void onMessageStateChanged(String to, String message, int newState) {
getChatStorage().updateMessageStatus(to, message, newState);
}
public void onImageMessageStateChanged(String to, int id, int newState) {
getChatStorage().updateMessageStatus(to, id, newState);
}
public void displayMissedCalls(final int missedCallsCount) {
if (missedCallsCount > 0) {
missedCalls.setText(missedCallsCount + "");
@ -893,8 +882,6 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
}
}
public void displayCustomToast(final String message, final int duration) {
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.toast, (ViewGroup) findViewById(R.id.toastRoot));
@ -1066,10 +1053,6 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
return currentFragment;
}
public ChatStorage getChatStorage() {
return ChatStorage.getInstance();
}
public void addContact(String displayName, String sipUri)
{
Bundle extras = new Bundle();
@ -1079,19 +1062,17 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
public void editContact(LinphoneContact contact)
{
Bundle extras = new Bundle();
extras.putSerializable("Contact", contact);
changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras);
Bundle extras = new Bundle();
extras.putSerializable("Contact", contact);
changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras);
}
public void editContact(LinphoneContact contact, String sipAddress)
{
Bundle extras = new Bundle();
extras.putSerializable("Contact", contact);
extras.putSerializable("NewSipAdress", sipAddress);
changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras);
Bundle extras = new Bundle();
extras.putSerializable("Contact", contact);
extras.putSerializable("NewSipAdress", sipAddress);
changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras);
}
public void quit() {
@ -1129,6 +1110,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
} else {
resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
}
} else if (requestCode == PERMISSIONS_REQUEST_OVERLAY) {
if (Compatibility.canDrawOverlays(this)) {
LinphonePreferences.instance().enableOverlay(true);
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
@ -1169,101 +1154,125 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
}
return true;
}
public boolean checkAndRequestOverlayPermission() {
Log.i("[Permission] Draw overlays permission is " + (Compatibility.canDrawOverlays(this) ? "granted" : "denied"));
if (!Compatibility.canDrawOverlays(this)) {
Log.i("[Permission] Asking for overlay");
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, PERMISSIONS_REQUEST_OVERLAY);
return false;
}
return true;
}
public void checkAndRequestReadExternalStoragePermission() {
checkAndRequestPermission(Manifest.permission.READ_EXTERNAL_STORAGE, 0);
}
public void checkAndRequestExternalStoragePermission() {
if (LinphonePreferences.instance().writeExternalStoragePermAsked()) {
return;
}
checkAndRequestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSIONS_REQUEST_EXTERNAL_FILE_STORAGE);
checkAndRequestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, 0);
}
public void checkAndRequestCameraPermission() {
if (LinphonePreferences.instance().cameraPermAsked()) {
return;
}
checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_REQUEST_CAMERA);
checkAndRequestPermission(Manifest.permission.CAMERA, 0);
}
public void checkAndRequestReadContactsPermission() {
if (LinphonePreferences.instance().readContactsPermAsked()) {
return;
}
checkAndRequestPermission(Manifest.permission.READ_CONTACTS, PERMISSIONS_REQUEST_CONTACTS);
}
public void checkAndRequestWriteContactsPermission() {
if (LinphonePreferences.instance().writeContactsPermAsked()) {
return;
}
checkAndRequestPermission(Manifest.permission.WRITE_CONTACTS, PERMISSIONS_REQUEST_CONTACTS);
checkAndRequestPermission(Manifest.permission.WRITE_CONTACTS, 0);
}
public void checkAndRequestAudioPermission(boolean isIncomingCall) {
if (LinphonePreferences.instance().audioPermAsked()) {
return;
public void checkAndRequestPermissionsToSendImage() {
ArrayList<String> permissionsList = new ArrayList<String>();
int readExternalStorage = getPackageManager().checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE, getPackageName());
Log.i("[Permission] Read external storage permission is " + (readExternalStorage == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
int camera = getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName());
Log.i("[Permission] Camera permission is " + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (readExternalStorage != PackageManager.PERMISSION_GRANTED) {
if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.READ_EXTERNAL_STORAGE) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
Log.i("[Permission] Asking for read external storage");
permissionsList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
}
checkAndRequestPermission(Manifest.permission.RECORD_AUDIO, isIncomingCall ? PERMISSIONS_REQUEST_RECORD_AUDIO_INCOMING_CALL : PERMISSIONS_REQUEST_RECORD_AUDIO);
if (LinphonePreferences.instance().shouldInitiateVideoCall() ||
LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) {
checkAndRequestCameraPermission();
if (camera != PackageManager.PERMISSION_GRANTED) {
if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.CAMERA) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
Log.i("[Permission] Asking for camera");
permissionsList.add(Manifest.permission.CAMERA);
}
}
if (permissionsList.size() > 0) {
String[] permissions = new String[permissionsList.size()];
permissions = permissionsList.toArray(permissions);
ActivityCompat.requestPermissions(this, permissions, 0);
}
}
private void checkSyncPermission() {
checkAndRequestPermission(Manifest.permission.WRITE_SYNC_SETTINGS, PERMISSIONS_REQUEST_SYNC);
}
public void checkAndRequestPermission(String permission, int result) {
if (getPackageManager().checkPermission(permission, getPackageName()) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{permission}, result);
int permissionGranted = getPackageManager().checkPermission(permission, getPackageName());
Log.i("[Permission] " + permission + " is " + (permissionGranted == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (permissionGranted != PackageManager.PERMISSION_GRANTED) {
if (LinphonePreferences.instance().firstTimeAskingForPermission(permission) || ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
Log.i("[Permission] Asking for " + permission);
ActivityCompat.requestPermissions(this, new String[] { permission }, result);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (grantResults.length > 0) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])) {
if (permissions[i].equals(Manifest.permission.RECORD_AUDIO)) {
LinphonePreferences.instance().neverAskAudioPerm();
} else if (permissions[i].equals(Manifest.permission.CAMERA)) {
LinphonePreferences.instance().neverAskCameraPerm();
} else if (permissions[i].equals(Manifest.permission.READ_CONTACTS)) {
LinphonePreferences.instance().neverAskReadContactsPerm();
} else if (permissions[i].equals(Manifest.permission.WRITE_CONTACTS)) {
LinphonePreferences.instance().neverAskWriteContactsPerm();
} else if (permissions[i].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
LinphonePreferences.instance().neverAskWriteExternalStoragePerm();
}
} else {
//TODO: show dialog explaining what we need the permission for
}
} else {
if (permissions[i].equals(Manifest.permission.RECORD_AUDIO)) {
LinphonePreferences.instance().neverAskAudioPerm();
} else if (permissions[i].equals(Manifest.permission.CAMERA)) {
LinphonePreferences.instance().neverAskCameraPerm();
} else if (permissions[i].equals(Manifest.permission.READ_CONTACTS)) {
LinphonePreferences.instance().neverAskReadContactsPerm();
} else if (permissions[i].equals(Manifest.permission.WRITE_CONTACTS)) {
LinphonePreferences.instance().neverAskWriteContactsPerm();
} else if (permissions[i].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
LinphonePreferences.instance().neverAskWriteExternalStoragePerm();
}
}
}
for (int i = 0; i < permissions.length; i++) {
Log.i("[Permission] " + permissions[i] + " is " + (grantResults[i] == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
}
switch (requestCode) {
case PERMISSIONS_REQUEST_RECORD_AUDIO:
startActivity(new Intent(this, CallOutgoingActivity.class));
case PERMISSIONS_REQUEST_SYNC:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
ContactsManager.getInstance().initializeSyncAccount(getApplicationContext(), getContentResolver());
} else {
ContactsManager.getInstance().initializeContactManager(getApplicationContext(), getContentResolver());
}
break;
case PERMISSIONS_REQUEST_RECORD_AUDIO_INCOMING_CALL:
startActivity(new Intent(this, CallIncomingActivity.class));
case PERMISSIONS_REQUEST_CONTACTS:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
ContactsManager.getInstance().enableContactsAccess();
ContactsManager.getInstance().fetchContacts();
fetchedContactsOnce = true;
}
break;
}
}
@Override
protected void onStart() {
super.onStart();
int contacts = getPackageManager().checkPermission(Manifest.permission.READ_CONTACTS, getPackageName());
Log.i("[Permission] Contacts permission is " + (contacts == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (contacts == PackageManager.PERMISSION_GRANTED && !fetchedContactsOnce) {
ContactsManager.getInstance().enableContactsAccess();
ContactsManager.getInstance().fetchContacts();
fetchedContactsOnce = true;
} else {
checkAndRequestReadContactsPermission();
}
}
@Override
protected void onResume() {
super.onResume();
if (!LinphoneService.isReady()) {
startService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class));
}
@ -1273,14 +1282,6 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
lc.addListener(mListener);
}
if (getPackageManager().checkPermission(Manifest.permission.READ_CONTACTS, getPackageName()) == PackageManager.PERMISSION_GRANTED && !fetchedContactsOnce) {
ContactsManager.getInstance().enableContactsAccess();
ContactsManager.getInstance().fetchContacts();
fetchedContactsOnce = true;
} else {
checkAndRequestReadContactsPermission();
}
refreshAccounts();
updateMissedChatCount();
@ -1296,18 +1297,11 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
if (LinphoneManager.getLc().getCalls().length > 0) {
LinphoneCall call = LinphoneManager.getLc().getCalls()[0];
LinphoneCall.State callState = call.getState();
if (callState == State.IncomingReceived) {
if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED || LinphonePreferences.instance().audioPermAsked()) {
startActivity(new Intent(this, CallIncomingActivity.class));
} else {
checkAndRequestAudioPermission(true);
}
startActivity(new Intent(this, CallIncomingActivity.class));
} else if (callState == State.OutgoingInit || callState == State.OutgoingProgress || callState == State.OutgoingRinging) {
if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED || LinphonePreferences.instance().audioPermAsked()) {
startActivity(new Intent(this, CallOutgoingActivity.class));
} else {
checkAndRequestAudioPermission(false);
}
startActivity(new Intent(this, CallOutgoingActivity.class));
} else {
if (call.getCurrentParamsCopy().getVideoEnabled()) {
startVideoActivity(call);
@ -1349,7 +1343,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Bundle extras = intent.getExtras();
if (extras != null && extras.getBoolean("GoToChat", false)) {
LinphoneService.instance().removeMessageNotification();
@ -1386,11 +1380,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
if (CallActivity.isInstanciated()) {
CallActivity.instance().startIncomingCallActivity();
} else {
if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED || LinphonePreferences.instance().audioPermAsked()) {
startActivity(new Intent(this, CallIncomingActivity.class));
} else {
checkAndRequestAudioPermission(true);
}
startActivity(new Intent(this, CallIncomingActivity.class));
}
}
}

View file

@ -48,10 +48,11 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
private static final long serialVersionUID = 9015568163905205244L;
private transient LinphoneFriend friend;
private String fullName, firstName, lastName, androidId;
private String fullName, firstName, lastName, androidId, androidRawId, androidTagId;
private transient Uri photoUri, thumbnailUri;
private List<LinphoneNumberOrAddress> addresses;
private transient ArrayList<ContentProviderOperation> changesToCommit;
private transient ArrayList<ContentProviderOperation> changesToCommit2;
private boolean hasSipAddress;
public LinphoneContact() {
@ -60,6 +61,7 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
thumbnailUri = null;
photoUri = null;
changesToCommit = new ArrayList<ContentProviderOperation>();
changesToCommit2 = new ArrayList<ContentProviderOperation>();
hasSipAddress = false;
}
@ -138,12 +140,12 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
public void setPhoto(byte[] photo) {
if (photo != null) {
if (isAndroidContact()) {
String rawContactId = findRawContactID(getAndroidId());
if (rawContactId != null) {
if (androidRawId != null) {
changesToCommit.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, androidRawId)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, photo)
.withValue(ContactsContract.Data.IS_PRIMARY, 1)
.withValue(ContactsContract.Data.IS_SUPER_PRIMARY, 1)
.build());
} else {
@ -153,8 +155,6 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
.withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, photo)
.build());
}
} else if (isLinphoneFriend()) {
//TODO: prepare photo changes in friend
}
}
}
@ -201,6 +201,15 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
changesToCommit.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
.withSelection(select, args)
.build());
if (androidTagId != null && noa.isSIPAddress()) {
select = ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + ContactsContract.Data.DATA1 + "=?";
args = new String[] { androidTagId, noa.getOldValue() };
changesToCommit.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
.withSelection(select, args)
.build());
}
}
if (isLinphoneFriend()) {
@ -239,19 +248,37 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
values.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM);
values.put(ContactsContract.CommonDataKinds.Phone.LABEL, ContactsManager.getInstance().getString(R.string.addressbook_label));
}
String rawContactId = findRawContactID(getAndroidId());
if (rawContactId != null) {
if (androidRawId != null) {
changesToCommit.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
.withValues(values)
.build());
.withValue(ContactsContract.Data.RAW_CONTACT_ID, androidRawId)
.withValues(values)
.build());
} else {
changesToCommit.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValues(values)
.build());
}
if (noa.isSIPAddress() && LinphoneManager.getInstance().getContext().getResources().getBoolean(R.bool.use_linphone_tag)) {
if (androidTagId != null) {
changesToCommit.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, androidTagId)
.withValue(ContactsContract.Data.MIMETYPE, ContactsManager.getInstance().getString(R.string.sync_mimetype))
.withValue(ContactsContract.Data.DATA1, noa.getValue())
.withValue(ContactsContract.Data.DATA2, ContactsManager.getInstance().getString(R.string.app_name))
.withValue(ContactsContract.Data.DATA3, noa.getValue())
.build());
} else {
changesToCommit2.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsManager.getInstance().getString(R.string.sync_mimetype))
.withValue(ContactsContract.Data.DATA1, noa.getValue())
.withValue(ContactsContract.Data.DATA2, ContactsManager.getInstance().getString(R.string.app_name))
.withValue(ContactsContract.Data.DATA3, noa.getValue())
.build());
}
}
} else {
ContentValues values = new ContentValues();
String select;
@ -266,13 +293,28 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, noa.getValue());
}
changesToCommit.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(select, args)
.withValues(values)
.build());
String rawContactId = findRawContactID(getAndroidId());
if (rawContactId != null) {
changesToCommit.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(select, args)
.withValues(values)
.build());
if (noa.isSIPAddress() && LinphoneManager.getInstance().getContext().getResources().getBoolean(R.bool.use_linphone_tag)) {
if (androidTagId != null) {
changesToCommit.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + ContactsContract.Data.DATA1 + "=? ", new String[] { androidTagId, noa.getOldValue() })
.withValue(ContactsContract.Data.DATA1, noa.getValue())
.withValue(ContactsContract.Data.DATA2, ContactsManager.getInstance().getString(R.string.app_name))
.withValue(ContactsContract.Data.DATA3, noa.getValue())
.build());
} else {
changesToCommit2.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsManager.getInstance().getString(R.string.sync_mimetype))
.withValue(ContactsContract.Data.DATA1, noa.getValue())
.withValue(ContactsContract.Data.DATA2, ContactsManager.getInstance().getString(R.string.app_name))
.withValue(ContactsContract.Data.DATA3, noa.getValue())
.build());
}
}
}
}
@ -309,16 +351,19 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
return androidId;
}
public void save() {
if (isAndroidContact() && ContactsManager.getInstance().hasContactsAccess() && changesToCommit.size() > 0) {
public void save() {
if (isAndroidContact() && ContactsManager.getInstance().hasContactsAccess() && changesToCommit.size() > 0) {
try {
ContactsManager.getInstance().getContentResolver().applyBatch(ContactsContract.AUTHORITY, changesToCommit);
createLinphoneTagIfNeeded();
} catch (Exception e) {
Log.e(e);
} finally {
changesToCommit = new ArrayList<ContentProviderOperation>();
changesToCommit2 = new ArrayList<ContentProviderOperation>();
}
}
if (isLinphoneFriend()) {
boolean hasAddr = false;
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
@ -387,17 +432,22 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
hasSipAddress = false;
if (isAndroidContact()) {
String id = getAndroidId();
getContactNames(id);
setThumbnailUri(getContactPictureUri(id));
setPhotoUri(getContactPhotoUri(id));
for (LinphoneNumberOrAddress noa : getAddressesAndNumbersForAndroidContact(id)) {
getContactNames();
setThumbnailUri(getContactPictureUri());
setPhotoUri(getContactPhotoUri());
androidRawId = findRawContactID();
if (LinphoneManager.getInstance().getContext().getResources().getBoolean(R.bool.use_linphone_tag)) {
androidTagId = findLinphoneRawContactId();
}
for (LinphoneNumberOrAddress noa : getAddressesAndNumbersForAndroidContact()) {
addNumberOrAddress(noa);
}
if (friend == null) {
friend = LinphoneCoreFactory.instance().createLinphoneFriend();
friend.setRefKey(id);
friend.setRefKey(getAndroidId());
// Disable subscribes for now
friend.enableSubscribes(false);
friend.setIncSubscribePolicy(SubscribePolicy.SPDeny);
@ -471,21 +521,21 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
return firstLetter.compareTo(contactfirstLetter);
}
private Uri getContactPictureUri(String id) {
Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(id));
private Uri getContactPictureUri() {
Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(getAndroidId()));
return Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
}
private Uri getContactPhotoUri(String id) {
Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(id));
private Uri getContactPhotoUri() {
Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(getAndroidId()));
return Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.DISPLAY_PHOTO);
}
private void getContactNames(String id) {
private void getContactNames() {
ContentResolver resolver = ContactsManager.getInstance().getContentResolver();
String[] proj = new String[]{ ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, ContactsContract.Contacts.DISPLAY_NAME };
String select = ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "=?";
String[] args = new String[]{ id, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE };
String[] args = new String[]{ getAndroidId(), ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE };
Cursor c = resolver.query(ContactsContract.Data.CONTENT_URI, proj, select, args, null);
if (c != null) {
if (c.moveToFirst()) {
@ -497,13 +547,13 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
}
}
private String findRawContactID(String id) {
private String findRawContactID() {
ContentResolver resolver = ContactsManager.getInstance().getContentResolver();
String result = null;
String[] projection = { ContactsContract.RawContacts._ID };
String selection = ContactsContract.RawContacts.CONTACT_ID + "=?";
Cursor c = resolver.query(ContactsContract.RawContacts.CONTENT_URI, projection, selection, new String[]{ id }, null);
Cursor c = resolver.query(ContactsContract.RawContacts.CONTENT_URI, projection, selection, new String[]{ getAndroidId() }, null);
if (c != null) {
if (c.moveToFirst()) {
result = c.getString(c.getColumnIndex(ContactsContract.RawContacts._ID));
@ -513,13 +563,13 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
return result;
}
private List<LinphoneNumberOrAddress> getAddressesAndNumbersForAndroidContact(String id) {
private List<LinphoneNumberOrAddress> getAddressesAndNumbersForAndroidContact() {
List<LinphoneNumberOrAddress> result = new ArrayList<LinphoneNumberOrAddress>();
ContentResolver resolver = ContactsManager.getInstance().getContentResolver();
String select = ContactsContract.Data.CONTACT_ID + " =? AND (" + ContactsContract.Data.MIMETYPE + "=? OR " + ContactsContract.Data.MIMETYPE + "=?)";
String[] projection = new String[] { ContactsContract.CommonDataKinds.SipAddress.SIP_ADDRESS, ContactsContract.Data.MIMETYPE }; // PHONE_NUMBER == SIP_ADDRESS == "data1"...
Cursor c = resolver.query(ContactsContract.Data.CONTENT_URI, projection, select, new String[]{ id, ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE }, null);
Cursor c = resolver.query(ContactsContract.Data.CONTENT_URI, projection, select, new String[]{ getAndroidId(), ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE }, null);
if (c != null) {
while (c.moveToNext()) {
String mime = c.getString(c.getColumnIndex(ContactsContract.Data.MIMETYPE));
@ -552,12 +602,14 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
private static LinphoneContact createAndroidContact() {
LinphoneContact contact = new LinphoneContact();
contact.changesToCommit.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
.withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
.build());
contact.setAndroidId("0");
return contact;
}
@ -570,4 +622,63 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
contact.friend = friend;
return contact;
}
private String findLinphoneRawContactId() {
ContentResolver resolver = ContactsManager.getInstance().getContentResolver();
String result = null;
String[] projection = { ContactsContract.RawContacts._ID };
String selection = ContactsContract.RawContacts.CONTACT_ID + "=? AND " + ContactsContract.RawContacts.ACCOUNT_TYPE + "=?";
Cursor c = resolver.query(ContactsContract.RawContacts.CONTENT_URI, projection, selection, new String[] { getAndroidId(), ContactsManager.getInstance().getString(R.string.sync_account_type) }, null);
if (c != null) {
if (c.moveToFirst()) {
result = c.getString(c.getColumnIndex(ContactsContract.RawContacts._ID));
}
c.close();
}
return result;
}
private void createLinphoneTagIfNeeded() {
if (LinphoneManager.getInstance().getContext().getResources().getBoolean(R.bool.use_linphone_tag)) {
if (androidTagId == null && findLinphoneRawContactId() == null) {
createLinphoneContactTag();
}
}
}
private void createLinphoneContactTag() {
ArrayList<ContentProviderOperation> batch = new ArrayList<ContentProviderOperation>();
batch.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, ContactsManager.getInstance().getString(R.string.sync_account_type))
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, ContactsManager.getInstance().getString(R.string.sync_account_name))
.withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
.build());
batch.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, getFullName())
.build());
batch.add(ContentProviderOperation.newUpdate(ContactsContract.AggregationExceptions.CONTENT_URI)
.withValue(ContactsContract.AggregationExceptions.TYPE, ContactsContract.AggregationExceptions.TYPE_KEEP_TOGETHER)
.withValue(ContactsContract.AggregationExceptions.RAW_CONTACT_ID1, androidRawId)
.withValueBackReference(ContactsContract.AggregationExceptions.RAW_CONTACT_ID2, 0)
.build());
if (changesToCommit2.size() > 0) {
for(ContentProviderOperation cpo : changesToCommit2) {
batch.add(cpo);
}
}
try {
ContactsManager.getInstance().getContentResolver().applyBatch(ContactsContract.AUTHORITY, batch);
androidTagId = findLinphoneRawContactId();
} catch (Exception e) {
Log.e(e);
}
}
}

View file

@ -20,7 +20,6 @@ package org.linphone;
import static android.content.Intent.ACTION_MAIN;
import org.linphone.mediastream.Log;
import org.linphone.assistant.RemoteProvisioningActivity;
import org.linphone.tutorials.TutorialLauncherActivity;
@ -83,7 +82,6 @@ public class LinphoneLauncherActivity extends Activity {
}, 1000);
}
private class ServiceWaitThread extends Thread {
public void run() {
while (!LinphoneService.isReady()) {

View file

@ -29,10 +29,12 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
@ -85,6 +87,7 @@ import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -110,6 +113,7 @@ 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;
@ -354,6 +358,40 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
public void setUploadingImageStream(ByteArrayInputStream array){
this.mUploadingImageStream = array;
}
private void storeImage(LinphoneChatMessage msg) {
if (msg == null || msg.getFileTransferInformation() == null || msg.getAppData() == null) return;
File file = new File(Environment.getExternalStorageDirectory(), msg.getAppData());
Bitmap bm = BitmapFactory.decodeFile(file.getPath());
if (bm == null) return;
ContentValues values = new ContentValues();
values.put(Images.Media.TITLE, file.getName());
String extension = msg.getFileTransferInformation().getSubtype();
values.put(Images.Media.MIME_TYPE, "image/" + extension);
ContentResolver cr = getContext().getContentResolver();
Uri path = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
OutputStream stream;
try {
stream = cr.openOutputStream(path);
if (extension != null && extension.toLowerCase(Locale.getDefault()).equals("png")) {
bm.compress(Bitmap.CompressFormat.PNG, 100, stream);
} else {
bm.compress(Bitmap.CompressFormat.JPEG, 100, stream);
}
stream.close();
file.delete();
bm.recycle();
msg.setAppData(path.toString());
} catch (FileNotFoundException e) {
Log.e(e);
} catch (IOException e) {
Log.e(e);
}
}
@Override
public void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, LinphoneChatMessage.State state) {
@ -362,17 +400,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
mUploadPendingFileMessage = null;
mUploadingImageStream = null;
} else {
File file = new File(Environment.getExternalStorageDirectory(), msg.getAppData());
try {
Bitmap bm = BitmapFactory.decodeFile(file.getPath());
if (bm != null) {
String url = MediaStore.Images.Media.insertImage(getContext().getContentResolver(), file.getPath(), file.getName(), null);
msg.setAppData(url);
file.delete();
}
} catch (FileNotFoundException e) {
Log.e(e);
}
storeImage(msg);
removePendingMessage(msg);
}
}
@ -862,13 +890,16 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
mLastNetworkType=curtype;
}
}
if (mLc.isNetworkReachable()) {
// When network isn't available, push informations might not be set. This should fix the issue.
LinphonePreferences prefs = LinphonePreferences.instance();
prefs.setPushNotificationEnabled(prefs.isPushNotificationEnabled());
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void doDestroy() {
if (LinphoneService.isReady()) // indeed, no need to crash
ChatStorage.getInstance().close();
BluetoothManager.getInstance().destroy();
try {
mTimer.cancel();
@ -943,13 +974,6 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
LinphoneAddress from = message.getFrom();
String textMessage = message.getText();
String url = message.getExternalBodyUrl();
if (textMessage != null && textMessage.length() > 0) {
ChatStorage.getInstance().saveTextMessage(from.asStringUriOnly(), "", textMessage, message.getTime());
} else if (url != null && url.length() > 0) {
ChatStorage.getInstance().saveImageMessage(from.asStringUriOnly(), "", null, message.getExternalBodyUrl(), message.getTime());
}
try {
LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(from);
if (!mServiceContext.getResources().getBoolean(R.bool.disable_chat_message_notification)) {

View file

@ -19,12 +19,12 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneAddress.TransportType;
@ -32,6 +32,7 @@ import org.linphone.core.LinphoneAuthInfo;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.AdaptiveRateAlgorithm;
import org.linphone.core.LinphoneCore.FirewallPolicy;
import org.linphone.core.LinphoneCore.LinphoneLimeState;
import org.linphone.core.LinphoneCore.MediaEncryption;
import org.linphone.core.LinphoneCore.Transports;
import org.linphone.core.LinphoneCoreException;
@ -1017,7 +1018,7 @@ public class LinphonePreferences {
lpc.edit();
lpc.setContactUriParameters(contactInfos);
lpc.done();
Log.d("Push notif infos added to proxy config");
Log.d("Push notif infos added to proxy config " + lpc.getAddress().asStringUriOnly());
}
lc.refreshRegisters();
}
@ -1027,7 +1028,7 @@ public class LinphonePreferences {
lpc.edit();
lpc.setContactUriParameters(null);
lpc.done();
Log.d("Push notif infos removed from proxy config");
Log.d("Push notif infos removed from proxy config " + lpc.getAddress().asStringUriOnly());
}
lc.refreshRegisters();
}
@ -1287,46 +1288,6 @@ public class LinphonePreferences {
return getConfig().getString("app", "debug_popup_magic", null);
}
public Boolean audioPermAsked(){
return getConfig().getBool("app", "audio_perm", false);
}
public void neverAskAudioPerm(){
getConfig().setBool("app", "audio_perm", true);
}
public Boolean cameraPermAsked(){
return getConfig().getBool("app", "camera_perm", false);
}
public void neverAskCameraPerm(){
getConfig().setBool("app", "camera_perm", true);
}
public Boolean readContactsPermAsked(){
return getConfig().getBool("app", "read_contacts_perm", false);
}
public void neverAskReadContactsPerm(){
getConfig().setBool("app", "read_contacts_perm", true);
}
public Boolean writeContactsPermAsked(){
return getConfig().getBool("app", "write_contacts_perm", false);
}
public void neverAskWriteContactsPerm(){
getConfig().setBool("app", "write_contacts_perm", true);
}
public Boolean writeExternalStoragePermAsked(){
return getConfig().getBool("app", "write_external_storage_perm", false);
}
public void neverAskWriteExternalStoragePerm(){
getConfig().setBool("app", "write_external_storage_perm", true);
}
public String getActivityToLaunchOnIncomingReceived() {
return getConfig().getString("app", "incoming_call_activity", "org.linphone.LinphoneActivity");
}
@ -1334,4 +1295,36 @@ public class LinphonePreferences {
public void setActivityToLaunchOnIncomingReceived(String name) {
getConfig().setString("app", "incoming_call_activity", name);
}
public boolean getServiceNotificationVisibility() {
return getConfig().getBool("app", "show_service_notification", true);
}
public void setServiceNotificationVisibility(boolean enable) {
getConfig().setBool("app", "show_service_notification", enable);
}
public boolean isOverlayEnabled() {
return getConfig().getBool("app", "display_overlay", false);
}
public void enableOverlay(boolean enable) {
getConfig().setBool("app", "display_overlay", enable);
}
public LinphoneLimeState getLimeEncryption() {
return getLc().getLimeEncryption();
}
public void setLimeEncryption(LinphoneLimeState lime) {
getLc().setLimeEncryption(lime);
}
public boolean firstTimeAskingForPermission(String permission) {
boolean firstTime = getConfig().getBool("app", permission, true);
if (firstTime) {
getConfig().setBool("app", permission, false);
}
return firstTime;
}
}

View file

@ -34,6 +34,7 @@ import org.linphone.core.LinphoneCoreListenerBase;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.mediastream.Log;
import org.linphone.mediastream.Version;
import org.linphone.ui.LinphoneOverlay;
import android.annotation.TargetApi;
import android.app.Activity;
@ -46,7 +47,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
@ -56,6 +56,7 @@ import android.os.IBinder;
import android.os.SystemClock;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.view.WindowManager;
/**
*
@ -118,6 +119,8 @@ public final class LinphoneService extends Service {
private boolean mDisableRegistrationStatus;
private LinphoneCoreListenerBase mListener;
public static int notifcationsPriority = (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41) ? Notification.PRIORITY_MIN : 0);
private WindowManager mWindowManager;
private LinphoneOverlay mOverlay;
public int getMessageNotifCount() {
return mMsgNotifCount;
@ -126,6 +129,31 @@ public final class LinphoneService extends Service {
public void resetMessageNotifCount() {
mMsgNotifCount = 0;
}
private boolean displayServiceNotification() {
return LinphonePreferences.instance().getServiceNotificationVisibility();
}
public void showServiceNotification() {
startForegroundCompat(NOTIF_ID, mNotif);
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc == null) return;
LinphoneProxyConfig lpc = lc.getDefaultProxyConfig();
if (lpc != null) {
if (lpc.isRegistered()) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_registered);
} else {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_register_failure);
}
} else {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_started);
}
}
public void hideServiceNotification() {
stopForegroundCompat(NOTIF_ID);
}
@SuppressWarnings("unchecked")
@Override
@ -182,6 +210,10 @@ public final class LinphoneService extends Service {
if (state == LinphoneCall.State.IncomingReceived) {
onIncomingReceived();
}
if (state == State.CallEnd || state == State.CallReleased || state == State.Error) {
destroyOverlay();
}
if (state == State.StreamsRunning) {
// Workaround bug current call seems to be updated after state changed to streams running
@ -195,7 +227,7 @@ public final class LinphoneService extends Service {
@Override
public void globalState(LinphoneCore lc,LinphoneCore.GlobalState state, String message) {
if (state == GlobalState.GlobalOn) {
if (state == GlobalState.GlobalOn && displayServiceNotification()) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_started);
}
}
@ -207,15 +239,15 @@ public final class LinphoneService extends Service {
// return;
// }
if (!mDisableRegistrationStatus) {
if (state == RegistrationState.RegistrationOk && LinphoneManager.getLc().getDefaultProxyConfig() != null && LinphoneManager.getLc().getDefaultProxyConfig().isRegistered()) {
if (displayServiceNotification() && state == RegistrationState.RegistrationOk && LinphoneManager.getLc().getDefaultProxyConfig() != null && LinphoneManager.getLc().getDefaultProxyConfig().isRegistered()) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_registered);
}
if ((state == RegistrationState.RegistrationFailed || state == RegistrationState.RegistrationCleared) && (LinphoneManager.getLc().getDefaultProxyConfig() == null || !LinphoneManager.getLc().getDefaultProxyConfig().isRegistered())) {
if (displayServiceNotification() && (state == RegistrationState.RegistrationFailed || state == RegistrationState.RegistrationCleared) && (LinphoneManager.getLc().getDefaultProxyConfig() == null || !LinphoneManager.getLc().getDefaultProxyConfig().isRegistered())) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_register_failure);
}
if (state == RegistrationState.RegistrationNone) {
if (displayServiceNotification() && state == RegistrationState.RegistrationNone) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_started);
}
}
@ -241,7 +273,9 @@ public final class LinphoneService extends Service {
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, ContactsManager.getInstance());
startForegroundCompat(NOTIF_ID, mNotif);
if (displayServiceNotification()) {
startForegroundCompat(NOTIF_ID, mNotif);
}
if (!mTestDelayElapsed) {
// Only used when testing. Simulates a 5 seconds delay for launching service
@ -259,8 +293,30 @@ public final class LinphoneService extends Service {
, SystemClock.elapsedRealtime()+600000
, 600000
, mkeepAlivePendingIntent);
}
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
}
public void createOverlay() {
if (mOverlay != null) destroyOverlay();
LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
if (call == null || !call.getCurrentParamsCopy().getVideoEnabled()) return;
mOverlay = new LinphoneOverlay(this);
WindowManager.LayoutParams params = mOverlay.getWindowManagerLayoutParams();
params.x = 0;
params.y = 0;
mWindowManager.addView(mOverlay, params);
}
public void destroyOverlay() {
if (mOverlay != null) {
mWindowManager.removeViewImmediate(mOverlay);
mOverlay.destroy();
}
mOverlay = null;
}
private enum IncallIconState {INCALL, PAUSE, VIDEO, IDLE}
private IncallIconState mCurrentIncallIconState = IncallIconState.IDLE;
@ -505,7 +561,7 @@ public final class LinphoneService extends Service {
mDisableRegistrationStatus = true;
}
public synchronized void sendNotification(int level, int textId) {
private synchronized void sendNotification(int level, int textId) {
String text = getString(textId);
if (text.contains("%s") && LinphoneManager.getLc() != null) {
// Test for null lc is to avoid a NPE when Android mess up badly with the String resources.
@ -559,6 +615,7 @@ public final class LinphoneService extends Service {
@Override
public synchronized void onDestroy() {
destroyOverlay();
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.removeListener(mListener);
@ -593,10 +650,10 @@ public final class LinphoneService extends Service {
Intent notifIntent = new Intent(this, incomingReceivedActivity);
mNotifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (mNotif != null) {
/*if (mNotif != null) {
mNotif.contentIntent = mNotifContentIntent;
}
notifyWrapper(NOTIF_ID, mNotif);
notifyWrapper(NOTIF_ID, mNotif);*/
}
protected void onIncomingReceived() {

View file

@ -455,5 +455,14 @@ public final class LinphoneUtils {
Log.e(e);
}
}
public static String getExtensionFromFileName(String fileName) {
String extension = null;
int i = fileName.lastIndexOf('.');
if (i > 0) {
extension = fileName.substring(i+1);
}
return extension;
}
}

View file

@ -18,8 +18,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.linphone;
import org.linphone.mediastream.Log;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -32,26 +30,18 @@ import android.telephony.TelephonyManager;
*
*/
public class PhoneStateChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String extraState = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (TelephonyManager.EXTRA_STATE_RINGING.equals(extraState) || TelephonyManager.EXTRA_STATE_OFFHOOK.equals(extraState)) {
LinphoneManager.setGsmIdle(false);
if (!LinphoneManager.isInstanciated()) {
Log.i("GSM call state changed but manager not instantiated");
return;
}
LinphoneManager.getLc().pauseAllCalls();
} else if (TelephonyManager.EXTRA_STATE_IDLE.equals(extraState)) {
LinphoneManager.setGsmIdle(true);
}
// do nothing
}
}

View file

@ -19,12 +19,14 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
import org.linphone.core.LinphoneCore.LinphoneLimeState;
import org.linphone.core.LinphoneCore.MediaEncryption;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreListenerBase;
@ -37,10 +39,10 @@ import org.linphone.tools.OpenH264DownloadHelper;
import org.linphone.purchase.InAppPurchaseActivity;
import org.linphone.ui.LedPreference;
import org.linphone.ui.PreferencesListFragment;
import android.content.Intent;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.preference.CheckBoxPreference;
@ -56,21 +58,19 @@ import android.preference.PreferenceScreen;
* @author Sylvain Berfini
*/
public class SettingsFragment extends PreferencesListFragment {
private static final int WIZARD_INTENT = 1;
private static final int STORE_INTENT = 2;
private LinphonePreferences mPrefs;
private Handler mHandler = new Handler();
private LinphoneCoreListenerBase mListener;
public SettingsFragment() {
super(R.xml.preferences);
mPrefs = LinphonePreferences.instance();
}
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
mPrefs = LinphonePreferences.instance();
removePreviousPreferencesFile(); // Required when updating the preferences order
addPreferencesFromResource(R.xml.preferences);
// Init the settings page interface
initSettings();
setListeners();
@ -100,6 +100,11 @@ public class SettingsFragment extends PreferencesListFragment {
}
};
}
private void removePreviousPreferencesFile() {
File dir = new File(LinphoneActivity.instance().getFilesDir().getAbsolutePath() + "shared_prefs");
dir.delete();
}
// Inits the values or the listener on some settings
private void initSettings() {
@ -107,6 +112,7 @@ public class SettingsFragment extends PreferencesListFragment {
initAudioSettings();
initVideoSettings();
initCallSettings();
initChatSettings();
initNetworkSettings();
initAdvancedSettings();
@ -134,6 +140,7 @@ public class SettingsFragment extends PreferencesListFragment {
setAudioPreferencesListener();
setVideoPreferencesListener();
setCallPreferencesListener();
setChatPreferencesListener();
setNetworkPreferencesListener();
setAdvancedPreferencesListener();
}
@ -436,6 +443,30 @@ public class SettingsFragment extends PreferencesListFragment {
pref.setSummary(value);
pref.setValue(value);
}
private void initLimeEncryptionPreference(ListPreference pref) {
List<CharSequence> entries = new ArrayList<CharSequence>();
List<CharSequence> values = new ArrayList<CharSequence>();
entries.add(getString(R.string.lime_encryption_entry_disabled));
values.add(LinphoneLimeState.Disabled.toString());
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc == null || !lc.isLimeEncryptionAvailable()) {
setListPreferenceValues(pref, entries, values);
pref.setEnabled(false);
return;
}
entries.add(getString(R.string.lime_encryption_entry_mandatory));
values.add(LinphoneLimeState.Mandatory.toString());
entries.add(getString(R.string.lime_encryption_entry_preferred));
values.add(LinphoneLimeState.Preferred.toString());
setListPreferenceValues(pref, entries, values);
LinphoneLimeState lime = mPrefs.getLimeEncryption();
pref.setSummary(lime.toString());
pref.setValue(lime.toString());
}
private static void setListPreferenceValues(ListPreference pref, List<CharSequence> entries, List<CharSequence> values) {
CharSequence[] contents = new CharSequence[entries.size()];
@ -639,6 +670,7 @@ public class SettingsFragment extends PreferencesListFragment {
((CheckBoxPreference) findPreference(getString(R.string.pref_video_use_front_camera_key))).setChecked(mPrefs.useFrontCam());
((CheckBoxPreference) findPreference(getString(R.string.pref_video_initiate_call_with_video_key))).setChecked(mPrefs.shouldInitiateVideoCall());
((CheckBoxPreference) findPreference(getString(R.string.pref_video_automatically_accept_video_key))).setChecked(mPrefs.shouldAutomaticallyAcceptVideoRequests());
((CheckBoxPreference) findPreference(getString(R.string.pref_overlay_key))).setChecked(mPrefs.isOverlayEnabled());
}
private void updateVideoPreferencesAccordingToPreset() {
@ -732,6 +764,21 @@ public class SettingsFragment extends PreferencesListFragment {
return true;
}
});
findPreference(getString(R.string.pref_overlay_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean enable = (Boolean) newValue;
if (enable) {
if (LinphoneActivity.instance().checkAndRequestOverlayPermission()) {
mPrefs.enableOverlay(true);
}
} else {
mPrefs.enableOverlay(false);
}
return true;
}
});
}
private void initCallSettings() {
@ -788,6 +835,47 @@ public class SettingsFragment extends PreferencesListFragment {
});
}
private void initChatSettings() {
setPreferenceDefaultValueAndSummary(R.string.pref_image_sharing_server_key, mPrefs.getSharingPictureServerUrl());
initLimeEncryptionPreference((ListPreference) findPreference(getString(R.string.pref_use_lime_encryption_key)));
}
private void setChatPreferencesListener() {
findPreference(getString(R.string.pref_image_sharing_server_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String value = (String) newValue;
mPrefs.setSharingPictureServerUrl(value);
preference.setSummary(value);
return true;
}
});
findPreference(getString(R.string.pref_use_lime_encryption_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String value = newValue.toString();
LinphoneLimeState lime = LinphoneLimeState.Disabled;
if (value.equals(LinphoneLimeState.Mandatory.toString()))
lime = LinphoneLimeState.Mandatory;
else if (value.equals(LinphoneLimeState.Preferred.toString()))
lime = LinphoneLimeState.Preferred;
mPrefs.setLimeEncryption(lime);
lime = mPrefs.getLimeEncryption();
if (lime == LinphoneLimeState.Disabled) {
preference.setSummary(getString(R.string.lime_encryption_entry_disabled));
} else if (lime == LinphoneLimeState.Mandatory) {
preference.setSummary(getString(R.string.lime_encryption_entry_mandatory));
} else if (lime == LinphoneLimeState.Preferred) {
preference.setSummary(getString(R.string.lime_encryption_entry_preferred));
}
return true;
}
});
}
private void initNetworkSettings() {
initMediaEncryptionPreference((ListPreference) findPreference(getString(R.string.pref_media_encryption_key)));
@ -929,8 +1017,8 @@ public class SettingsFragment extends PreferencesListFragment {
((CheckBoxPreference)findPreference(getString(R.string.pref_debug_key))).setChecked(mPrefs.isDebugEnabled());
((CheckBoxPreference)findPreference(getString(R.string.pref_background_mode_key))).setChecked(mPrefs.isBackgroundModeEnabled());
((CheckBoxPreference)findPreference(getString(R.string.pref_animation_enable_key))).setChecked(mPrefs.areAnimationsEnabled());
((CheckBoxPreference)findPreference(getString(R.string.pref_service_notification_key))).setChecked(mPrefs.getServiceNotificationVisibility());
((CheckBoxPreference)findPreference(getString(R.string.pref_autostart_key))).setChecked(mPrefs.isAutoStartEnabled());
setPreferenceDefaultValueAndSummary(R.string.pref_image_sharing_server_key, mPrefs.getSharingPictureServerUrl());
setPreferenceDefaultValueAndSummary(R.string.pref_remote_provisioning_key, mPrefs.getRemoteProvisioningUrl());
setPreferenceDefaultValueAndSummary(R.string.pref_display_name_key, mPrefs.getDefaultDisplayName());
setPreferenceDefaultValueAndSummary(R.string.pref_user_name_key, mPrefs.getDefaultUsername());
@ -964,6 +1052,20 @@ public class SettingsFragment extends PreferencesListFragment {
}
});
findPreference(getString(R.string.pref_service_notification_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean value = (Boolean) newValue;
mPrefs.setServiceNotificationVisibility(value);
if (value) {
LinphoneService.instance().showServiceNotification();
} else {
LinphoneService.instance().hideServiceNotification();
}
return true;
}
});
findPreference(getString(R.string.pref_autostart_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
@ -973,16 +1075,6 @@ public class SettingsFragment extends PreferencesListFragment {
}
});
findPreference(getString(R.string.pref_image_sharing_server_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String value = (String) newValue;
mPrefs.setSharingPictureServerUrl(value);
preference.setSummary(value);
return true;
}
});
findPreference(getString(R.string.pref_remote_provisioning_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {

View file

@ -44,6 +44,7 @@ import android.app.FragmentTransaction;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.ColorDrawable;
@ -200,7 +201,8 @@ private static AssistantActivity instance;
if (getResources().getBoolean(R.bool.setup_cancel_move_to_back)) {
moveTaskToBack(true);
} else {
setResult(Activity.RESULT_CANCELED);
LinphonePreferences.instance().firstLaunchSuccessful();
startActivity(new Intent().setClass(this, LinphoneActivity.class));
finish();
}
} else if (id == R.id.back) {
@ -216,7 +218,8 @@ private static AssistantActivity instance;
if (getResources().getBoolean(R.bool.setup_cancel_move_to_back)) {
moveTaskToBack(true);
} else {
setResult(Activity.RESULT_CANCELED);
LinphonePreferences.instance().firstLaunchSuccessful();
startActivity(new Intent().setClass(this, LinphoneActivity.class));
finish();
}
} else if (currentFragment == AssistantFragmentsEnum.LOGIN
@ -241,8 +244,12 @@ private static AssistantActivity instance;
}
public void checkAndRequestAudioPermission() {
if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) != PackageManager.PERMISSION_GRANTED) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
int recordAudio = getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName());
Log.i("[Permission] Record audio permission is " + (recordAudio == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (recordAudio != PackageManager.PERMISSION_GRANTED) {
if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.RECORD_AUDIO) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
Log.i("[Permission] Asking for record audio");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, PERMISSIONS_REQUEST_RECORD_AUDIO);
}
}
@ -250,8 +257,12 @@ private static AssistantActivity instance;
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
for (int i = 0; i < permissions.length; i++) {
Log.i("[Permission] " + permissions[i] + " is " + (grantResults[i] == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
}
if (requestCode == PERMISSIONS_REQUEST_RECORD_AUDIO) {
if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
launchEchoCancellerCalibration(true);
} else {
isEchoCalibrationFinished();
@ -541,10 +552,7 @@ private static AssistantActivity instance;
public void success() {
mPrefs.firstLaunchSuccessful();
if(LinphoneActivity.instance() != null) {
LinphoneActivity.instance().isNewProxyConfig();
setResult(Activity.RESULT_OK);
}
startActivity(new Intent().setClass(this, LinphoneActivity.class).putExtra("isNewProxyConfig", true));
finish();
}

View file

@ -69,6 +69,7 @@ public class ApiElevenPlus {
| Notification.DEFAULT_SOUND
| Notification.DEFAULT_VIBRATE)
.setWhen(System.currentTimeMillis())
.setNumber(msgCount)
.setLargeIcon(contactIcon).getNotification();
return notif;

View file

@ -3,12 +3,9 @@ package org.linphone.compatibility;
import java.util.ArrayList;
import java.util.List;
import org.linphone.Contact;
import org.linphone.LinphoneContact;
import org.linphone.LinphoneUtils;
import org.linphone.R;
import org.linphone.core.LinphoneAddress;
import org.linphone.mediastream.Log;
import android.annotation.TargetApi;
import android.content.ContentProviderOperation;
@ -195,89 +192,4 @@ public class ApiNinePlus {
cursor.close();
return null;
}
//Linphone Contacts Tag
public static void addLinphoneContactTag(Context context, ArrayList<ContentProviderOperation> ops, String newAddress, String rawContactId){
if(rawContactId != null) {
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
.withValue(ContactsContract.Data.MIMETYPE, context.getString(R.string.sync_mimetype))
.withValue(ContactsContract.Data.DATA1, newAddress)
.withValue(ContactsContract.Data.DATA2, context.getString(R.string.app_name))
.withValue(ContactsContract.Data.DATA3, newAddress)
.build()
);
}
}
public static void updateLinphoneContactTag(Context context, ArrayList<ContentProviderOperation> ops, String newAddress, String oldAddress, String rawContactId){
if(rawContactId != null) {
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + ContactsContract.Data.DATA1 + "=? ", new String[]{rawContactId, oldAddress})
.withValue(ContactsContract.Data.DATA1, newAddress)
.withValue(ContactsContract.Data.DATA2, context.getString(R.string.app_name))
.withValue(ContactsContract.Data.DATA3, newAddress)
.build());
}
}
public static void deleteLinphoneContactTag(ArrayList<ContentProviderOperation> ops , String oldAddress, String rawContactId){
if(rawContactId != null) {
String select = ContactsContract.Data.RAW_CONTACT_ID + "=? AND "
+ ContactsContract.Data.DATA1 + "= ?";
String[] args = new String[]{rawContactId, oldAddress};
ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
.withSelection(select, args)
.build());
}
}
public static void createLinphoneContactTag(Context context, ContentResolver contentResolver, Contact contact, String rawContactId){
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
if (contact != null) {
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, context.getString(R.string.sync_account_type))
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, context.getString(R.string.sync_account_name))
.build()
);
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contact.getName())
.build()
);
List<String> numbersOrAddresses = contact.getNumbersOrAddresses();
for (String numberOrAddress : numbersOrAddresses) {
if (LinphoneUtils.isSipAddress(numberOrAddress)) {
if (numberOrAddress.startsWith("sip:")){
numberOrAddress = numberOrAddress.substring(4);
}
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, context.getString(R.string.sync_mimetype))
.withValue(ContactsContract.Data.DATA1, numberOrAddress)
.withValue(ContactsContract.Data.DATA2, context.getString(R.string.app_name))
.withValue(ContactsContract.Data.DATA3, numberOrAddress)
.build()
);
}
}
ops.add(ContentProviderOperation.newUpdate(ContactsContract.AggregationExceptions.CONTENT_URI)
.withValue(ContactsContract.AggregationExceptions.TYPE, ContactsContract.AggregationExceptions.TYPE_KEEP_TOGETHER)
.withValue(ContactsContract.AggregationExceptions.RAW_CONTACT_ID1, rawContactId)
.withValueBackReference(ContactsContract.AggregationExceptions.RAW_CONTACT_ID2, 0).build());
try {
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) {
Log.e(e);
}
}
}
}

View file

@ -56,6 +56,7 @@ public class ApiSixteenPlus {
| Notification.DEFAULT_VIBRATE)
.setWhen(System.currentTimeMillis())
.setLargeIcon(contactIcon)
.setNumber(msgCount)
.build();
return notif;

View file

@ -54,6 +54,7 @@ public class ApiTwentyOnePlus {
.setCategory(Notification.CATEGORY_MESSAGE)
.setVisibility(Notification.VISIBILITY_PRIVATE)
.setPriority(Notification.PRIORITY_HIGH)
.setNumber(msgCount)
.build();
return notif;

View file

@ -21,7 +21,6 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.linphone.Contact;
import org.linphone.LinphoneContact;
import org.linphone.core.LinphoneAddress;
import org.linphone.mediastream.Version;
@ -38,6 +37,7 @@ import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.Uri;
import android.preference.Preference;
import android.provider.Settings;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
/**
@ -300,32 +300,6 @@ public class Compatibility {
ApiFivePlus.deleteSipAddressFromContact(ops, oldSipAddress, contactID);
}
//Linphone Contacts Tag
public static void addLinphoneContactTag(Context context, ArrayList<ContentProviderOperation> ops, String newSipAddress, String rawContactId) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
ApiNinePlus.addLinphoneContactTag(context, ops, newSipAddress, rawContactId);
}
}
public static void updateLinphoneContactTag(Context context, ArrayList<ContentProviderOperation> ops, String newSipAddress, String oldSipAddress, String rawContactId) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
ApiNinePlus.updateLinphoneContactTag(context, ops, newSipAddress, oldSipAddress, rawContactId);
}
}
public static void deleteLinphoneContactTag(ArrayList<ContentProviderOperation> ops, String oldSipAddress, String rawContactId) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
ApiNinePlus.deleteLinphoneContactTag(ops, oldSipAddress, rawContactId);
}
}
public static void createLinphoneContactTag(Context context, ContentResolver contentResolver, Contact contact, String rawContactId) {
if (Version.sdkAboveOrEqual(Version.API09_GINGERBREAD_23)) {
ApiNinePlus.createLinphoneContactTag(context, contentResolver, contact, rawContactId);
}
}
//End of Linphone Contact Tag
public static void removeGlobalLayoutListener(ViewTreeObserver viewTreeObserver, OnGlobalLayoutListener keyboardListener) {
if (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41)) {
ApiSixteenPlus.removeGlobalLayoutListener(viewTreeObserver, keyboardListener);
@ -363,4 +337,11 @@ public class Compatibility {
return ApiEightPlus.getAudioManagerEventForBluetoothConnectionStateChangedEvent();
}
}
public static boolean canDrawOverlays(Context context) {
if (Version.sdkAboveOrEqual(Version.API23_MARSHMALLOW_60)) {
return Settings.canDrawOverlays(context);
}
return true;
}
}

View file

@ -25,6 +25,7 @@ import org.linphone.LinphonePreferences;
import org.linphone.LinphoneService;
import org.linphone.R;
import org.linphone.UIThreadDispatcher;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.mediastream.Log;
import android.content.Context;
@ -44,12 +45,19 @@ public class GCMService extends GCMBaseIntentService {
@Override
protected void onError(Context context, String errorId) {
boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled();
LinphoneCoreFactory.instance().enableLogCollection(isDebugEnabled);
LinphoneCoreFactory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name));
Log.e("Error while registering push notification : " + errorId);
}
@Override
protected void onMessage(Context context, Intent intent) {
boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled();
LinphoneCoreFactory.instance().enableLogCollection(isDebugEnabled);
LinphoneCoreFactory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name));
Log.d("Push notification received");
if (!LinphoneService.isReady()) {
startService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class));
} else if (LinphoneManager.isInstanciated() && LinphoneManager.getLc().getCallsNb() == 0) {
@ -68,13 +76,21 @@ public class GCMService extends GCMBaseIntentService {
@Override
protected void onRegistered(Context context, String regId) {
boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled();
LinphoneCoreFactory.instance().enableLogCollection(isDebugEnabled);
LinphoneCoreFactory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name));
Log.d("Registered push notification : " + regId);
LinphonePreferences.instance().setPushNotificationRegistrationID(regId);
}
@Override
protected void onUnregistered(Context context, String regId) {
boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled();
LinphoneCoreFactory.instance().enableLogCollection(isDebugEnabled);
LinphoneCoreFactory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name));
Log.w("Unregistered push notification : " + regId);
LinphonePreferences.instance().setPushNotificationRegistrationID(null);
}

View file

@ -173,7 +173,8 @@ public class BubbleChat implements LinphoneChatMessage.LinphoneChatMessageListen
public void onClick(View v) {
if (mContext.getPackageManager().checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, mContext.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
v.setEnabled(false);
String filename = context.getString(R.string.temp_photo_name_with_date).replace("%s", String.valueOf(System.currentTimeMillis()));
String extension = nativeMessage.getFileTransferInformation().getSubtype();
String filename = context.getString(R.string.temp_photo_name_with_date).replace("%s", String.valueOf(System.currentTimeMillis())) + "." + extension;
File file = new File(Environment.getExternalStorageDirectory(), filename);
nativeMessage.setAppData(filename);
LinphoneManager.getInstance().addDownloadMessagePending(nativeMessage);

View file

@ -0,0 +1,119 @@
package org.linphone.ui;
import org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphoneService;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCallParams;
import org.linphone.mediastream.video.AndroidVideoWindowImpl;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
public class LinphoneOverlay extends org.linphone.mediastream.video.display.GL2JNIView {
private WindowManager wm;
private WindowManager.LayoutParams params;
private DisplayMetrics metrics;
private float x;
private float y;
private float touchX;
private float touchY;
private AndroidVideoWindowImpl androidVideoWindowImpl;
public LinphoneOverlay(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
androidVideoWindowImpl = new AndroidVideoWindowImpl(this, null, new AndroidVideoWindowImpl.VideoWindowListener() {
public void onVideoRenderingSurfaceReady(AndroidVideoWindowImpl vw, SurfaceView surface) {
LinphoneManager.getLc().setVideoWindow(vw);
}
public void onVideoRenderingSurfaceDestroyed(AndroidVideoWindowImpl vw) {
}
public void onVideoPreviewSurfaceReady(AndroidVideoWindowImpl vw, SurfaceView surface) {
}
public void onVideoPreviewSurfaceDestroyed(AndroidVideoWindowImpl vw) {
}
});
LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
LinphoneCallParams callParams = call.getCurrentParamsCopy();
params.width = callParams.getReceivedVideoSize().width;
params.height = callParams.getReceivedVideoSize().height;
LinphoneManager.getLc().setVideoWindow(androidVideoWindowImpl);
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Context context = LinphoneService.instance();
Intent intent = new Intent(context, LinphoneActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
}
public LinphoneOverlay(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LinphoneOverlay(Context context) {
this(context, null);
}
public void destroy() {
androidVideoWindowImpl.release();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
x = event.getRawX();
y = event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchX = event.getX();
touchY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
updateViewPostion();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
touchX = touchY = 0;
break;
default:
break;
}
return super.onTouchEvent(event);
}
private void updateViewPostion() {
params.x = Math.min(Math.max(0, (int) (x - touchX)), metrics.widthPixels - getMeasuredWidth());
params.y = Math.min(Math.max(0, (int) (y - touchY)), metrics.heightPixels - getMeasuredHeight());
wm.updateViewLayout(this, params);
}
public WindowManager.LayoutParams getWindowManagerLayoutParams() {
return params;
}
}

View file

@ -2,7 +2,6 @@ package org.linphone.test;
import junit.framework.Assert;
import org.linphone.ChatStorage;
import org.linphone.LinphoneActivity;
import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatMessage.State;
@ -29,9 +28,9 @@ public class Chat extends SampleTest {
public void testAEmptyChatHistory() {
goToChat();
ChatStorage chatStorage = ChatStorage.getInstance();
for (String conversation : chatStorage.getChatList()) {
chatStorage.removeDiscussion(conversation);
LinphoneChatRoom[] chats = LinphoneTestManager.getInstance().getLc().getChatRooms();
for (LinphoneChatRoom chatroom : chats) {
chatroom.deleteHistory();
}
Assert.assertEquals(0, LinphoneActivity.instance().getUnreadMessageCount());