From f763bfb7267e42451135861f6e08931dd3a25f4b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 1 Jul 2016 14:49:51 +0200 Subject: [PATCH 01/35] Fix issues on rotation --- src/org/linphone/CallVideoFragment.java | 2 +- src/org/linphone/LinphoneActivity.java | 13 ------------- src/org/linphone/LinphoneContact.java | 2 -- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/org/linphone/CallVideoFragment.java b/src/org/linphone/CallVideoFragment.java index 1bc890fd6..5aa9e146b 100644 --- a/src/org/linphone/CallVideoFragment.java +++ b/src/org/linphone/CallVideoFragment.java @@ -61,7 +61,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); diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index da1e71f3e..9774559c8 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -140,17 +140,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) { @@ -198,8 +187,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(){ diff --git a/src/org/linphone/LinphoneContact.java b/src/org/linphone/LinphoneContact.java index ba76ea319..e67ebed88 100644 --- a/src/org/linphone/LinphoneContact.java +++ b/src/org/linphone/LinphoneContact.java @@ -153,8 +153,6 @@ public class LinphoneContact implements Serializable, Comparable Date: Fri, 1 Jul 2016 15:08:34 +0200 Subject: [PATCH 02/35] Improved contact's picture update from camera --- src/org/linphone/ContactEditorFragment.java | 29 ++++++++++++++++++--- src/org/linphone/LinphoneContact.java | 1 + 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/org/linphone/ContactEditorFragment.java b/src/org/linphone/ContactEditorFragment.java index e94aefdc0..f8c523770 100644 --- a/src/org/linphone/ContactEditorFragment.java +++ b/src/org/linphone/ContactEditorFragment.java @@ -34,12 +34,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; @@ -372,10 +374,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) { diff --git a/src/org/linphone/LinphoneContact.java b/src/org/linphone/LinphoneContact.java index e67ebed88..600d87ac8 100644 --- a/src/org/linphone/LinphoneContact.java +++ b/src/org/linphone/LinphoneContact.java @@ -144,6 +144,7 @@ public class LinphoneContact implements Serializable, Comparable Date: Mon, 4 Jul 2016 12:01:23 +0200 Subject: [PATCH 03/35] Fix click on texts and images in chat view crash --- src/org/linphone/ChatFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java index 687d9d581..94f110459 100644 --- a/src/org/linphone/ChatFragment.java +++ b/src/org/linphone/ChatFragment.java @@ -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); From d603eb25eca8d51abe27f14cff2926bf9e9961c2 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 4 Jul 2016 15:35:57 +0200 Subject: [PATCH 04/35] Fixed toast messages on outgoing call error --- src/org/linphone/CallActivity.java | 17 +++----- src/org/linphone/CallOutgoingActivity.java | 47 +++++++++++++++++----- src/org/linphone/LinphoneActivity.java | 12 ------ 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/src/org/linphone/CallActivity.java b/src/org/linphone/CallActivity.java index afdbd8b60..b2904a313 100644 --- a/src/org/linphone/CallActivity.java +++ b/src/org/linphone/CallActivity.java @@ -30,6 +30,7 @@ import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreListenerBase; import org.linphone.core.LinphonePlayer; +import org.linphone.core.Reason; import org.linphone.mediastream.Log; import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration; import org.linphone.ui.Numpad; @@ -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) { diff --git a/src/org/linphone/CallOutgoingActivity.java b/src/org/linphone/CallOutgoingActivity.java index 62a107206..b98bb7c5e 100644 --- a/src/org/linphone/CallOutgoingActivity.java +++ b/src/org/linphone/CallOutgoingActivity.java @@ -26,6 +26,7 @@ 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.app.Activity; @@ -33,10 +34,14 @@ import android.content.pm.ActivityInfo; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; +import android.view.Gravity; import android.view.KeyEvent; +import android.view.LayoutInflater; +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{ @@ -88,16 +93,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 +106,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; } } }; @@ -204,6 +217,20 @@ 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); } diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index 9774559c8..3db9c5eeb 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -242,16 +242,6 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta checkAndRequestAudioPermission(false); } } 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(); } @@ -880,8 +870,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)); From b7167be063df4f2f18ce864089a1fa3eebca7ae4 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Jul 2016 15:05:59 +0200 Subject: [PATCH 05/35] Updated cmake builder to fix compilation issue when disabling unit tests --- submodules/cmake-builder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/cmake-builder b/submodules/cmake-builder index a76e657cb..d5277aa08 160000 --- a/submodules/cmake-builder +++ b/submodules/cmake-builder @@ -1 +1 @@ -Subproject commit a76e657cb8848094d6c5fc27666d1f7439de0b89 +Subproject commit d5277aa084ea43630b489a42e942dfa62c3ef0f0 From b20bd7a0225a5dcc885c6274af91f858368bfb20 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 5 Jul 2016 17:21:43 +0200 Subject: [PATCH 06/35] Removed useless ChatStorage class --- src/org/linphone/ChatFragment.java | 22 +- src/org/linphone/ChatListFragment.java | 8 +- src/org/linphone/ChatStorage.java | 409 ------------------------- src/org/linphone/LinphoneActivity.java | 86 +++--- src/org/linphone/LinphoneManager.java | 10 - 5 files changed, 62 insertions(+), 473 deletions(-) delete mode 100644 src/org/linphone/ChatStorage.java diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java index 94f110459..d1e2ede31 100644 --- a/src/org/linphone/ChatFragment.java +++ b/src/org/linphone/ChatFragment.java @@ -742,10 +742,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 +815,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); } } 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/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index 3db9c5eeb..de98f146f 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -23,6 +23,8 @@ 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; @@ -61,7 +63,6 @@ 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; @@ -803,43 +804,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 + ""); @@ -1041,10 +1051,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(); @@ -1054,19 +1060,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() { diff --git a/src/org/linphone/LinphoneManager.java b/src/org/linphone/LinphoneManager.java index c3a27a732..7ee8ffd33 100644 --- a/src/org/linphone/LinphoneManager.java +++ b/src/org/linphone/LinphoneManager.java @@ -796,9 +796,6 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag @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(); @@ -873,13 +870,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)) { From 2ebf80a2230d066f44f35cc14ca6dc7ddc5d714e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 6 Jul 2016 10:29:41 +0200 Subject: [PATCH 07/35] Remove reference to ChatStorage in tester --- tests/src/org/linphone/test/Chat.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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()); From fc3f698d905b46817cc579066eaa03a8cdaed7fb Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 11 Jul 2016 10:00:58 +0200 Subject: [PATCH 08/35] Update linphone submodule. --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index ae708bdd8..eb27b8d93 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit ae708bdd8cabe0efa5afc102ee7a06e324594847 +Subproject commit eb27b8d930fb84899ebbacf7b26b89fe80c197a0 From 84e53b12e737c2c373cb99904581eff2a8816254 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 11 Jul 2016 10:26:07 +0200 Subject: [PATCH 09/35] Update bctoolbox and linphone submodules. --- submodules/bctoolbox | 2 +- submodules/linphone | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/bctoolbox b/submodules/bctoolbox index 381df0104..2a3e07731 160000 --- a/submodules/bctoolbox +++ b/submodules/bctoolbox @@ -1 +1 @@ -Subproject commit 381df01040121f427c5d1a533cee017be033487a +Subproject commit 2a3e07731e72110de8d8301c87763dbcf9028450 diff --git a/submodules/linphone b/submodules/linphone index eb27b8d93..fd25dd44c 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit eb27b8d930fb84899ebbacf7b26b89fe80c197a0 +Subproject commit fd25dd44ce3a2c2a16db0273c86446b3bf19d2d1 From 954cf1e447340f7cc2e063b5ba9240b8f9c61071 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 11 Jul 2016 10:26:25 +0200 Subject: [PATCH 10/35] Remove now useless javah ant rule. --- custom_rules.xml | 44 -------------------------------------------- 1 file changed, 44 deletions(-) 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From f804c2900864eaeb92695e620ca27e39649fe917 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Jul 2016 14:09:08 +0200 Subject: [PATCH 11/35] Added make quick target to makefile and setting to disable/enable service notification --- res/values/non_localizable_strings.xml | 1 + res/values/strings.xml | 1 + res/xml/preferences.xml | 4 ++ src/org/linphone/LinphonePreferences.java | 8 ++++ src/org/linphone/LinphoneService.java | 45 ++++++++++++++++++----- src/org/linphone/SettingsFragment.java | 15 ++++++++ 6 files changed, 65 insertions(+), 9 deletions(-) diff --git a/res/values/non_localizable_strings.xml b/res/values/non_localizable_strings.xml index f204815ee..2d39b0234 100644 --- a/res/values/non_localizable_strings.xml +++ b/res/values/non_localizable_strings.xml @@ -71,6 +71,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 diff --git a/res/values/strings.xml b/res/values/strings.xml index 943878304..d949fc668 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -291,6 +291,7 @@ Debug Background mode Enable Animations + Enable service notification Start at boot time Incoming call hangup (in seconds) Sharing server diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 8eab25ca6..36abf4528 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -202,6 +202,10 @@ android:title="@string/pref_background_mode" android:key="@string/pref_background_mode_key"/> + + diff --git a/src/org/linphone/LinphonePreferences.java b/src/org/linphone/LinphonePreferences.java index 8c8395074..73a5893ba 100644 --- a/src/org/linphone/LinphonePreferences.java +++ b/src/org/linphone/LinphonePreferences.java @@ -1334,4 +1334,12 @@ 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); + } } diff --git a/src/org/linphone/LinphoneService.java b/src/org/linphone/LinphoneService.java index 47dedb3bc..ae23baafc 100644 --- a/src/org/linphone/LinphoneService.java +++ b/src/org/linphone/LinphoneService.java @@ -32,6 +32,7 @@ import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListenerBase; import org.linphone.core.LinphoneProxyConfig; +import org.linphone.core.LpConfig; import org.linphone.mediastream.Log; import org.linphone.mediastream.Version; @@ -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; @@ -126,6 +126,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 @@ -195,7 +220,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 +232,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 +266,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 @@ -505,7 +532,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. @@ -593,10 +620,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/SettingsFragment.java b/src/org/linphone/SettingsFragment.java index 3aa3195ef..6f6386a59 100644 --- a/src/org/linphone/SettingsFragment.java +++ b/src/org/linphone/SettingsFragment.java @@ -899,6 +899,7 @@ 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()); @@ -934,6 +935,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) { From c3061eed7c6635d38df77fc1df54f5b882e09dfb Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Jul 2016 14:13:55 +0200 Subject: [PATCH 12/35] Forgot to add make quick target --- .gitmodules | 3 --- prepare.py | 6 +++++- submodules/externals/vo-amrwbenc | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) delete mode 160000 submodules/externals/vo-amrwbenc diff --git a/.gitmodules b/.gitmodules index fa0235b31..a5ff94598 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 diff --git a/prepare.py b/prepare.py index 1e2316165..357874d3c 100755 --- a/prepare.py +++ b/prepare.py @@ -287,6 +287,11 @@ 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 + install-apk: \tant installd @@ -328,7 +333,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/submodules/externals/vo-amrwbenc b/submodules/externals/vo-amrwbenc deleted file mode 160000 index 60b925e62..000000000 --- a/submodules/externals/vo-amrwbenc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 60b925e621fd8d2bd3000207ceb5596a0fa20fb3 From e0140592ba7c280e4fee6a97f6139f7f53ebfc53 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Jul 2016 15:35:31 +0200 Subject: [PATCH 13/35] Fix compilation since last linphone submodule update --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index fd25dd44c..489c03a89 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit fd25dd44ce3a2c2a16db0273c86446b3bf19d2d1 +Subproject commit 489c03a89c4c28041c3cda8596f5c4fb8af8eed0 From 4473782f86ed11c08426e8cc94e008f3f48fb428 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Jul 2016 16:01:27 +0200 Subject: [PATCH 14/35] Removed log to fix crash because library not loaded --- src/org/linphone/PhoneStateChangedReceiver.java | 10 ---------- 1 file changed, 10 deletions(-) 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 } - } From 7074db040a43494a9cd3ed4e0a91404f1397d08f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Jul 2016 16:47:44 +0200 Subject: [PATCH 15/35] Fix for push information not being set if network down at configuration time --- src/org/linphone/LinphoneManager.java | 6 ++++++ src/org/linphone/LinphonePreferences.java | 4 ++-- src/org/linphone/compatibility/ApiElevenPlus.java | 1 + src/org/linphone/compatibility/ApiSixteenPlus.java | 1 + src/org/linphone/compatibility/ApiTwentyOnePlus.java | 1 + 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/org/linphone/LinphoneManager.java b/src/org/linphone/LinphoneManager.java index 7ee8ffd33..6efc2a469 100644 --- a/src/org/linphone/LinphoneManager.java +++ b/src/org/linphone/LinphoneManager.java @@ -792,6 +792,12 @@ 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) diff --git a/src/org/linphone/LinphonePreferences.java b/src/org/linphone/LinphonePreferences.java index 73a5893ba..babfb4613 100644 --- a/src/org/linphone/LinphonePreferences.java +++ b/src/org/linphone/LinphonePreferences.java @@ -1017,7 +1017,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 +1027,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(); } 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/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; From ce3ec6295a5e80ea2c31b8022f5eeb82a010e2ea Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Jul 2016 17:07:13 +0200 Subject: [PATCH 16/35] Added video preview window draggable feature made by Christophe Deschamps --- src/org/linphone/CallVideoFragment.java | 27 ++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/org/linphone/CallVideoFragment.java b/src/org/linphone/CallVideoFragment.java index 5aa9e146b..7b4202fd0 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 @@ -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; } From db5b1b95ad5940a772444f50b80e525892bfcf2d Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 11 Jul 2016 17:57:35 +0200 Subject: [PATCH 17/35] Ask for camera permission on incoming/outgoing call if video is enabled --- src/org/linphone/CallIncomingActivity.java | 61 +++++++++++++++++++-- src/org/linphone/CallOutgoingActivity.java | 63 ++++++++++++++++++++-- 2 files changed, 117 insertions(+), 7 deletions(-) diff --git a/src/org/linphone/CallIncomingActivity.java b/src/org/linphone/CallIncomingActivity.java index 2e55230c4..1e35f9bbc 100644 --- a/src/org/linphone/CallIncomingActivity.java +++ b/src/org/linphone/CallIncomingActivity.java @@ -29,12 +29,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,8 +48,8 @@ import android.widget.TextView; import android.widget.Toast; public class CallIncomingActivity extends Activity implements LinphoneSliderTriggered { - private static CallIncomingActivity instance; + private static final int PERMISSIONS_REQUEST_CAMERA = 205; private TextView name, number; private ImageView contactPicture, accept, decline; @@ -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,6 +202,9 @@ public class CallIncomingActivity extends Activity implements LinphoneSliderTrig } }; + if (LinphonePreferences.instance().isVideoEnabled() && LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) { + checkAndRequestCameraPermission(); + } super.onCreate(savedInstanceState); instance = this; @@ -320,4 +323,54 @@ public class CallIncomingActivity extends Activity implements LinphoneSliderTrig public void onRightHandleTriggered() { } + + private void checkAndRequestCameraPermission() { + if (LinphonePreferences.instance().cameraPermAsked()) { + return; + } + checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_REQUEST_CAMERA); + } + + private void checkAndRequestPermission(String permission, int result) { + if (getPackageManager().checkPermission(permission, getPackageName()) != PackageManager.PERMISSION_GRANTED) { + 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(); + } + } + } + } + } } \ No newline at end of file diff --git a/src/org/linphone/CallOutgoingActivity.java b/src/org/linphone/CallOutgoingActivity.java index b98bb7c5e..4adac7d80 100644 --- a/src/org/linphone/CallOutgoingActivity.java +++ b/src/org/linphone/CallOutgoingActivity.java @@ -29,14 +29,17 @@ 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.view.View; -import android.view.View.OnClickListener; +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.ViewGroup; import android.view.WindowManager; import android.widget.ImageView; @@ -44,8 +47,8 @@ import android.widget.TextView; import android.widget.Toast; public class CallOutgoingActivity extends Activity implements OnClickListener{ - private static CallOutgoingActivity instance; + private static final int PERMISSIONS_REQUEST_CAMERA = 205; private TextView name, number; private ImageView contactPicture, micro, speaker, hangUp; @@ -125,6 +128,10 @@ public class CallOutgoingActivity extends Activity implements OnClickListener{ } } }; + + if (LinphonePreferences.instance().isVideoEnabled() && LinphonePreferences.instance().shouldInitiateVideoCall()) { + checkAndRequestCameraPermission(); + } super.onCreate(savedInstanceState); instance = this; @@ -234,4 +241,54 @@ public class CallOutgoingActivity extends Activity implements OnClickListener{ private void decline() { LinphoneManager.getLc().terminateCall(mCall); } + + private void checkAndRequestCameraPermission() { + if (LinphonePreferences.instance().cameraPermAsked()) { + return; + } + checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_REQUEST_CAMERA); + } + + private void checkAndRequestPermission(String permission, int result) { + if (getPackageManager().checkPermission(permission, getPackageName()) != PackageManager.PERMISSION_GRANTED) { + 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(); + } + } + } + } + } } From cd3ab64f34de31fe3cd911d69c707fc5bdd22a52 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 12 Jul 2016 10:09:00 +0200 Subject: [PATCH 18/35] Updated bctoolbox to fix compil --- submodules/bctoolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/bctoolbox b/submodules/bctoolbox index 2a3e07731..cedccbe75 160000 --- a/submodules/bctoolbox +++ b/submodules/bctoolbox @@ -1 +1 @@ -Subproject commit 2a3e07731e72110de8d8301c87763dbcf9028450 +Subproject commit cedccbe75ca28f1a7f5ab953d652511b46804fa4 From dbdb72c46555dbfc14b3fe640b43161336f59e04 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 12 Jul 2016 12:26:58 +0200 Subject: [PATCH 19/35] Added video overlay when leaving Linphone while in video call --- AndroidManifest.xml | 2 + res/values/non_localizable_strings.xml | 1 + res/values/strings.xml | 2 + res/xml/preferences.xml | 15 ++- src/org/linphone/CallActivity.java | 3 +- src/org/linphone/CallVideoFragment.java | 6 ++ src/org/linphone/LinphoneActivity.java | 15 +++ src/org/linphone/LinphonePreferences.java | 10 +- src/org/linphone/LinphoneService.java | 36 ++++++- src/org/linphone/SettingsFragment.java | 18 ++++ src/org/linphone/ui/LinphoneOverlay.java | 115 ++++++++++++++++++++++ 11 files changed, 213 insertions(+), 10 deletions(-) create mode 100644 src/org/linphone/ui/LinphoneOverlay.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7d99c6672..799dbb8fd 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -43,6 +43,8 @@ + + diff --git a/res/values/non_localizable_strings.xml b/res/values/non_localizable_strings.xml index 2d39b0234..9b3be0fc7 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 diff --git a/res/values/strings.xml b/res/values/strings.xml index d949fc668..f0309c6fd 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -252,6 +252,8 @@ Video + Video overlay + Display call video in overlay when outside the application Use front camera Initiate video calls Always send video requests diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 36abf4528..3d8656fd1 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" /> + + - + diff --git a/src/org/linphone/CallActivity.java b/src/org/linphone/CallActivity.java index b2904a313..4b843b6df 100644 --- a/src/org/linphone/CallActivity.java +++ b/src/org/linphone/CallActivity.java @@ -30,7 +30,6 @@ import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreListenerBase; import org.linphone.core.LinphonePlayer; -import org.linphone.core.Reason; import org.linphone.mediastream.Log; import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration; import org.linphone.ui.Numpad; @@ -38,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; @@ -56,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; diff --git a/src/org/linphone/CallVideoFragment.java b/src/org/linphone/CallVideoFragment.java index 7b4202fd0..31d65389e 100644 --- a/src/org/linphone/CallVideoFragment.java +++ b/src/org/linphone/CallVideoFragment.java @@ -159,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); @@ -180,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/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index de98f146f..560b76577 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -67,6 +67,7 @@ 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; @@ -106,6 +107,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta 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 LinphoneActivity instance; @@ -1108,6 +1110,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } else { resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); } + } else if (requestCode == PERMISSIONS_REQUEST_OVERLAY) { + if (Settings.canDrawOverlays(this)) { + LinphonePreferences.instance().enableOverlay(true); + } } else { super.onActivityResult(requestCode, resultCode, data); } @@ -1148,6 +1154,15 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } return true; } + + public boolean checkAndRequestOverlayPermission() { + if (!Settings.canDrawOverlays(this)) { + Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); + startActivityForResult(intent, PERMISSIONS_REQUEST_OVERLAY); + return false; + } + return true; + } public void checkAndRequestExternalStoragePermission() { if (LinphonePreferences.instance().writeExternalStoragePermAsked()) { diff --git a/src/org/linphone/LinphonePreferences.java b/src/org/linphone/LinphonePreferences.java index babfb4613..5f9a6eb5f 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; @@ -1342,4 +1342,12 @@ public class LinphonePreferences { 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); + } } diff --git a/src/org/linphone/LinphoneService.java b/src/org/linphone/LinphoneService.java index ae23baafc..2edc6636b 100644 --- a/src/org/linphone/LinphoneService.java +++ b/src/org/linphone/LinphoneService.java @@ -32,9 +32,9 @@ import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListenerBase; import org.linphone.core.LinphoneProxyConfig; -import org.linphone.core.LpConfig; import org.linphone.mediastream.Log; import org.linphone.mediastream.Version; +import org.linphone.ui.LinphoneOverlay; import android.annotation.TargetApi; import android.app.Activity; @@ -49,6 +49,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.PixelFormat; import android.net.Uri; import android.os.Build; import android.os.Handler; @@ -56,6 +57,8 @@ import android.os.IBinder; import android.os.SystemClock; import android.provider.ContactsContract; import android.provider.MediaStore; +import android.view.Gravity; +import android.view.WindowManager; /** * @@ -118,6 +121,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; @@ -207,6 +212,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 @@ -286,8 +295,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.removeView(mOverlay); + mOverlay.destroy(); + } + mOverlay = null; + } private enum IncallIconState {INCALL, PAUSE, VIDEO, IDLE} private IncallIconState mCurrentIncallIconState = IncallIconState.IDLE; @@ -586,6 +617,7 @@ public final class LinphoneService extends Service { @Override public synchronized void onDestroy() { + destroyOverlay(); LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); if (lc != null) { lc.removeListener(mListener); diff --git a/src/org/linphone/SettingsFragment.java b/src/org/linphone/SettingsFragment.java index 6f6386a59..c45d0c256 100644 --- a/src/org/linphone/SettingsFragment.java +++ b/src/org/linphone/SettingsFragment.java @@ -39,6 +39,7 @@ import org.linphone.ui.LedPreference; import org.linphone.ui.PreferencesListFragment; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.preference.CheckBoxPreference; @@ -49,6 +50,7 @@ import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceCategory; import android.preference.PreferenceScreen; +import android.provider.Settings; /** * @author Sylvain Berfini @@ -609,6 +611,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() { @@ -702,6 +705,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() { diff --git a/src/org/linphone/ui/LinphoneOverlay.java b/src/org/linphone/ui/LinphoneOverlay.java new file mode 100644 index 000000000..80805a95f --- /dev/null +++ b/src/org/linphone/ui/LinphoneOverlay.java @@ -0,0 +1,115 @@ +package org.linphone.ui; + +import org.linphone.LinphoneManager; +import org.linphone.core.LinphoneCall; +import org.linphone.core.LinphoneCallParams; +import org.linphone.mediastream.video.AndroidVideoWindowImpl; + +import android.content.Context; +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) { + LinphoneManager.getLc().setPreviewWindow(null); + } + + 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) { + + } + }); + } + + 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; + } +} From d53ee51346be34d06eb1f76b6de23f0f20120de7 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 12 Jul 2016 14:27:22 +0200 Subject: [PATCH 20/35] Fix overlay crash on rotation + go back to call activity when clicking on overlay --- src/org/linphone/KeepAliveHandler.java | 11 ++++++----- src/org/linphone/KeepAliveReceiver.java | 4 ---- src/org/linphone/LinphoneService.java | 4 +--- src/org/linphone/ui/LinphoneOverlay.java | 8 ++++++-- 4 files changed, 13 insertions(+), 14 deletions(-) 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/LinphoneService.java b/src/org/linphone/LinphoneService.java index 2edc6636b..07c468ba0 100644 --- a/src/org/linphone/LinphoneService.java +++ b/src/org/linphone/LinphoneService.java @@ -49,7 +49,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.graphics.PixelFormat; import android.net.Uri; import android.os.Build; import android.os.Handler; @@ -57,7 +56,6 @@ import android.os.IBinder; import android.os.SystemClock; import android.provider.ContactsContract; import android.provider.MediaStore; -import android.view.Gravity; import android.view.WindowManager; /** @@ -314,7 +312,7 @@ public final class LinphoneService extends Service { public void destroyOverlay() { if (mOverlay != null) { - mWindowManager.removeView(mOverlay); + mWindowManager.removeViewImmediate(mOverlay); mOverlay.destroy(); } mOverlay = null; diff --git a/src/org/linphone/ui/LinphoneOverlay.java b/src/org/linphone/ui/LinphoneOverlay.java index 80805a95f..6cb15ac0d 100644 --- a/src/org/linphone/ui/LinphoneOverlay.java +++ b/src/org/linphone/ui/LinphoneOverlay.java @@ -1,11 +1,14 @@ 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; @@ -48,7 +51,6 @@ public class LinphoneOverlay extends org.linphone.mediastream.video.display.GL2J } public void onVideoPreviewSurfaceReady(AndroidVideoWindowImpl vw, SurfaceView surface) { - LinphoneManager.getLc().setPreviewWindow(null); } public void onVideoPreviewSurfaceDestroyed(AndroidVideoWindowImpl vw) { @@ -64,7 +66,9 @@ public class LinphoneOverlay extends org.linphone.mediastream.video.display.GL2J 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); } }); } From 36fd60f6fd6b7c72489b9943367724b27b29d95c Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 12 Jul 2016 14:33:31 +0200 Subject: [PATCH 21/35] Added ant run to quick target in Makefile --- prepare.py | 1 + 1 file changed, 1 insertion(+) diff --git a/prepare.py b/prepare.py index 357874d3c..468acddef 100755 --- a/prepare.py +++ b/prepare.py @@ -291,6 +291,7 @@ quick: \tant clean \tant debug \tant installd +\tant run install-apk: \tant installd From 6220879ea4b65588e1bdcc36bb99222c7dbb16ec Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 12 Jul 2016 14:44:36 +0200 Subject: [PATCH 22/35] Fix overlay related crash on Android < 6 --- src/org/linphone/LinphoneActivity.java | 5 +++-- src/org/linphone/compatibility/Compatibility.java | 8 ++++++++ submodules/cmake-builder | 2 +- submodules/linphone | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index 560b76577..0fd75b9c2 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -30,6 +30,7 @@ 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; @@ -1111,7 +1112,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); } } else if (requestCode == PERMISSIONS_REQUEST_OVERLAY) { - if (Settings.canDrawOverlays(this)) { + if (Compatibility.canDrawOverlays(this)) { LinphonePreferences.instance().enableOverlay(true); } } else { @@ -1156,7 +1157,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } public boolean checkAndRequestOverlayPermission() { - if (!Settings.canDrawOverlays(this)) { + if (!Compatibility.canDrawOverlays(this)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, PERMISSIONS_REQUEST_OVERLAY); return false; diff --git a/src/org/linphone/compatibility/Compatibility.java b/src/org/linphone/compatibility/Compatibility.java index da9f9b934..5857ba776 100644 --- a/src/org/linphone/compatibility/Compatibility.java +++ b/src/org/linphone/compatibility/Compatibility.java @@ -38,6 +38,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; /** @@ -363,4 +364,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/submodules/cmake-builder b/submodules/cmake-builder index d5277aa08..2a0a6c2af 160000 --- a/submodules/cmake-builder +++ b/submodules/cmake-builder @@ -1 +1 @@ -Subproject commit d5277aa084ea43630b489a42e942dfa62c3ef0f0 +Subproject commit 2a0a6c2af3342151cdba959e86ff14ff17b7ef9a diff --git a/submodules/linphone b/submodules/linphone index 489c03a89..e45b4fe4e 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 489c03a89c4c28041c3cda8596f5c4fb8af8eed0 +Subproject commit e45b4fe4eb58eed27ece1ca9c33c08be35a7d993 From 7c4834562529173b4c6a4311fe620b0ae8632aac Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 13 Jul 2016 10:51:20 +0200 Subject: [PATCH 23/35] Improved permissions management + ask for external storage read permission --- AndroidManifest.xml | 1 + src/org/linphone/CallActivity.java | 19 ++-- src/org/linphone/CallIncomingActivity.java | 65 +++--------- src/org/linphone/CallOutgoingActivity.java | 63 +++--------- src/org/linphone/ChatFragment.java | 2 +- src/org/linphone/LinphoneActivity.java | 109 +++++++++------------ src/org/linphone/LinphonePreferences.java | 40 -------- 7 files changed, 84 insertions(+), 215 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 799dbb8fd..67a847cb3 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -27,6 +27,7 @@ + diff --git a/src/org/linphone/CallActivity.java b/src/org/linphone/CallActivity.java index 4b843b6df..cd4c2c498 100644 --- a/src/org/linphone/CallActivity.java +++ b/src/org/linphone/CallActivity.java @@ -454,13 +454,13 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve } @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + public void onRequestPermissionsResult(int requestCode, String[] permissions, final int[] grantResults) { switch (requestCode) { case PERMISSIONS_REQUEST_CAMERA: UIThreadDispatcher.dispatch(new Runnable() { @Override public void run() { - acceptCallUpdate(true); + acceptCallUpdate(grantResults[0] == PackageManager.PERMISSION_GRANTED); } }); break; @@ -468,12 +468,11 @@ 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; } - LinphonePreferences.instance().neverAskCameraPerm(); } public void createInCallStats() { @@ -606,7 +605,7 @@ 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())); + disableVideo(isVideoEnabled(LinphoneManager.getLc().getCurrentCall())); } else { checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_ENABLED_CAMERA); } @@ -719,13 +718,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); @@ -1379,7 +1378,7 @@ 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()) { + if (getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) == PackageManager.PERMISSION_GRANTED || !ActivityCompat.shouldShowRequestPermissionRationale(CallActivity.this, Manifest.permission.CAMERA)) { CallActivity.instance().acceptCallUpdate(true); } else { checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_REQUEST_CAMERA); @@ -1389,9 +1388,7 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve } }); - 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 1e35f9bbc..1aa118f2f 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; @@ -49,7 +50,6 @@ import android.widget.Toast; public class CallIncomingActivity extends Activity implements LinphoneSliderTriggered { private static CallIncomingActivity instance; - private static final int PERMISSIONS_REQUEST_CAMERA = 205; private TextView name, number; private ImageView contactPicture, accept, decline; @@ -201,10 +201,8 @@ public class CallIncomingActivity extends Activity implements LinphoneSliderTrig } } }; - - if (LinphonePreferences.instance().isVideoEnabled() && LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) { - checkAndRequestCameraPermission(); - } + + checkAndRequestCallPermissions(); super.onCreate(savedInstanceState); instance = this; @@ -324,53 +322,20 @@ public class CallIncomingActivity extends Activity implements LinphoneSliderTrig } - private void checkAndRequestCameraPermission() { - if (LinphonePreferences.instance().cameraPermAsked()) { - return; + private void checkAndRequestCallPermissions() { + ArrayList permissionsList = new ArrayList(); + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO) && getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) != PackageManager.PERMISSION_GRANTED) { + permissionsList.add(Manifest.permission.RECORD_AUDIO); } - checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_REQUEST_CAMERA); - } - - private void checkAndRequestPermission(String permission, int result) { - if (getPackageManager().checkPermission(permission, getPackageName()) != PackageManager.PERMISSION_GRANTED) { - 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(); - } - } + if (LinphonePreferences.instance().shouldInitiateVideoCall() || LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) && getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) != PackageManager.PERMISSION_GRANTED) { + permissionsList.add(Manifest.permission.CAMERA); } } + if (permissionsList.size() > 0) { + String[] permissions = new String[permissionsList.size()]; + permissions = permissionsList.toArray(permissions); + ActivityCompat.requestPermissions(this, permissions, 0); + } } } \ No newline at end of file diff --git a/src/org/linphone/CallOutgoingActivity.java b/src/org/linphone/CallOutgoingActivity.java index 4adac7d80..ce24b64de 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; @@ -48,7 +49,6 @@ import android.widget.Toast; public class CallOutgoingActivity extends Activity implements OnClickListener{ private static CallOutgoingActivity instance; - private static final int PERMISSIONS_REQUEST_CAMERA = 205; private TextView name, number; private ImageView contactPicture, micro, speaker, hangUp; @@ -129,9 +129,7 @@ public class CallOutgoingActivity extends Activity implements OnClickListener{ } }; - if (LinphonePreferences.instance().isVideoEnabled() && LinphonePreferences.instance().shouldInitiateVideoCall()) { - checkAndRequestCameraPermission(); - } + checkAndRequestCallPermissions(); super.onCreate(savedInstanceState); instance = this; @@ -242,53 +240,20 @@ public class CallOutgoingActivity extends Activity implements OnClickListener{ LinphoneManager.getLc().terminateCall(mCall); } - private void checkAndRequestCameraPermission() { - if (LinphonePreferences.instance().cameraPermAsked()) { - return; + private void checkAndRequestCallPermissions() { + ArrayList permissionsList = new ArrayList(); + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO) && getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) != PackageManager.PERMISSION_GRANTED) { + permissionsList.add(Manifest.permission.RECORD_AUDIO); } - checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_REQUEST_CAMERA); - } - - private void checkAndRequestPermission(String permission, int result) { - if (getPackageManager().checkPermission(permission, getPackageName()) != PackageManager.PERMISSION_GRANTED) { - 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(); - } - } + if (LinphonePreferences.instance().shouldInitiateVideoCall() || LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) && getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) != PackageManager.PERMISSION_GRANTED) { + permissionsList.add(Manifest.permission.CAMERA); } } + if (permissionsList.size() > 0) { + String[] permissions = new String[permissionsList.size()]; + permissions = permissionsList.toArray(permissions); + ActivityCompat.requestPermissions(this, permissions, 0); + } } } diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java index d1e2ede31..de94d40de 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); diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index 0fd75b9c2..990ccd3ff 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -106,9 +106,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta 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_EXTERNAL_FILE_STORAGE_WRITE = 204; private static final int PERMISSIONS_REQUEST_CAMERA = 205; private static final int PERMISSIONS_REQUEST_OVERLAY = 206; + private static final int PERMISSIONS_REQUEST_EXTERNAL_FILE_STORAGE_READ = 207; private static LinphoneActivity instance; @@ -234,16 +235,16 @@ 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()) { + if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED || !ActivityCompat.shouldShowRequestPermissionRationale(LinphoneActivity.this, Manifest.permission.RECORD_AUDIO)) { startActivity(new Intent(LinphoneActivity.instance(), CallIncomingActivity.class)); } else { - checkAndRequestAudioPermission(true); + checkAndRequestCallPermissions(true); } } else if (state == State.OutgoingInit || state == State.OutgoingProgress) { - if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED || LinphonePreferences.instance().audioPermAsked()) { + if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED || !ActivityCompat.shouldShowRequestPermissionRationale(LinphoneActivity.this, Manifest.permission.RECORD_AUDIO)) { startActivity(new Intent(LinphoneActivity.instance(), CallOutgoingActivity.class)); } else { - checkAndRequestAudioPermission(false); + checkAndRequestCallPermissions(false); } } else if (state == State.CallEnd || state == State.Error || state == State.CallReleased) { resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); @@ -1164,43 +1165,56 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } return true; } + + public void checkAndRequestReadExternalStoragePermission() { + checkAndRequestPermission(Manifest.permission.READ_EXTERNAL_STORAGE, PERMISSIONS_REQUEST_EXTERNAL_FILE_STORAGE_READ); + } 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, PERMISSIONS_REQUEST_EXTERNAL_FILE_STORAGE_WRITE); } public void checkAndRequestCameraPermission() { - if (LinphonePreferences.instance().cameraPermAsked()) { - return; - } checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_REQUEST_CAMERA); } 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); } - public void checkAndRequestAudioPermission(boolean isIncomingCall) { - if (LinphonePreferences.instance().audioPermAsked()) { - return; + public void checkAndRequestCallPermissions(boolean isIncomingCall) { + ArrayList permissionsList = new ArrayList(); + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO) && getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) != PackageManager.PERMISSION_GRANTED) { + permissionsList.add(Manifest.permission.RECORD_AUDIO); } - 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 (LinphonePreferences.instance().shouldInitiateVideoCall() || LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) && getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) != PackageManager.PERMISSION_GRANTED) { + permissionsList.add(Manifest.permission.CAMERA); + } + } + if (permissionsList.size() > 0) { + String[] permissions = new String[permissionsList.size()]; + permissions = permissionsList.toArray(permissions); + ActivityCompat.requestPermissions(this, permissions, isIncomingCall ? PERMISSIONS_REQUEST_RECORD_AUDIO_INCOMING_CALL : PERMISSIONS_REQUEST_RECORD_AUDIO); + } + } + + public void checkAndRequestPermissionsToSendImage() { + ArrayList permissionsList = new ArrayList(); + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE) && getPackageManager().checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE, getPackageName()) != PackageManager.PERMISSION_GRANTED) { + permissionsList.add(Manifest.permission.READ_EXTERNAL_STORAGE); + } + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) && getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) != PackageManager.PERMISSION_GRANTED) { + permissionsList.add(Manifest.permission.CAMERA); + } + if (permissionsList.size() > 0) { + String[] permissions = new String[permissionsList.size()]; + permissions = permissionsList.toArray(permissions); + ActivityCompat.requestPermissions(this, permissions, 0); } } @@ -1212,39 +1226,6 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta @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(); - } - } - } - } switch (requestCode) { case PERMISSIONS_REQUEST_RECORD_AUDIO: startActivity(new Intent(this, CallOutgoingActivity.class)); @@ -1292,16 +1273,16 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta 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()) { + if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED || !ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) { startActivity(new Intent(this, CallIncomingActivity.class)); } else { - checkAndRequestAudioPermission(true); + checkAndRequestCallPermissions(true); } } 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()) { + if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED || !ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) { startActivity(new Intent(this, CallOutgoingActivity.class)); } else { - checkAndRequestAudioPermission(false); + checkAndRequestCallPermissions(false); } } else { if (call.getCurrentParamsCopy().getVideoEnabled()) { @@ -1381,10 +1362,10 @@ 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()) { + if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) == PackageManager.PERMISSION_GRANTED || !ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) { startActivity(new Intent(this, CallIncomingActivity.class)); } else { - checkAndRequestAudioPermission(true); + checkAndRequestCallPermissions(true); } } } diff --git a/src/org/linphone/LinphonePreferences.java b/src/org/linphone/LinphonePreferences.java index 5f9a6eb5f..a4db6c5f7 100644 --- a/src/org/linphone/LinphonePreferences.java +++ b/src/org/linphone/LinphonePreferences.java @@ -1287,46 +1287,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"); } From 5a40d15e1b638de65880b869235583c554a20702 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 13 Jul 2016 10:55:59 +0200 Subject: [PATCH 24/35] Fix crash when receiving push notification without service --- src/org/linphone/gcm/GCMService.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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); } From 182888f824a45b47fca5ab2f410c800cb795de9a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 13 Jul 2016 15:42:13 +0200 Subject: [PATCH 25/35] Added back the sync mechanism for contacts --- AndroidManifest.xml | 2 +- res/values/non_localizable_custom.xml | 2 +- src/org/linphone/ContactsManager.java | 3 +- src/org/linphone/LinphoneActivity.java | 35 ++-- src/org/linphone/LinphoneContact.java | 180 ++++++++++++++---- .../linphone/compatibility/ApiNinePlus.java | 88 --------- .../linphone/compatibility/Compatibility.java | 27 --- 7 files changed, 173 insertions(+), 164 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 67a847cb3..568325779 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -78,7 +78,7 @@ - + diff --git a/res/values/non_localizable_custom.xml b/res/values/non_localizable_custom.xml index 4266988c7..d938030fe 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 diff --git a/src/org/linphone/ContactsManager.java b/src/org/linphone/ContactsManager.java index 78b7ef8b5..a0ebae3d3 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()); @@ -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/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index 990ccd3ff..834bb7186 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -103,13 +103,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta 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_WRITE = 204; - private static final int PERMISSIONS_REQUEST_CAMERA = 205; private static final int PERMISSIONS_REQUEST_OVERLAY = 206; - private static final int PERMISSIONS_REQUEST_EXTERNAL_FILE_STORAGE_READ = 207; + private static final int PERMISSIONS_REQUEST_SYNC = 207; private static LinphoneActivity instance; @@ -174,9 +171,12 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } } - //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()); } @@ -1167,23 +1167,23 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } public void checkAndRequestReadExternalStoragePermission() { - checkAndRequestPermission(Manifest.permission.READ_EXTERNAL_STORAGE, PERMISSIONS_REQUEST_EXTERNAL_FILE_STORAGE_READ); + checkAndRequestPermission(Manifest.permission.READ_EXTERNAL_STORAGE, 0); } public void checkAndRequestExternalStoragePermission() { - checkAndRequestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSIONS_REQUEST_EXTERNAL_FILE_STORAGE_WRITE); + checkAndRequestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, 0); } public void checkAndRequestCameraPermission() { - checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_REQUEST_CAMERA); + checkAndRequestPermission(Manifest.permission.CAMERA, 0); } public void checkAndRequestReadContactsPermission() { - checkAndRequestPermission(Manifest.permission.READ_CONTACTS, PERMISSIONS_REQUEST_CONTACTS); + checkAndRequestPermission(Manifest.permission.READ_CONTACTS, 0); } public void checkAndRequestWriteContactsPermission() { - checkAndRequestPermission(Manifest.permission.WRITE_CONTACTS, PERMISSIONS_REQUEST_CONTACTS); + checkAndRequestPermission(Manifest.permission.WRITE_CONTACTS, 0); } public void checkAndRequestCallPermissions(boolean isIncomingCall) { @@ -1217,6 +1217,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta 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) { @@ -1233,6 +1237,13 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta case PERMISSIONS_REQUEST_RECORD_AUDIO_INCOMING_CALL: startActivity(new Intent(this, CallIncomingActivity.class)); break; + case PERMISSIONS_REQUEST_SYNC: + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + ContactsManager.getInstance().initializeSyncAccount(getApplicationContext(), getContentResolver()); + } else { + ContactsManager.getInstance().initializeContactManager(getApplicationContext(), getContentResolver()); + } + break; } } diff --git a/src/org/linphone/LinphoneContact.java b/src/org/linphone/LinphoneContact.java index 600d87ac8..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,10 +140,9 @@ 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(); @@ -386,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)); @@ -551,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/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/Compatibility.java b/src/org/linphone/compatibility/Compatibility.java index 5857ba776..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; @@ -301,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); From 7ea7da9f0dfa68120042461369b4147c689daf59 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 15 Jul 2016 12:08:52 +0200 Subject: [PATCH 26/35] Restore vo-amrwbenc submodule. --- .gitmodules | 3 +++ submodules/externals/vo-amrwbenc | 1 + 2 files changed, 4 insertions(+) create mode 160000 submodules/externals/vo-amrwbenc diff --git a/.gitmodules b/.gitmodules index a5ff94598..6778bad1b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -101,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/submodules/externals/vo-amrwbenc b/submodules/externals/vo-amrwbenc new file mode 160000 index 000000000..60b925e62 --- /dev/null +++ b/submodules/externals/vo-amrwbenc @@ -0,0 +1 @@ +Subproject commit 60b925e621fd8d2bd3000207ceb5596a0fa20fb3 From d8e8700e603e00b7004331945c4f9cdb36880abc Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 15 Jul 2016 12:32:20 +0200 Subject: [PATCH 27/35] Added chat preferences folder with lime encryption setting --- res/values/non_localizable_strings.xml | 2 + res/values/strings.xml | 10 +- res/xml/preferences.xml | 18 +++- src/org/linphone/LinphoneActivity.java | 4 +- .../linphone/LinphoneLauncherActivity.java | 2 - src/org/linphone/LinphonePreferences.java | 9 ++ src/org/linphone/SettingsFragment.java | 100 ++++++++++++++---- submodules/belle-sip | 2 +- submodules/linphone | 2 +- 9 files changed, 117 insertions(+), 32 deletions(-) diff --git a/res/values/non_localizable_strings.xml b/res/values/non_localizable_strings.xml index 9b3be0fc7..f3c4727f7 100644 --- a/res/values/non_localizable_strings.xml +++ b/res/values/non_localizable_strings.xml @@ -199,4 +199,6 @@ Send logs Cancel + + pref_use_lime_encryption_key diff --git a/res/values/strings.xml b/res/values/strings.xml index f0309c6fd..4f55d9a5b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -271,6 +271,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 @@ -296,7 +305,6 @@ 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 3d8656fd1..be34cd865 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -141,6 +141,20 @@ android:key="@string/pref_voice_mail_key"/> + + + + + + + + @@ -224,10 +238,6 @@ android:key="@string/pref_incoming_call_timeout_key" android:layout="@layout/hidden"/> - - diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index 834bb7186..8e83ed2f2 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -1250,7 +1250,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta @Override protected void onResume() { super.onResume(); - + if (!LinphoneService.isReady()) { startService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class)); } @@ -1336,7 +1336,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(); 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/LinphonePreferences.java b/src/org/linphone/LinphonePreferences.java index a4db6c5f7..43fc4a767 100644 --- a/src/org/linphone/LinphonePreferences.java +++ b/src/org/linphone/LinphonePreferences.java @@ -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; @@ -1310,4 +1311,12 @@ public class LinphonePreferences { 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); + } } diff --git a/src/org/linphone/SettingsFragment.java b/src/org/linphone/SettingsFragment.java index c45d0c256..efe897f7a 100644 --- a/src/org/linphone/SettingsFragment.java +++ b/src/org/linphone/SettingsFragment.java @@ -19,13 +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.AdaptiveRateAlgorithm; 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,9 +38,8 @@ import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration; import org.linphone.purchase.InAppPurchaseActivity; import org.linphone.ui.LedPreference; import org.linphone.ui.PreferencesListFragment; -import android.content.Intent; -import android.net.Uri; +import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.preference.CheckBoxPreference; @@ -50,27 +50,24 @@ import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceCategory; import android.preference.PreferenceScreen; -import android.provider.Settings; /** * @author Sylvain Berfini */ 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 +97,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 +109,7 @@ public class SettingsFragment extends PreferencesListFragment { initAudioSettings(); initVideoSettings(); initCallSettings(); + initChatSettings(); initNetworkSettings(); initAdvancedSettings(); @@ -134,6 +137,7 @@ public class SettingsFragment extends PreferencesListFragment { setAudioPreferencesListener(); setVideoPreferencesListener(); setCallPreferencesListener(); + setChatPreferencesListener(); setNetworkPreferencesListener(); setAdvancedPreferencesListener(); } @@ -436,6 +440,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()]; @@ -776,6 +804,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))); @@ -919,7 +988,6 @@ public class SettingsFragment extends PreferencesListFragment { ((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()); @@ -976,16 +1044,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/submodules/belle-sip b/submodules/belle-sip index 374a1ae8b..245bdae5f 160000 --- a/submodules/belle-sip +++ b/submodules/belle-sip @@ -1 +1 @@ -Subproject commit 374a1ae8be6eea497df54e90041b11d81bb32cdf +Subproject commit 245bdae5fe12032e4d0c3041c9e0c6f0d78ed2a7 diff --git a/submodules/linphone b/submodules/linphone index e45b4fe4e..d3e8feeb6 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit e45b4fe4eb58eed27ece1ca9c33c08be35a7d993 +Subproject commit d3e8feeb605b087e33c628ebfd0c79e84d598120 From fae6f62cdd968342e8f24c0d3d48c8d7939c92ed Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 15 Jul 2016 14:02:04 +0200 Subject: [PATCH 28/35] Update msamr submodule. --- submodules/msamr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/msamr b/submodules/msamr index 9d22b95d9..80c83e1b1 160000 --- a/submodules/msamr +++ b/submodules/msamr @@ -1 +1 @@ -Subproject commit 9d22b95d9be7411e1c0146c1aa9095e414585f5b +Subproject commit 80c83e1b1eb1d20880246faecc95b8ee0ba2b41b From ccff156889f05055a38ce1fd70edb45e276b0bb5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 15 Jul 2016 15:47:27 +0200 Subject: [PATCH 29/35] Only display username but save SIP addresses with sip: prefix and the domain from default proxy config --- src/org/linphone/ContactDetailsFragment.java | 3 +++ src/org/linphone/ContactEditorFragment.java | 21 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) 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 f8c523770..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; @@ -124,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) { @@ -142,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(); @@ -472,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) From 7f4fdba68926fe197ac7dd6fcbbc860baa84afeb Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 15 Jul 2016 17:11:06 +0200 Subject: [PATCH 30/35] Fix crash when downloading received picture encrypted with lime via chat message --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index d3e8feeb6..554635c53 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit d3e8feeb605b087e33c628ebfd0c79e84d598120 +Subproject commit 554635c53bc22ca449b8f74f50836afffe9cbdb9 From 4b00bfcb553837417da3bebf57acbf8ccc5d173f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 18 Jul 2016 11:54:43 +0200 Subject: [PATCH 31/35] Fixed issues with permissions + added logs --- src/org/linphone/CallActivity.java | 62 +++++++++++-- src/org/linphone/CallIncomingActivity.java | 42 +++++++-- src/org/linphone/CallOutgoingActivity.java | 40 ++++++-- src/org/linphone/LinphoneActivity.java | 92 ++++++++----------- src/org/linphone/LinphonePreferences.java | 8 ++ .../linphone/assistant/AssistantActivity.java | 15 ++- 6 files changed, 175 insertions(+), 84 deletions(-) diff --git a/src/org/linphone/CallActivity.java b/src/org/linphone/CallActivity.java index cd4c2c498..321d0a80a 100644 --- a/src/org/linphone/CallActivity.java +++ b/src/org/linphone/CallActivity.java @@ -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; @@ -446,15 +447,23 @@ 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, 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() { @@ -472,6 +481,16 @@ public class CallActivity extends Activity implements OnClickListener, SensorEve } }); break; + case PERMISSIONS_ENABLED_MIC: + UIThreadDispatcher.dispatch(new Runnable() { + @Override + public void run() { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + toggleMicro(); + } + } + }); + break; } } @@ -518,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); @@ -525,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 { @@ -604,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) { + 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(); @@ -1378,10 +1417,17 @@ 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 || !ActivityCompat.shouldShowRequestPermissionRationale(CallActivity.this, Manifest.permission.CAMERA)) { + 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(); diff --git a/src/org/linphone/CallIncomingActivity.java b/src/org/linphone/CallIncomingActivity.java index 1aa118f2f..e33b052ad 100644 --- a/src/org/linphone/CallIncomingActivity.java +++ b/src/org/linphone/CallIncomingActivity.java @@ -201,8 +201,6 @@ public class CallIncomingActivity extends Activity implements LinphoneSliderTrig } } }; - - checkAndRequestCallPermissions(); super.onCreate(savedInstanceState); instance = this; @@ -235,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) { @@ -245,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() { @@ -324,18 +330,38 @@ public class CallIncomingActivity extends Activity implements LinphoneSliderTrig private void checkAndRequestCallPermissions() { ArrayList permissionsList = new ArrayList(); - if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO) && getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) != PackageManager.PERMISSION_GRANTED) { - permissionsList.add(Manifest.permission.RECORD_AUDIO); - } - if (LinphonePreferences.instance().shouldInitiateVideoCall() || LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) { - if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) && getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) != PackageManager.PERMISSION_GRANTED) { - permissionsList.add(Manifest.permission.CAMERA); + + 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 ce24b64de..b3ad9b00c 100644 --- a/src/org/linphone/CallOutgoingActivity.java +++ b/src/org/linphone/CallOutgoingActivity.java @@ -128,8 +128,6 @@ public class CallOutgoingActivity extends Activity implements OnClickListener{ } } }; - - checkAndRequestCallPermissions(); super.onCreate(savedInstanceState); instance = this; @@ -170,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() { @@ -242,18 +246,38 @@ public class CallOutgoingActivity extends Activity implements OnClickListener{ private void checkAndRequestCallPermissions() { ArrayList permissionsList = new ArrayList(); - if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO) && getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) != PackageManager.PERMISSION_GRANTED) { - permissionsList.add(Manifest.permission.RECORD_AUDIO); - } - if (LinphonePreferences.instance().shouldInitiateVideoCall() || LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) { - if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) && getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) != PackageManager.PERMISSION_GRANTED) { - permissionsList.add(Manifest.permission.CAMERA); + + 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/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index 8e83ed2f2..f02ade576 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -103,8 +103,6 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta 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_RECORD_AUDIO = 201; - private static final int PERMISSIONS_REQUEST_RECORD_AUDIO_INCOMING_CALL = 203; private static final int PERMISSIONS_REQUEST_OVERLAY = 206; private static final int PERMISSIONS_REQUEST_SYNC = 207; @@ -235,17 +233,9 @@ 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 || !ActivityCompat.shouldShowRequestPermissionRationale(LinphoneActivity.this, Manifest.permission.RECORD_AUDIO)) { - startActivity(new Intent(LinphoneActivity.instance(), CallIncomingActivity.class)); - } else { - checkAndRequestCallPermissions(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 || !ActivityCompat.shouldShowRequestPermissionRationale(LinphoneActivity.this, Manifest.permission.RECORD_AUDIO)) { - startActivity(new Intent(LinphoneActivity.instance(), CallOutgoingActivity.class)); - } else { - checkAndRequestCallPermissions(false); - } + startActivity(new Intent(LinphoneActivity.instance(), CallOutgoingActivity.class)); } else if (state == State.CallEnd || state == State.Error || state == State.CallReleased) { resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); } @@ -1158,7 +1148,9 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } 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; @@ -1186,30 +1178,25 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta checkAndRequestPermission(Manifest.permission.WRITE_CONTACTS, 0); } - public void checkAndRequestCallPermissions(boolean isIncomingCall) { - ArrayList permissionsList = new ArrayList(); - if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO) && getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName()) != PackageManager.PERMISSION_GRANTED) { - permissionsList.add(Manifest.permission.RECORD_AUDIO); - } - if (LinphonePreferences.instance().shouldInitiateVideoCall() || LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) { - if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) && getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) != PackageManager.PERMISSION_GRANTED) { - permissionsList.add(Manifest.permission.CAMERA); - } - } - if (permissionsList.size() > 0) { - String[] permissions = new String[permissionsList.size()]; - permissions = permissionsList.toArray(permissions); - ActivityCompat.requestPermissions(this, permissions, isIncomingCall ? PERMISSIONS_REQUEST_RECORD_AUDIO_INCOMING_CALL : PERMISSIONS_REQUEST_RECORD_AUDIO); - } - } - public void checkAndRequestPermissionsToSendImage() { ArrayList permissionsList = new ArrayList(); - if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE) && getPackageManager().checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE, getPackageName()) != PackageManager.PERMISSION_GRANTED) { - permissionsList.add(Manifest.permission.READ_EXTERNAL_STORAGE); + + 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); + } } - if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) && getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName()) != PackageManager.PERMISSION_GRANTED) { - permissionsList.add(Manifest.permission.CAMERA); + 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()]; @@ -1223,20 +1210,24 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } 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) { + 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)); - break; - case PERMISSIONS_REQUEST_RECORD_AUDIO_INCOMING_CALL: - startActivity(new Intent(this, CallIncomingActivity.class)); - break; case PERMISSIONS_REQUEST_SYNC: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { ContactsManager.getInstance().initializeSyncAccount(getApplicationContext(), getContentResolver()); @@ -1283,18 +1274,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 || !ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) { - startActivity(new Intent(this, CallIncomingActivity.class)); - } else { - checkAndRequestCallPermissions(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 || !ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) { - startActivity(new Intent(this, CallOutgoingActivity.class)); - } else { - checkAndRequestCallPermissions(false); - } + startActivity(new Intent(this, CallOutgoingActivity.class)); } else { if (call.getCurrentParamsCopy().getVideoEnabled()) { startVideoActivity(call); @@ -1373,11 +1357,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 || !ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) { - startActivity(new Intent(this, CallIncomingActivity.class)); - } else { - checkAndRequestCallPermissions(true); - } + startActivity(new Intent(this, CallIncomingActivity.class)); } } } diff --git a/src/org/linphone/LinphonePreferences.java b/src/org/linphone/LinphonePreferences.java index 43fc4a767..52f44440c 100644 --- a/src/org/linphone/LinphonePreferences.java +++ b/src/org/linphone/LinphonePreferences.java @@ -1319,4 +1319,12 @@ public class LinphonePreferences { 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/assistant/AssistantActivity.java b/src/org/linphone/assistant/AssistantActivity.java index 9a0a99e59..a1b1216a5 100644 --- a/src/org/linphone/assistant/AssistantActivity.java +++ b/src/org/linphone/assistant/AssistantActivity.java @@ -27,7 +27,6 @@ import org.linphone.core.LinphoneAddress; import org.linphone.core.LinphoneAddress.TransportType; import org.linphone.core.LinphoneCore; import org.linphone.core.LinphoneCore.RegistrationState; -import org.linphone.core.LinphoneCore.RemoteProvisioningState; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListenerBase; @@ -229,8 +228,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); } } @@ -238,8 +241,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 { success(); From bb070b3665704e2a12f4d89c6f5ae43de9fb9582 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 18 Jul 2016 12:32:37 +0200 Subject: [PATCH 32/35] Fix permissions loops when asking for record audio, camera or contacts --- AndroidManifest.xml | 2 -- src/org/linphone/ContactsManager.java | 2 +- src/org/linphone/LinphoneActivity.java | 35 +++++++++++++++++++------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 568325779..909529b19 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -97,7 +97,6 @@ @@ -107,7 +106,6 @@ diff --git a/src/org/linphone/ContactsManager.java b/src/org/linphone/ContactsManager.java index a0ebae3d3..48d42e69d 100644 --- a/src/org/linphone/ContactsManager.java +++ b/src/org/linphone/ContactsManager.java @@ -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()) { diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index f02ade576..dcdabcbfa 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -105,6 +105,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta private static final int CALL_ACTIVITY = 19; 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; @@ -353,6 +354,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(); @@ -1171,7 +1173,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta } public void checkAndRequestReadContactsPermission() { - checkAndRequestPermission(Manifest.permission.READ_CONTACTS, 0); + checkAndRequestPermission(Manifest.permission.READ_CONTACTS, PERMISSIONS_REQUEST_CONTACTS); } public void checkAndRequestWriteContactsPermission() { @@ -1235,6 +1237,29 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta ContactsManager.getInstance().initializeContactManager(getApplicationContext(), getContentResolver()); } break; + 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(); } } @@ -1251,14 +1276,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(); From bffe9c95371354697d69316dd875a144686babaa Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 18 Jul 2016 14:20:40 +0200 Subject: [PATCH 33/35] Reworked lifecycle to not fully start LinphoneActivity at first start before the wizard --- src/org/linphone/LinphoneActivity.java | 16 +++++++++++----- .../linphone/assistant/AssistantActivity.java | 12 ++++++------ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java index dcdabcbfa..e33e90058 100644 --- a/src/org/linphone/LinphoneActivity.java +++ b/src/org/linphone/LinphoneActivity.java @@ -100,8 +100,6 @@ 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_OVERLAY = 206; private static final int PERMISSIONS_REQUEST_SYNC = 207; @@ -161,14 +159,22 @@ 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"); + } if (getResources().getBoolean(R.bool.use_linphone_tag)) { if (getPackageManager().checkPermission(Manifest.permission.WRITE_SYNC_SETTINGS, getPackageName()) != PackageManager.PERMISSION_GRANTED) { diff --git a/src/org/linphone/assistant/AssistantActivity.java b/src/org/linphone/assistant/AssistantActivity.java index a1b1216a5..03a1f4db4 100644 --- a/src/org/linphone/assistant/AssistantActivity.java +++ b/src/org/linphone/assistant/AssistantActivity.java @@ -42,6 +42,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; @@ -187,7 +188,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) { @@ -203,7 +205,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 @@ -519,10 +522,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(); } From 107fc4b54fb0595cf24e66699cb2da5d1b63115e Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 18 Jul 2016 15:33:47 +0200 Subject: [PATCH 34/35] Set correct content type when uploading image + store image as correct type (fix png transparency issue) --- res/values/non_localizable_custom.xml | 6 ++-- res/values/strings.xml | 1 - src/org/linphone/ChatFragment.java | 11 ++++-- src/org/linphone/LinphoneManager.java | 50 +++++++++++++++++++++------ src/org/linphone/LinphoneUtils.java | 9 +++++ src/org/linphone/ui/BubbleChat.java | 3 +- 6 files changed, 60 insertions(+), 20 deletions(-) diff --git a/res/values/non_localizable_custom.xml b/res/values/non_localizable_custom.xml index d938030fe..437890f35 100644 --- a/res/values/non_localizable_custom.xml +++ b/res/values/non_localizable_custom.xml @@ -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/strings.xml b/res/values/strings.xml index 4f55d9a5b..5711011d1 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 diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java index de94d40de..6c5cdafd8 100644 --- a/src/org/linphone/ChatFragment.java +++ b/src/org/linphone/ChatFragment.java @@ -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); @@ -909,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; } @@ -921,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/LinphoneManager.java b/src/org/linphone/LinphoneManager.java index 6efc2a469..6d5c1139e 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; @@ -79,6 +81,7 @@ import android.annotation.TargetApi; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.ContentResolver; +import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -102,6 +105,7 @@ import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.Vibrator; import android.provider.MediaStore; +import android.provider.MediaStore.Images; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.telephony.TelephonyManager; @@ -284,6 +288,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) { @@ -292,17 +330,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); } } 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/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); From edb9896105e5323cd55878601a1cf31af7b47d03 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 18 Jul 2016 15:43:18 +0200 Subject: [PATCH 35/35] Fix crash in linphone login on tablet --- res/layout-sw533dp-land/assistant_linphone_login.xml | 7 +++++++ 1 file changed, 7 insertions(+) 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"/> + +