diff --git a/.gitmodules b/.gitmodules
index fa0235b31..6778bad1b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -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
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7d99c6672..909529b19 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -27,6 +27,7 @@
+
@@ -43,6 +44,8 @@
+
+
@@ -75,7 +78,7 @@
-
+
@@ -94,7 +97,6 @@
@@ -104,7 +106,6 @@
diff --git a/custom_rules.xml b/custom_rules.xml
index 8eb805335..45b003dc2 100644
--- a/custom_rules.xml
+++ b/custom_rules.xml
@@ -8,50 +8,6 @@
failonerror="false" />
-
- Generate JNI header
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/prepare.py b/prepare.py
index 1e2316165..468acddef 100755
--- a/prepare.py
+++ b/prepare.py
@@ -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
diff --git a/res/layout-sw533dp-land/assistant_linphone_login.xml b/res/layout-sw533dp-land/assistant_linphone_login.xml
index 54239505d..8122c8ccd 100644
--- a/res/layout-sw533dp-land/assistant_linphone_login.xml
+++ b/res/layout-sw533dp-land/assistant_linphone_login.xml
@@ -78,6 +78,13 @@
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
+
+
diff --git a/res/values/non_localizable_custom.xml b/res/values/non_localizable_custom.xml
index 4266988c7..437890f35 100644
--- a/res/values/non_localizable_custom.xml
+++ b/res/values/non_localizable_custom.xml
@@ -6,7 +6,7 @@
stun.linphone.org
org.linphone
- vnd.android.cursor.item/org.linphone.profile
+ vnd.android.cursor.item/org.linphone.profile
false
false
@@ -68,10 +68,8 @@
linphone-android@belledonne-communications.com
false
-
- linphone-android-photo-temp.jpg
- linphone-android-photo-%s.jpg
-
+ linphone-android-photo-temp
+ linphone-android-photo-%s
false
false
diff --git a/res/values/non_localizable_strings.xml b/res/values/non_localizable_strings.xml
index f204815ee..f3c4727f7 100644
--- a/res/values/non_localizable_strings.xml
+++ b/res/values/non_localizable_strings.xml
@@ -59,6 +59,7 @@
pref_wifi_only_key
+ pref_overlay_key
pref_video_use_front_camera_key
pref_video_codec_h263_key
pref_video_codec_mpeg4_key
@@ -71,6 +72,7 @@
pref_preferred_video_fps_key
pref_bandwidth_limit_key
pref_animation_enable_key
+ pref_service_notification_key
pref_escape_plus_key
pref_friendlist_subscribe_key
pref_echo_cancellation_key
@@ -197,4 +199,6 @@
- Send logs
- Cancel
+
+ pref_use_lime_encryption_key
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f673d0845..f6ce8a7d5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -20,7 +20,6 @@
dd/MM, HH:mm
dd/MM
HH:mm
- linphone-mms-%s.jpg
Username
@@ -255,6 +254,8 @@
Video
+ Video overlay
+ Display call video in overlay when outside the application
Use front camera
Initiate video calls
Always send video requests
@@ -272,6 +273,15 @@
Send RFC2833 DTMFs
Send SIP INFO DTMFs
Voice mail URI
+
+
+ Chat
+ Sharing server
+ Do not edit unless you know what you are doing!
+ Use LIME encryption
+ Disabled
+ Mandatory
+ Preferred
Network
@@ -294,9 +304,9 @@
Debug
Background mode
Enable Animations
+ Enable service notification
Start at boot time
Incoming call hangup (in seconds)
- Sharing server
Remote provisioning
Primary account
Display name
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
index 8eab25ca6..be34cd865 100644
--- a/res/xml/preferences.xml
+++ b/res/xml/preferences.xml
@@ -111,12 +111,17 @@
android:title="@string/pref_bandwidth_limit"
android:key="@string/pref_bandwidth_limit_key"
android:numeric="integer" />
+
+
-
+
@@ -136,6 +141,20 @@
android:key="@string/pref_voice_mail_key"/>
+
+
+
+
+
+
+
+
@@ -202,6 +221,10 @@
android:title="@string/pref_background_mode"
android:key="@string/pref_background_mode_key"/>
+
+
@@ -215,10 +238,6 @@
android:key="@string/pref_incoming_call_timeout_key"
android:layout="@layout/hidden"/>
-
-
diff --git a/src/org/linphone/CallActivity.java b/src/org/linphone/CallActivity.java
index afdbd8b60..321d0a80a 100644
--- a/src/org/linphone/CallActivity.java
+++ b/src/org/linphone/CallActivity.java
@@ -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()) {
diff --git a/src/org/linphone/CallIncomingActivity.java b/src/org/linphone/CallIncomingActivity.java
index 2e55230c4..e33b052ad 100644
--- a/src/org/linphone/CallIncomingActivity.java
+++ b/src/org/linphone/CallIncomingActivity.java
@@ -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 permissionsList = new ArrayList();
+
+ 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"));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/org/linphone/CallOutgoingActivity.java b/src/org/linphone/CallOutgoingActivity.java
index 62a107206..b3ad9b00c 100644
--- a/src/org/linphone/CallOutgoingActivity.java
+++ b/src/org/linphone/CallOutgoingActivity.java
@@ -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 permissionsList = new ArrayList();
+
+ 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"));
+ }
+ }
}
diff --git a/src/org/linphone/CallVideoFragment.java b/src/org/linphone/CallVideoFragment.java
index 1bc890fd6..31d65389e 100644
--- a/src/org/linphone/CallVideoFragment.java
+++ b/src/org/linphone/CallVideoFragment.java
@@ -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();
}
diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java
index 687d9d581..6c5cdafd8 100644
--- a/src/org/linphone/ChatFragment.java
+++ b/src/org/linphone/ChatFragment.java
@@ -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);
diff --git a/src/org/linphone/ChatListFragment.java b/src/org/linphone/ChatListFragment.java
index 497281f5f..c303e0554 100644
--- a/src/org/linphone/ChatListFragment.java
+++ b/src/org/linphone/ChatListFragment.java
@@ -57,7 +57,7 @@ import android.widget.TextView;
*/
public class ChatListFragment extends Fragment implements OnClickListener, OnItemClickListener {
private LayoutInflater mInflater;
- private List mConversations, mDrafts;
+ private List 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;
}
diff --git a/src/org/linphone/ChatStorage.java b/src/org/linphone/ChatStorage.java
deleted file mode 100644
index a685620ae..000000000
--- a/src/org/linphone/ChatStorage.java
+++ /dev/null
@@ -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 getDrafts() {
- List drafts = new ArrayList();
-
- 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 getChatList() {
- ArrayList chatList = new ArrayList();
-
- LinphoneChatRoom[] chats = LinphoneManager.getLc().getChatRooms();
- List rooms = new ArrayList();
-
- for (LinphoneChatRoom chatroom : chats) {
- if (chatroom.getHistorySize() > 0) {
- rooms.add(chatroom);
- }
- }
-
- if (rooms.size() > 1) {
- Collections.sort(rooms, new Comparator() {
- @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);
- }
- }
-}
diff --git a/src/org/linphone/ContactDetailsFragment.java b/src/org/linphone/ContactDetailsFragment.java
index 1c2c8d11c..b77fa72e9 100644
--- a/src/org/linphone/ContactDetailsFragment.java
+++ b/src/org/linphone/ContactDetailsFragment.java
@@ -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()) {
diff --git a/src/org/linphone/ContactEditorFragment.java b/src/org/linphone/ContactEditorFragment.java
index e94aefdc0..01865a037 100644
--- a/src/org/linphone/ContactEditorFragment.java
+++ b/src/org/linphone/ContactEditorFragment.java
@@ -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)
diff --git a/src/org/linphone/ContactsManager.java b/src/org/linphone/ContactsManager.java
index 78b7ef8b5..48d42e69d 100644
--- a/src/org/linphone/ContactsManager.java
+++ b/src/org/linphone/ContactsManager.java
@@ -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 fetchContactsAsync() {
List contacts = new ArrayList();
- 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);
}
diff --git a/src/org/linphone/KeepAliveHandler.java b/src/org/linphone/KeepAliveHandler.java
index 7c3ec6fee..9b554e9fa 100644
--- a/src/org/linphone/KeepAliveHandler.java
+++ b/src/org/linphone/KeepAliveHandler.java
@@ -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
}
-
}
-
}
-
}
diff --git a/src/org/linphone/KeepAliveReceiver.java b/src/org/linphone/KeepAliveReceiver.java
index 321953df1..06f7e532b 100644
--- a/src/org/linphone/KeepAliveReceiver.java
+++ b/src/org/linphone/KeepAliveReceiver.java
@@ -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);
}
}
-
}
-
}
diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java
index da1e71f3e..e33e90058 100644
--- a/src/org/linphone/LinphoneActivity.java
+++ b/src/org/linphone/LinphoneActivity.java
@@ -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 getChatList() {
- return getChatStorage().getChatList();
- }
+ ArrayList chatList = new ArrayList();
- public List getDraftChatList() {
- return getChatStorage().getDrafts();
+ LinphoneChatRoom[] chats = LinphoneManager.getLc().getChatRooms();
+ List rooms = new ArrayList();
+
+ for (LinphoneChatRoom chatroom : chats) {
+ if (chatroom.getHistorySize() > 0) {
+ rooms.add(chatroom);
+ }
+ }
+
+ if (rooms.size() > 1) {
+ Collections.sort(rooms, new Comparator() {
+ @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 permissionsList = new ArrayList();
+
+ 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));
}
}
}
diff --git a/src/org/linphone/LinphoneContact.java b/src/org/linphone/LinphoneContact.java
index ba76ea319..43453a62b 100644
--- a/src/org/linphone/LinphoneContact.java
+++ b/src/org/linphone/LinphoneContact.java
@@ -48,10 +48,11 @@ public class LinphoneContact implements Serializable, Comparable addresses;
private transient ArrayList changesToCommit;
+ private transient ArrayList changesToCommit2;
private boolean hasSipAddress;
public LinphoneContact() {
@@ -60,6 +61,7 @@ public class LinphoneContact implements Serializable, Comparable();
+ changesToCommit2 = new ArrayList();
hasSipAddress = false;
}
@@ -138,12 +140,12 @@ public class LinphoneContact implements Serializable, Comparable 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();
+ changesToCommit2 = new ArrayList();
}
}
+
if (isLinphoneFriend()) {
boolean hasAddr = false;
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
@@ -387,17 +432,22 @@ public class LinphoneContact implements Serializable, Comparable getAddressesAndNumbersForAndroidContact(String id) {
+ private List getAddressesAndNumbersForAndroidContact() {
List result = new ArrayList();
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 batch = new ArrayList();
+
+ 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);
+ }
+ }
}
diff --git a/src/org/linphone/LinphoneLauncherActivity.java b/src/org/linphone/LinphoneLauncherActivity.java
index d3a56d61e..a7fa589ba 100644
--- a/src/org/linphone/LinphoneLauncherActivity.java
+++ b/src/org/linphone/LinphoneLauncherActivity.java
@@ -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()) {
diff --git a/src/org/linphone/LinphoneManager.java b/src/org/linphone/LinphoneManager.java
index d397904e8..cbeced18b 100644
--- a/src/org/linphone/LinphoneManager.java
+++ b/src/org/linphone/LinphoneManager.java
@@ -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)) {
diff --git a/src/org/linphone/LinphonePreferences.java b/src/org/linphone/LinphonePreferences.java
index 8c8395074..52f44440c 100644
--- a/src/org/linphone/LinphonePreferences.java
+++ b/src/org/linphone/LinphonePreferences.java
@@ -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;
+ }
}
diff --git a/src/org/linphone/LinphoneService.java b/src/org/linphone/LinphoneService.java
index 47dedb3bc..07c468ba0 100644
--- a/src/org/linphone/LinphoneService.java
+++ b/src/org/linphone/LinphoneService.java
@@ -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() {
diff --git a/src/org/linphone/LinphoneUtils.java b/src/org/linphone/LinphoneUtils.java
index 8d3668418..42661832b 100644
--- a/src/org/linphone/LinphoneUtils.java
+++ b/src/org/linphone/LinphoneUtils.java
@@ -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;
+ }
}
diff --git a/src/org/linphone/PhoneStateChangedReceiver.java b/src/org/linphone/PhoneStateChangedReceiver.java
index 26452669f..226f6ae33 100644
--- a/src/org/linphone/PhoneStateChangedReceiver.java
+++ b/src/org/linphone/PhoneStateChangedReceiver.java
@@ -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
}
-
}
diff --git a/src/org/linphone/SettingsFragment.java b/src/org/linphone/SettingsFragment.java
index 14aa5661a..652a9ed54 100644
--- a/src/org/linphone/SettingsFragment.java
+++ b/src/org/linphone/SettingsFragment.java
@@ -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 entries = new ArrayList();
+ List values = new ArrayList();
+ 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 entries, List 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) {
diff --git a/src/org/linphone/assistant/AssistantActivity.java b/src/org/linphone/assistant/AssistantActivity.java
index 505cc2fd6..a7636db01 100644
--- a/src/org/linphone/assistant/AssistantActivity.java
+++ b/src/org/linphone/assistant/AssistantActivity.java
@@ -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();
}
diff --git a/src/org/linphone/compatibility/ApiElevenPlus.java b/src/org/linphone/compatibility/ApiElevenPlus.java
index d967bc6d3..d8c0a1fe4 100644
--- a/src/org/linphone/compatibility/ApiElevenPlus.java
+++ b/src/org/linphone/compatibility/ApiElevenPlus.java
@@ -69,6 +69,7 @@ public class ApiElevenPlus {
| Notification.DEFAULT_SOUND
| Notification.DEFAULT_VIBRATE)
.setWhen(System.currentTimeMillis())
+ .setNumber(msgCount)
.setLargeIcon(contactIcon).getNotification();
return notif;
diff --git a/src/org/linphone/compatibility/ApiNinePlus.java b/src/org/linphone/compatibility/ApiNinePlus.java
index 70dd126cf..80c49202e 100644
--- a/src/org/linphone/compatibility/ApiNinePlus.java
+++ b/src/org/linphone/compatibility/ApiNinePlus.java
@@ -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 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 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 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 ops = new ArrayList();
-
- 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 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);
- }
- }
- }
}
diff --git a/src/org/linphone/compatibility/ApiSixteenPlus.java b/src/org/linphone/compatibility/ApiSixteenPlus.java
index ac9ccd86d..a97cb04e1 100644
--- a/src/org/linphone/compatibility/ApiSixteenPlus.java
+++ b/src/org/linphone/compatibility/ApiSixteenPlus.java
@@ -56,6 +56,7 @@ public class ApiSixteenPlus {
| Notification.DEFAULT_VIBRATE)
.setWhen(System.currentTimeMillis())
.setLargeIcon(contactIcon)
+ .setNumber(msgCount)
.build();
return notif;
diff --git a/src/org/linphone/compatibility/ApiTwentyOnePlus.java b/src/org/linphone/compatibility/ApiTwentyOnePlus.java
index e1a842b4c..8247caa5f 100644
--- a/src/org/linphone/compatibility/ApiTwentyOnePlus.java
+++ b/src/org/linphone/compatibility/ApiTwentyOnePlus.java
@@ -54,6 +54,7 @@ public class ApiTwentyOnePlus {
.setCategory(Notification.CATEGORY_MESSAGE)
.setVisibility(Notification.VISIBILITY_PRIVATE)
.setPriority(Notification.PRIORITY_HIGH)
+ .setNumber(msgCount)
.build();
return notif;
diff --git a/src/org/linphone/compatibility/Compatibility.java b/src/org/linphone/compatibility/Compatibility.java
index da9f9b934..9a6f1ec5a 100644
--- a/src/org/linphone/compatibility/Compatibility.java
+++ b/src/org/linphone/compatibility/Compatibility.java
@@ -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 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 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 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;
+ }
}
diff --git a/src/org/linphone/gcm/GCMService.java b/src/org/linphone/gcm/GCMService.java
index 59906ef77..7d6c24936 100644
--- a/src/org/linphone/gcm/GCMService.java
+++ b/src/org/linphone/gcm/GCMService.java
@@ -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);
}
diff --git a/src/org/linphone/ui/BubbleChat.java b/src/org/linphone/ui/BubbleChat.java
index 50b3d4ea6..712c31933 100644
--- a/src/org/linphone/ui/BubbleChat.java
+++ b/src/org/linphone/ui/BubbleChat.java
@@ -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);
diff --git a/src/org/linphone/ui/LinphoneOverlay.java b/src/org/linphone/ui/LinphoneOverlay.java
new file mode 100644
index 000000000..6cb15ac0d
--- /dev/null
+++ b/src/org/linphone/ui/LinphoneOverlay.java
@@ -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;
+ }
+}
diff --git a/tests/src/org/linphone/test/Chat.java b/tests/src/org/linphone/test/Chat.java
index f6754e166..0db97b052 100644
--- a/tests/src/org/linphone/test/Chat.java
+++ b/tests/src/org/linphone/test/Chat.java
@@ -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());