diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java index 83bd637eb..c692df465 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -201,6 +201,8 @@ public class CallActivity extends AppCompatActivity { private PulseAnimation pulseAnimation; private View.OnClickListener videoOnClickListener; + private String baseUrl; + private static int getSystemUiVisibility() { int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; @@ -236,6 +238,13 @@ public class CallActivity extends AppCompatActivity { callSession = getIntent().getExtras().getString(BundleKeys.KEY_CALL_SESSION, "0"); credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()); + if (getIntent().getExtras().containsKey(BundleKeys.KEY_MODIFIED_BASE_URL)) { + credentials = null; + baseUrl = getIntent().getExtras().getString(BundleKeys.KEY_MODIFIED_BASE_URL); + } else { + baseUrl = userEntity.getBaseUrl(); + } + callControls.setZ(100.0f); basicInitialization(); @@ -281,7 +290,7 @@ public class CallActivity extends AppCompatActivity { } private void handleFromNotification() { - ncApi.getRooms(credentials, ApiUtils.getUrlForGetRooms(userEntity.getBaseUrl())) + ncApi.getRooms(credentials, ApiUtils.getUrlForGetRooms(baseUrl)) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer() { @@ -676,8 +685,7 @@ public class CallActivity extends AppCompatActivity { public void startPullingSignalingMessages() { leavingCall = false; - ncApi.getSignalingSettings(ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()), - ApiUtils.getUrlForSignalingSettings(userEntity.getBaseUrl())) + ncApi.getSignalingSettings(credentials, ApiUtils.getUrlForSignalingSettings(baseUrl)) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer() { @@ -737,7 +745,7 @@ public class CallActivity extends AppCompatActivity { private void joinRoomAndCall() { if (callSession.equals("0")) { - ncApi.joinRoom(credentials, ApiUtils.getUrlForRoomParticipants(userEntity.getBaseUrl(), roomToken), null) + ncApi.joinRoom(credentials, ApiUtils.getUrlForRoomParticipants(baseUrl, roomToken), null) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .retry(3) @@ -769,7 +777,7 @@ public class CallActivity extends AppCompatActivity { private void performCall(@Nullable String callSessionId) { ncApi.joinCall(credentials, - ApiUtils.getUrlForCall(userEntity.getBaseUrl(), roomToken)) + ApiUtils.getUrlForCall(baseUrl, roomToken)) .subscribeOn(Schedulers.newThread()) .retry(3) .observeOn(AndroidSchedulers.mainThread()) @@ -787,8 +795,7 @@ public class CallActivity extends AppCompatActivity { } // start pinging the call - ncApi.pingCall(ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()), - ApiUtils.getUrlForCallPing(userEntity.getBaseUrl(), roomToken)) + ncApi.pingCall(credentials, ApiUtils.getUrlForCallPing(baseUrl, roomToken)) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .repeatWhen(observable -> observable.delay(5000, TimeUnit.MILLISECONDS)) @@ -817,8 +824,7 @@ public class CallActivity extends AppCompatActivity { }); // Start pulling signaling messages - ncApi.pullSignalingMessages(ApiUtils.getCredentials(userEntity.getUsername(), - userEntity.getToken()), ApiUtils.getUrlForSignaling(userEntity.getBaseUrl())) + ncApi.pullSignalingMessages(credentials, ApiUtils.getUrlForSignaling(baseUrl)) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .repeatWhen(observable -> observable) @@ -945,8 +951,7 @@ public class CallActivity extends AppCompatActivity { Set oldSesssions = new HashSet<>(); for (HashMap participant : users) { - if (!participant.get("sessionId").equals(callSession) && !participant.get("userId").equals(userEntity - .getUserId())) { + if (!participant.get("sessionId").equals(callSession)) { Object inCallObject = participant.get("inCall"); if ((boolean) inCallObject) { newSessions.add(participant.get("sessionId")); @@ -1050,7 +1055,7 @@ public class CallActivity extends AppCompatActivity { localAudioTrack = null; localVideoTrack = null; - if (!dueToNetworkChange) { + if (!dueToNetworkChange && credentials != null) { hangupNetworkCalls(); } else { finish(); @@ -1058,8 +1063,7 @@ public class CallActivity extends AppCompatActivity { } private void hangupNetworkCalls() { - String credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()); - ncApi.leaveCall(credentials, ApiUtils.getUrlForCall(userEntity.getBaseUrl(), roomToken)) + ncApi.leaveCall(credentials, ApiUtils.getUrlForCall(baseUrl, roomToken)) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer() { @@ -1070,7 +1074,7 @@ public class CallActivity extends AppCompatActivity { @Override public void onNext(GenericOverall genericOverall) { - ncApi.leaveRoom(credentials, ApiUtils.getUrlForRoomParticipants(userEntity.getBaseUrl(), roomToken)) + ncApi.leaveRoom(credentials, ApiUtils.getUrlForRoomParticipants(baseUrl, roomToken)) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer() { @@ -1277,7 +1281,6 @@ public class CallActivity extends AppCompatActivity { @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onMessageEvent(SessionDescriptionSendEvent sessionDescriptionSend) throws IOException { - String credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()); NCMessageWrapper ncMessageWrapper = new NCMessageWrapper(); ncMessageWrapper.setEv("message"); ncMessageWrapper.setSessionId(callSession); @@ -1317,7 +1320,7 @@ public class CallActivity extends AppCompatActivity { String stringToSend = stringBuilder.toString(); strings.add(stringToSend); - ncApi.sendSignalingMessages(credentials, ApiUtils.getUrlForSignaling(userEntity.getBaseUrl()), + ncApi.sendSignalingMessages(credentials, ApiUtils.getUrlForSignaling(baseUrl), strings.toString()) .retry(3) .subscribeOn(Schedulers.newThread()) @@ -1427,7 +1430,7 @@ public class CallActivity extends AppCompatActivity { @Override public void onBackPressed() { - hangup(false); + onHangupClick(); } private class microphoneButtonTouchListener implements View.OnTouchListener { diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index 951244d00..2c4944fba 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -143,34 +143,34 @@ public interface NcApi { @FormUrlEncoded @POST - Observable joinRoom(@Header("Authorization") String authorization, @Url String url, + Observable joinRoom(@Nullable @Header("Authorization") String authorization, @Url String url, @Nullable @Field("password") String password); @DELETE - Observable leaveRoom(@Header("Authorization") String authorization, @Url String url); + Observable leaveRoom(@Nullable @Header("Authorization") String authorization, @Url String url); /* Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken */ @POST - Observable joinCall(@Header("Authorization") String authorization, @Url String url); + Observable joinCall(@Nullable @Header("Authorization") String authorization, @Url String url); /* Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken */ @DELETE - Observable leaveCall(@Header("Authorization") String authorization, @Url String url); + Observable leaveCall(@Nullable @Header("Authorization") String authorization, @Url String url); /* Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /call/callToken/ping */ @POST - Observable pingCall(@Header("Authorization") String authorization, @Url String url); + Observable pingCall(@Nullable @Header("Authorization") String authorization, @Url String url); @GET - Observable getSignalingSettings(@Header("Authorization") String authorization, @Url - String url); + Observable getSignalingSettings(@Nullable @Header("Authorization") String authorization, + @Url String url); /* QueryMap items are as follows: @@ -180,14 +180,16 @@ public interface NcApi { */ @FormUrlEncoded @POST - Observable sendSignalingMessages(@Header("Authorization") String authorization, @Url String url, + Observable sendSignalingMessages(@Nullable@Header("Authorization") String authorization, @Url String url, @Field("messages") String messages); /* Server URL is: baseUrl + ocsApiVersion + spreedApiVersion + /signaling */ @GET - Observable pullSignalingMessages(@Header("Authorization") String authorization, @Url String url); + Observable pullSignalingMessages(@Nullable @Header("Authorization") String authorization, @Url + String + url); /* QueryMap items are as follows: diff --git a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java index ff9536b17..4a07266d2 100644 --- a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java +++ b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java @@ -113,6 +113,31 @@ public class NextcloudTalkApplication extends MultiDexApplication implements Pro super.onCreate(); ProviderInstaller.installIfNeededAsync(this, this); + /*if (Build.MANUFACTURER.equalsIgnoreCase("huawei")) { + try { + Class enclosingClass = Class.forName("com.huawei.systemmanager.startupmgr.db.StartupDataMgrHelper"); + Method method = enclosingClass.getMethod("modifyNormalStartupInfoStatus", Context.class, String.class, boolean.class); + method.invoke(null, getApplicationContext(), getPackageName(), true); + + Class secondaryEnclosingClass = Class.forName("com.huawei.systemmanager.optimize.process" + + ".ProtectAppControl"); + Method secondaryMethod = secondaryEnclosingClass.getMethod("getInstance", Context.class); + Object object = secondaryMethod.invoke(null, getApplicationContext()); + Method thirdMethod = secondaryEnclosingClass.getMethod("setNoProtect", List.class); + List packageNames = new ArrayList<>(); + packageNames.add(getPackageName()); + thirdMethod.invoke(object, packageNames); + } catch (ClassNotFoundException e) { + Log.e(TAG, "Failed to find the required class on Huawei"); + } catch (NoSuchMethodException e) { + Log.e(TAG, "Failed to find the appropriate method"); + } catch (IllegalAccessException e) { + Log.e(TAG, "Illegal access exception"); + } catch (InvocationTargetException e) { + Log.e(TAG, "Invocation target exception"); + } + }*/ + JobManager.create(this).addJobCreator(new MagicJobCreator()); FirebaseAnalytics.getInstance(this).setAnalyticsCollectionEnabled(false); @@ -138,6 +163,8 @@ public class NextcloudTalkApplication extends MultiDexApplication implements Pro } + private void prepareThingsForStrangePhones() { + } @Override public void onTerminate() { super.onTerminate(); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java b/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java index 9acabf805..83b6a29d5 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallsListController.java @@ -231,16 +231,9 @@ public class CallsListController extends BaseController implements SearchView.On public boolean onOptionsItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case R.id.action_new_conversation: - searchItem.setVisible(false); - menuVariable.findItem(R.id.action_new_conversation).setVisible(false); Bundle bundle = new Bundle(); - bundle.putBoolean(BundleKeys.KEY_NEW_CONVERSATION, true); - if (getParentController() != null) { - getParentController().getRouter().pushController( - (RouterTransaction.with(new ContactsController(bundle)) - .pushChangeHandler(new VerticalChangeHandler()) - .popChangeHandler(new VerticalChangeHandler()))); - } + bundle.putParcelable(BundleKeys.KEY_MENU_TYPE, Parcels.wrap(CallMenuController.MenuType.NEW_CONVERSATION)); + prepareAndShowBottomSheetWithBundle(bundle, true); return true; default: return super.onOptionsItemSelected(item); @@ -445,6 +438,7 @@ public class CallsListController extends BaseController implements SearchView.On Bundle bundle = new Bundle(); Room room = moreMenuClickEvent.getRoom(); bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(room)); + bundle.putParcelable(BundleKeys.KEY_MENU_TYPE, Parcels.wrap(CallMenuController.MenuType.REGULAR)); prepareAndShowBottomSheetWithBundle(bundle, true); } @@ -455,13 +449,13 @@ public class CallsListController extends BaseController implements SearchView.On if (shouldShowCallMenuController) { getChildRouter((ViewGroup) view).setRoot( RouterTransaction.with(new CallMenuController(bundle)) - .popChangeHandler(new HorizontalChangeHandler()) - .pushChangeHandler(new HorizontalChangeHandler())); + .popChangeHandler(new VerticalChangeHandler()) + .pushChangeHandler(new VerticalChangeHandler())); } else { getChildRouter((ViewGroup) view).setRoot( RouterTransaction.with(new EntryMenuController(bundle)) - .popChangeHandler(new HorizontalChangeHandler()) - .pushChangeHandler(new HorizontalChangeHandler())); + .popChangeHandler(new VerticalChangeHandler()) + .pushChangeHandler(new VerticalChangeHandler())); } boolean isNew = false; diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java index d0fe90c8d..7ebb69d6d 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java @@ -32,11 +32,14 @@ import android.view.View; import android.view.ViewGroup; import com.bluelinelabs.conductor.RouterTransaction; +import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; +import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler; import com.kennyc.bottomsheet.adapters.AppAdapter; import com.nextcloud.talk.R; import com.nextcloud.talk.adapters.items.AppItem; import com.nextcloud.talk.adapters.items.MenuItem; import com.nextcloud.talk.application.NextcloudTalkApplication; +import com.nextcloud.talk.controllers.ContactsController; import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.events.BottomSheetLockEvent; import com.nextcloud.talk.models.json.rooms.Room; @@ -45,6 +48,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys; import com.nextcloud.talk.utils.database.user.UserUtils; import org.greenrobot.eventbus.EventBus; +import org.parceler.Parcel; import org.parceler.Parcels; import java.util.ArrayList; @@ -73,14 +77,19 @@ public class CallMenuController extends BaseController implements FlexibleAdapte private List menuItems; private FlexibleAdapter adapter; - private boolean isShare; + @Parcel + public enum MenuType { + REGULAR, SHARE, NEW_CONVERSATION + } + + private MenuType menuType; private Intent shareIntent; public CallMenuController(Bundle args) { super(args); this.room = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM)); - if (args.containsKey(BundleKeys.KEY_IS_SHARE)) { - this.isShare = true; + if (args.containsKey(BundleKeys.KEY_MENU_TYPE)) { + this.menuType = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_MENU_TYPE)); } } @@ -124,7 +133,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte private void prepareMenu() { menuItems = new ArrayList<>(); - if (!isShare) { + if (menuType.equals(MenuType.REGULAR)) { menuItems.add(new MenuItem(getResources().getString(R.string.nc_what), 0)); menuItems.add(new MenuItem(getResources().getString(R.string.nc_leave), 1)); @@ -156,7 +165,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte if (room.isDeletable()) { menuItems.add(new MenuItem(getResources().getString(R.string.nc_delete_call), 9)); } - } else { + } else if (menuType.equals(MenuType.SHARE)) { prepareIntent(); List appInfoList = ShareUtils.getShareApps(getActivity(), shareIntent, null, null); @@ -167,6 +176,10 @@ public class CallMenuController extends BaseController implements FlexibleAdapte menuItems.add(new AppItem(appInfo.title, appInfo.packageName, appInfo.name, appInfo.drawable)); } } + } else { + menuItems.add(new MenuItem(getResources().getString(R.string.nc_what), 0)); + menuItems.add(new MenuItem(getResources().getString(R.string.nc_new_conversation), 1)); + menuItems.add(new MenuItem(getResources().getString(R.string.nc_join_via_link), 2)); } } @@ -175,7 +188,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte Bundle bundle = new Bundle(); bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(room)); - if (!isShare) { + if (menuType.equals(MenuType.REGULAR)) { MenuItem menuItem = (MenuItem) adapter.getItem(position); if (menuItem != null) { @@ -188,16 +201,22 @@ public class CallMenuController extends BaseController implements FlexibleAdapte bundle.putInt(BundleKeys.KEY_OPERATION_CODE, tag); if (tag != 2 && tag != 4 && tag != 6 && tag != 7) { eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); - getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle))); + getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) + .pushChangeHandler(new HorizontalChangeHandler()) + .popChangeHandler(new HorizontalChangeHandler())); } else if (tag != 7) { - getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle))); + getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle)) + .pushChangeHandler(new VerticalChangeHandler()) + .popChangeHandler(new VerticalChangeHandler())); } else { - bundle.putBoolean(BundleKeys.KEY_IS_SHARE, true); - getRouter().pushController(RouterTransaction.with(new CallMenuController(bundle))); + bundle.putParcelable(BundleKeys.KEY_MENU_TYPE, Parcels.wrap(MenuType.SHARE)); + getRouter().pushController(RouterTransaction.with(new CallMenuController(bundle)) + .pushChangeHandler(new VerticalChangeHandler()) + .popChangeHandler(new VerticalChangeHandler())); } } } - } else if (position != 0) { + } else if (menuType.equals(MenuType.SHARE) && position != 0) { AppItem appItem = (AppItem) adapter.getItem(position); if (appItem != null && getActivity() != null) { if (!room.hasPassword) { @@ -213,7 +232,30 @@ public class CallMenuController extends BaseController implements FlexibleAdapte bundle.putParcelable(BundleKeys.KEY_SHARE_INTENT, Parcels.wrap(shareIntent)); bundle.putString(BundleKeys.KEY_APP_ITEM_PACKAGE_NAME, appItem.getPackageName()); bundle.putString(BundleKeys.KEY_APP_ITEM_NAME, appItem.getName()); - getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle))); + getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle)) + .pushChangeHandler(new VerticalChangeHandler()) + .popChangeHandler(new VerticalChangeHandler())); + } + } + } else if (menuType.equals(MenuType.NEW_CONVERSATION) && position != 0) { + MenuItem menuItem = (MenuItem) adapter.getItem(position); + if (menuItem != null) { + if (menuItem.getTag() == 1) { + eventBus.post(new BottomSheetLockEvent(true, 0, false, true)); + bundle = new Bundle(); + bundle.putBoolean(BundleKeys.KEY_NEW_CONVERSATION, true); + if (getParentController() != null && getParentController().getParentController() != null) { + getParentController().getParentController().getRouter().pushController( + (RouterTransaction.with(new ContactsController(bundle)) + .pushChangeHandler(new VerticalChangeHandler()) + .popChangeHandler(new VerticalChangeHandler()))); + } + } else { + bundle = new Bundle(); + bundle.putInt(BundleKeys.KEY_OPERATION_CODE, 10); + getRouter().pushController(RouterTransaction.with(new EntryMenuController(bundle)) + .pushChangeHandler(new HorizontalChangeHandler()) + .popChangeHandler(new HorizontalChangeHandler())); } } } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java index 5f790c4c7..91a274e58 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java @@ -34,6 +34,7 @@ import android.view.inputmethod.EditorInfo; import android.widget.Button; import com.bluelinelabs.conductor.RouterTransaction; +import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler; import com.nextcloud.talk.R; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; @@ -84,7 +85,9 @@ public class EntryMenuController extends BaseController { public EntryMenuController(Bundle args) { super(args); this.operationCode = args.getInt(BundleKeys.KEY_OPERATION_CODE); - this.room = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM)); + if (args.containsKey(BundleKeys.KEY_ROOM)) { + this.room = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM)); + } if (args.containsKey(BundleKeys.KEY_SHARE_INTENT)) { this.shareIntent = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_SHARE_INTENT)); @@ -123,12 +126,13 @@ public class EntryMenuController extends BaseController { eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); bundle = new Bundle(); bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(room)); - bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(userEntity)); bundle.putString(BundleKeys.KEY_CALL_PASSWORD, editText.getText().toString()); - getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle))); + getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) + .pushChangeHandler(new HorizontalChangeHandler()) + .popChangeHandler(new HorizontalChangeHandler())); } - } else if (operationCode != 7) { + } else if (operationCode != 7 && operationCode != 10) { eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); bundle = new Bundle(); if (operationCode == 4 || operationCode == 6) { @@ -138,8 +142,10 @@ public class EntryMenuController extends BaseController { } bundle.putParcelable(BundleKeys.KEY_ROOM, Parcels.wrap(room)); bundle.putInt(BundleKeys.KEY_OPERATION_CODE, operationCode); - getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle))); - } else { + getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) + .pushChangeHandler(new HorizontalChangeHandler()) + .popChangeHandler(new HorizontalChangeHandler())); + } else if (operationCode == 7) { if (getActivity() != null) { shareIntent.putExtra(Intent.EXTRA_TEXT, ShareUtils.getStringForIntent(getActivity(), editText.getText().toString(), userUtils, room)); @@ -149,6 +155,15 @@ public class EntryMenuController extends BaseController { getActivity().startActivity(intent); eventBus.post(new BottomSheetLockEvent(true, 0, false, true)); } + } else { + eventBus.post(new BottomSheetLockEvent(false, 0, false, false)); + bundle = new Bundle(); + bundle.putInt(BundleKeys.KEY_OPERATION_CODE, operationCode); + bundle.putString(BundleKeys.KEY_CALL_URL, editText.getText().toString()); + getRouter().pushController(RouterTransaction.with(new OperationsMenuController(bundle)) + .pushChangeHandler(new HorizontalChangeHandler()) + .popChangeHandler(new HorizontalChangeHandler())); + } } @@ -193,11 +208,27 @@ public class EntryMenuController extends BaseController { textFieldBoxes.setError(getResources().getString(R.string.nc_call_name_is_same), true); } - } else { + } else if (operationCode != 10) { if (!proceedButton.isEnabled()) { proceedButton.setEnabled(true); proceedButton.setAlpha(1.0f); } + } else if (editText.getText().toString().startsWith("http://") || + editText.getText().toString().startsWith("https://") && + editText.getText().toString().contains("/call/")) { + // operation code 10 + if (!proceedButton.isEnabled()) { + proceedButton.setEnabled(true); + proceedButton.setAlpha(1.0f); + + } + } else { + if (proceedButton.isEnabled()) { + proceedButton.setEnabled(false); + proceedButton.setAlpha(0.7f); + } + textFieldBoxes.setError(getResources().getString(R.string.nc_wrong_link), + true); } } else { if (proceedButton.isEnabled()) { @@ -219,8 +250,12 @@ public class EntryMenuController extends BaseController { case 6: case 7: case 99: + // 99 is joining a room via password labelText = getResources().getString(R.string.nc_password); break; + case 10: + labelText = getResources().getString(R.string.nc_conversation_link); + break; default: break; } diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java index ce4334ef0..d50983410 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/OperationsMenuController.java @@ -39,8 +39,8 @@ import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.events.BottomSheetLockEvent; import com.nextcloud.talk.models.database.UserEntity; -import com.nextcloud.talk.models.json.call.CallOverall; import com.nextcloud.talk.models.json.rooms.Room; +import com.nextcloud.talk.models.json.rooms.RoomOverall; import com.nextcloud.talk.utils.ApiUtils; import com.nextcloud.talk.utils.ApplicationWideMessageHolder; import com.nextcloud.talk.utils.DisplayUtils; @@ -90,21 +90,21 @@ public class OperationsMenuController extends BaseController { private UserEntity userEntity; private String callPassword; + private String callUrl; + + private String baseUrl; private Disposable disposable; - private Disposable secondaryDisposable; - - private int retryCount = 0; public OperationsMenuController(Bundle args) { super(args); this.operationCode = args.getInt(BundleKeys.KEY_OPERATION_CODE); - this.room = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM)); + if (args.containsKey(BundleKeys.KEY_ROOM)) { + this.room = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_ROOM)); + } this.callPassword = args.getString(BundleKeys.KEY_CALL_PASSWORD, ""); - if (args.containsKey(BundleKeys.KEY_USER_ENTITY)) { - this.userEntity = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_USER_ENTITY)); - } + this.callUrl = args.getString(BundleKeys.KEY_CALL_URL, ""); } @Override @@ -121,7 +121,7 @@ public class OperationsMenuController extends BaseController { } private void processOperation() { - UserEntity userEntity = userUtils.getCurrentUser(); + userEntity = userUtils.getCurrentUser(); OperationsObserver operationsObserver = new OperationsObserver(); if (userEntity != null) { String credentials = ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()); @@ -181,6 +181,46 @@ public class OperationsMenuController extends BaseController { .observeOn(AndroidSchedulers.mainThread()) .retry(1) .subscribe(operationsObserver); + case 10: + String conversationToken = callUrl.substring(callUrl.lastIndexOf("/") + 1, callUrl.length()); + if (callUrl.contains("/index.php")) { + baseUrl = callUrl.substring(0, callUrl.indexOf("/index.php")); + } else { + baseUrl = callUrl.substring(0, callUrl.indexOf("/call")); + } + + ncApi.getRoom(credentials, ApiUtils.getRoom(baseUrl, conversationToken)) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .retry(1) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + disposable = d; + } + + @Override + public void onNext(RoomOverall roomOverall) { + room = roomOverall.getOcs().getData(); + if (room.isHasPassword() && room.isGuest()) { + + } else { + initiateCall(); + } + } + + @Override + public void onError(Throwable e) { + showResultImage(false, false); + dispose(); + } + + @Override + public void onComplete() { + dispose(); + } + }); + break; case 99: ncApi.joinRoom(credentials, ApiUtils.getUrlForRoomParticipants(userEntity.getBaseUrl(), room.getToken()), callPassword) @@ -195,7 +235,7 @@ public class OperationsMenuController extends BaseController { } } - private void showResultImage(boolean everythingOK) { + private void showResultImage(boolean everythingOK, boolean isSignalingSettingsError) { progressBar.setVisibility(View.GONE); if (everythingOK) { @@ -212,7 +252,11 @@ public class OperationsMenuController extends BaseController { resultsTextView.setText(R.string.nc_all_ok_operation); } else { resultsTextView.setTextColor(getResources().getColor(R.color.nc_darkRed)); - resultsTextView.setText(R.string.nc_failed_to_perform_operation); + if (!isSignalingSettingsError) { + resultsTextView.setText(R.string.nc_failed_to_perform_operation); + } else { + resultsTextView.setText(R.string.nc_failed_signaling_settings); + } } resultsTextView.setVisibility(View.VISIBLE); @@ -221,8 +265,8 @@ public class OperationsMenuController extends BaseController { } else { resultImageView.setImageDrawable(DisplayUtils.getTintedDrawable(getResources(), R.drawable .ic_cancel_black_24dp, R.color.nc_darkRed)); - okButton.setOnClickListener(v -> eventBus.post(new BottomSheetLockEvent(true, 0, operationCode != 99, - true))); + okButton.setOnClickListener(v -> eventBus.post(new BottomSheetLockEvent(true, 0, operationCode != 99 + && operationCode != 10, true))); okButton.setVisibility(View.VISIBLE); } } @@ -241,35 +285,41 @@ public class OperationsMenuController extends BaseController { dispose(); } + private void initiateCall() { + eventBus.post(new BottomSheetLockEvent(true, 0, false, true)); + Bundle bundle = new Bundle(); + bundle.putString(BundleKeys.KEY_ROOM_TOKEN, room.getToken()); + bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(userEntity)); + if (!baseUrl.equals(userEntity.getBaseUrl())) { + bundle.putString(BundleKeys.KEY_MODIFIED_BASE_URL, baseUrl); + } + overridePushHandler(new NoOpControllerChangeHandler()); + overridePopHandler(new NoOpControllerChangeHandler()); + Intent callIntent = new Intent(getActivity(), CallActivity.class); + callIntent.putExtras(bundle); + startActivity(callIntent); + } + private class OperationsObserver implements Observer { @Override public void onSubscribe(Disposable d) { disposable = d; - retryCount++; } @Override public void onNext(Object o) { if (operationCode != 99) { - showResultImage(true); + showResultImage(true, false); } else { - Bundle bundle = new Bundle(); - bundle.putString(BundleKeys.KEY_ROOM_TOKEN, room.getToken()); - bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(userEntity)); - bundle.putString(BundleKeys.KEY_CALL_SESSION, ((CallOverall) o).getOcs().getData().getSessionId()); - overridePushHandler(new NoOpControllerChangeHandler()); - overridePopHandler(new NoOpControllerChangeHandler()); - Intent callIntent = new Intent(getActivity(), CallActivity.class); - callIntent.putExtras(bundle); - startActivity(callIntent); + initiateCall(); } } @Override public void onError(Throwable e) { if (operationCode != 99 || !(e instanceof HttpException)) { - showResultImage(false); + showResultImage(false, false); } else { if (((HttpException) e).response().code() == 403) { eventBus.post(new BottomSheetLockEvent(true, 0, false, @@ -277,7 +327,7 @@ public class OperationsMenuController extends BaseController { ApplicationWideMessageHolder.getInstance().setMessageType(ApplicationWideMessageHolder.MessageType.CALL_PASSWORD_WRONG); getRouter().popCurrentController(); } else { - showResultImage(false); + showResultImage(false, false); } } dispose(); diff --git a/app/src/main/java/com/nextcloud/talk/jobs/NotificationJob.java b/app/src/main/java/com/nextcloud/talk/jobs/NotificationJob.java new file mode 100644 index 000000000..d04236508 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/jobs/NotificationJob.java @@ -0,0 +1,222 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2018 Mario Danic + * + * 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 3 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, see . + */ + +package com.nextcloud.talk.jobs; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; + +import com.bluelinelabs.logansquare.LoganSquare; +import com.evernote.android.job.Job; +import com.evernote.android.job.util.support.PersistableBundleCompat; +import com.nextcloud.talk.R; +import com.nextcloud.talk.activities.CallActivity; +import com.nextcloud.talk.models.SignatureVerification; +import com.nextcloud.talk.models.json.push.DecryptedPushMessage; +import com.nextcloud.talk.models.json.push.PushMessage; +import com.nextcloud.talk.utils.NotificationUtils; +import com.nextcloud.talk.utils.PushUtils; +import com.nextcloud.talk.utils.bundle.BundleKeys; + +import org.parceler.Parcels; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.util.Calendar; +import java.util.zip.CRC32; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; + +public class NotificationJob extends Job { + public static final String TAG = "NotificationJob"; + + @NonNull + @Override + protected Result onRunJob(Params params) { + Context context = getContext(); + PersistableBundleCompat persistableBundleCompat = getParams().getExtras(); + String subject = persistableBundleCompat.getString(BundleKeys.KEY_NOTIFICATION_SUBJECT, ""); + String signature = persistableBundleCompat.getString(BundleKeys.KEY_NOTIFICATION_SIGNATURE, ""); + + if (!TextUtils.isEmpty(subject) && !TextUtils.isEmpty(signature)) { + + try { + PushMessage pushMessage = new PushMessage(); + pushMessage.setSubject(subject); + pushMessage.setSignature(signature); + + byte[] base64DecodedSubject = Base64.decode(pushMessage.getSubject(), Base64.DEFAULT); + byte[] base64DecodedSignature = Base64.decode(pushMessage.getSignature(), Base64.DEFAULT); + PushUtils pushUtils = new PushUtils(); + PrivateKey privateKey = (PrivateKey) pushUtils.readKeyFromFile(false); + + try { + SignatureVerification signatureVerification = pushUtils.verifySignature(base64DecodedSignature, + base64DecodedSubject); + + if (signatureVerification.isSignatureValid()) { + Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + byte[] decryptedSubject = cipher.doFinal(base64DecodedSubject); + DecryptedPushMessage decryptedPushMessage = LoganSquare.parse(new String(decryptedSubject), + DecryptedPushMessage.class); + + if (decryptedPushMessage.getApp().equals("spreed")) { + int smallIcon; + Bitmap largeIcon; + String category = ""; + int priority = Notification.PRIORITY_DEFAULT; + Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + + Intent intent = new Intent(context, CallActivity.class); + Bundle bundle = new Bundle(); + bundle.putString(BundleKeys.KEY_ROOM_TOKEN, decryptedPushMessage.getId()); + bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(signatureVerification + .getUserEntity())); + bundle.putBoolean("fromNotification", true); + intent.putExtras(bundle); + + PendingIntent pendingIntent = PendingIntent.getActivity(context, + 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + + NotificationManager notificationManager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + switch (decryptedPushMessage.getType()) { + case "call": + smallIcon = R.drawable.ic_call_black_24dp; + category = Notification.CATEGORY_CALL; + priority = Notification.PRIORITY_HIGH; + soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE); + break; + case "room": + smallIcon = R.drawable.ic_notifications_black_24dp; + category = Notification.CATEGORY_CALL; + priority = Notification.PRIORITY_HIGH; + break; + case "chat": + smallIcon = R.drawable.ic_chat_black_24dp; + category = Notification.CATEGORY_MESSAGE; + break; + default: + smallIcon = R.drawable.ic_logo; + } + + largeIcon = BitmapFactory.decodeResource(context.getResources(), smallIcon); + CRC32 crc32 = new CRC32(); + + Notification.Builder notificationBuilder = new Notification.Builder(context) + .setLargeIcon(largeIcon) + .setSmallIcon(smallIcon) + .setCategory(category) + .setPriority(priority) + .setWhen(Calendar.getInstance().getTimeInMillis()) + .setShowWhen(true) + .setSubText(signatureVerification.getUserEntity().getDisplayName()) + .setContentTitle(decryptedPushMessage.getSubject()) + .setSound(soundUri) + .setAutoCancel(true); + + if (Build.VERSION.SDK_INT >= 23) { + // This method should exist since API 21, but some phones don't have it + // So as a safeguard, we don't use it until 23 + notificationBuilder.setColor(context.getResources().getColor(R.color.colorPrimary)); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + + String groupName = String.format(context.getResources().getString(R.string + .nc_notification_channel), signatureVerification.getUserEntity() + .getDisplayName(), signatureVerification.getUserEntity().getBaseUrl()); + crc32.update(groupName.getBytes()); + + NotificationUtils.createNotificationChannelGroup(notificationManager, + Long.toString(crc32.getValue()), + groupName); + + if (category.equals(Notification.CATEGORY_CALL)) { + NotificationUtils.createNotificationChannel(notificationManager, + NotificationUtils.NOTIFICATION_CHANNEL_CALLS, context.getResources() + .getString(R + .string.nc_notification_channel_calls), context.getResources() + .getString + (R.string.nc_notification_channel_calls_description), true, + NotificationManager.IMPORTANCE_HIGH, soundUri); + + notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_CALLS); + } else { + NotificationUtils.createNotificationChannel(notificationManager, + NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES, context.getResources() + .getString(R + .string.nc_notification_channel_messages), context.getResources() + .getString + (R.string.nc_notification_channel_messages_description), true, + NotificationManager.IMPORTANCE_DEFAULT, soundUri); + + notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES); + } + + notificationBuilder.setGroup(Long.toString(crc32.getValue())); + } + + notificationBuilder.setContentIntent(pendingIntent); + + String stringForCrc = decryptedPushMessage.getSubject() + " " + signatureVerification + .getUserEntity().getDisplayName() + " " + signatureVerification.getUserEntity + ().getBaseUrl(); + + crc32 = new CRC32(); + crc32.update(stringForCrc.getBytes()); + + if (notificationManager != null) { + notificationManager.notify((int) crc32.getValue(), notificationBuilder.build()); + } + } + + } + } catch (NoSuchAlgorithmException e1) { + Log.d(TAG, "No proper algorithm to decrypt the message " + e1.getLocalizedMessage()); + } catch (NoSuchPaddingException e1) { + Log.d(TAG, "No proper padding to decrypt the message " + e1.getLocalizedMessage()); + } catch (InvalidKeyException e1) { + Log.d(TAG, "Invalid private key " + e1.getLocalizedMessage()); + } + } catch (Exception exception) { + Log.d(TAG, "Something went very wrong" + exception.getLocalizedMessage()); + } + } + return Result.SUCCESS; + } +} diff --git a/app/src/main/java/com/nextcloud/talk/jobs/creator/MagicJobCreator.java b/app/src/main/java/com/nextcloud/talk/jobs/creator/MagicJobCreator.java index 60e228e3e..af01fddfc 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/creator/MagicJobCreator.java +++ b/app/src/main/java/com/nextcloud/talk/jobs/creator/MagicJobCreator.java @@ -26,6 +26,7 @@ import android.support.annotation.Nullable; import com.evernote.android.job.Job; import com.evernote.android.job.JobCreator; import com.nextcloud.talk.jobs.AccountRemovalJob; +import com.nextcloud.talk.jobs.NotificationJob; import com.nextcloud.talk.jobs.PushRegistrationJob; public class MagicJobCreator implements JobCreator { @@ -39,6 +40,8 @@ public class MagicJobCreator implements JobCreator { return new PushRegistrationJob(); case AccountRemovalJob.TAG: return new AccountRemovalJob(); + case NotificationJob.TAG: + return new NotificationJob(); default: return null; } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/rooms/Room.java b/app/src/main/java/com/nextcloud/talk/models/json/rooms/Room.java index b23b8ce50..647fca189 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/rooms/Room.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/rooms/Room.java @@ -68,6 +68,11 @@ public class Room { return (RoomType.ROOM_PUBLIC_CALL.equals(type)); } + public boolean isGuest() { + return (Participant.ParticipantType.GUEST.equals(participantType) || + Participant.ParticipantType.USER_FOLLOWING_LINK.equals(participantType)); + } + public boolean canModerate() { return (Participant.ParticipantType.OWNER.equals(participantType) || Participant.ParticipantType.MODERATOR.equals(participantType)); diff --git a/app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.java b/app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.java index 60c4391a0..bacb05460 100644 --- a/app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.java +++ b/app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.java @@ -21,43 +21,14 @@ package com.nextcloud.talk.services.firebase; import android.annotation.SuppressLint; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.RingtoneManager; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.util.Base64; -import android.util.Log; -import com.bluelinelabs.logansquare.LoganSquare; +import com.evernote.android.job.JobRequest; +import com.evernote.android.job.util.support.PersistableBundleCompat; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; -import com.nextcloud.talk.R; -import com.nextcloud.talk.activities.CallActivity; -import com.nextcloud.talk.models.SignatureVerification; -import com.nextcloud.talk.models.json.push.DecryptedPushMessage; -import com.nextcloud.talk.models.json.push.PushMessage; -import com.nextcloud.talk.utils.NotificationUtils; -import com.nextcloud.talk.utils.PushUtils; +import com.nextcloud.talk.jobs.NotificationJob; import com.nextcloud.talk.utils.bundle.BundleKeys; -import org.parceler.Parcels; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.util.Calendar; -import java.util.zip.CRC32; - -import javax.crypto.Cipher; -import javax.crypto.NoSuchPaddingException; - public class MagicFirebaseMessagingService extends FirebaseMessagingService { private static final String TAG = "MagicFirebaseMessagingService"; @@ -65,149 +36,17 @@ public class MagicFirebaseMessagingService extends FirebaseMessagingService { @Override public void onMessageReceived(RemoteMessage remoteMessage) { if (remoteMessage.getData() != null) { - try { - PushMessage pushMessage = new PushMessage(); - pushMessage.setSubject(remoteMessage.getData().get("subject")); - pushMessage.setSignature(remoteMessage.getData().get("signature")); - - byte[] base64DecodedSubject = android.util.Base64.decode(pushMessage.getSubject(), Base64.DEFAULT); - byte[] base64DecodedSignature = android.util.Base64.decode(pushMessage.getSignature(), Base64.DEFAULT); - PushUtils pushUtils = new PushUtils(); - PrivateKey privateKey = (PrivateKey) pushUtils.readKeyFromFile(false); - - try { - SignatureVerification signatureVerification = pushUtils.verifySignature(base64DecodedSignature, - base64DecodedSubject); - - if (signatureVerification.isSignatureValid()) { - Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding"); - cipher.init(Cipher.DECRYPT_MODE, privateKey); - byte[] decryptedSubject = cipher.doFinal(base64DecodedSubject); - DecryptedPushMessage decryptedPushMessage = LoganSquare.parse(new String(decryptedSubject), - DecryptedPushMessage.class); - - if (decryptedPushMessage.getApp().equals("spreed")) { - int smallIcon; - Bitmap largeIcon; - String category = ""; - int priority = Notification.PRIORITY_DEFAULT; - Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - - Intent intent = new Intent(this, CallActivity.class); - Bundle bundle = new Bundle(); - bundle.putString(BundleKeys.KEY_ROOM_TOKEN, decryptedPushMessage.getId()); - bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(signatureVerification - .getUserEntity())); - bundle.putBoolean("fromNotification", true); - intent.putExtras(bundle); - - PendingIntent pendingIntent = PendingIntent.getActivity(this, - 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); - - NotificationManager notificationManager = - (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - - switch (decryptedPushMessage.getType()) { - case "call": - smallIcon = R.drawable.ic_call_black_24dp; - category = Notification.CATEGORY_CALL; - priority = Notification.PRIORITY_HIGH; - soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE); - break; - case "room": - smallIcon = R.drawable.ic_notifications_black_24dp; - category = Notification.CATEGORY_CALL; - priority = Notification.PRIORITY_HIGH; - break; - case "chat": - smallIcon = R.drawable.ic_chat_black_24dp; - category = Notification.CATEGORY_MESSAGE; - break; - default: - smallIcon = R.drawable.ic_logo; - } - - largeIcon = BitmapFactory.decodeResource(getResources(), smallIcon); - CRC32 crc32 = new CRC32(); - - Notification.Builder notificationBuilder = new Notification.Builder(this) - .setLargeIcon(largeIcon) - .setSmallIcon(smallIcon) - .setCategory(category) - .setPriority(priority) - .setWhen(Calendar.getInstance().getTimeInMillis()) - .setShowWhen(true) - .setSubText(signatureVerification.getUserEntity().getDisplayName()) - .setContentTitle(decryptedPushMessage.getSubject()) - .setSound(soundUri) - .setAutoCancel(true); - - if (Build.VERSION.SDK_INT >= 23) { - // This method should exist since API 21, but some phones don't have it - // So as a safeguard, we don't use it until 23 - notificationBuilder.setColor(getResources().getColor(R.color.colorPrimary)); - } - - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - - String groupName = String.format(getResources().getString(R.string - .nc_notification_channel), signatureVerification.getUserEntity() - .getDisplayName(), signatureVerification.getUserEntity().getBaseUrl()); - crc32.update(groupName.getBytes()); - - NotificationUtils.createNotificationChannelGroup(notificationManager, - Long.toString(crc32.getValue()), - groupName); - - if (category.equals(Notification.CATEGORY_CALL)) { - NotificationUtils.createNotificationChannel(notificationManager, - NotificationUtils.NOTIFICATION_CHANNEL_CALLS, getResources().getString(R - .string.nc_notification_channel_calls), getResources().getString - (R.string.nc_notification_channel_calls_description), true, - NotificationManager.IMPORTANCE_HIGH, soundUri); - - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_CALLS); - } else { - NotificationUtils.createNotificationChannel(notificationManager, - NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES, getResources().getString(R - .string.nc_notification_channel_messages), getResources().getString - (R.string.nc_notification_channel_messages_description), true, - NotificationManager.IMPORTANCE_DEFAULT, soundUri); - - notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES); - } - - notificationBuilder.setGroup(Long.toString(crc32.getValue())); - } - - notificationBuilder.setContentIntent(pendingIntent); - - String stringForCrc = decryptedPushMessage.getSubject() + " " + signatureVerification - .getUserEntity().getDisplayName() + " " + signatureVerification.getUserEntity - ().getBaseUrl(); - - crc32 = new CRC32(); - crc32.update(stringForCrc.getBytes()); - - if (notificationManager != null) { - notificationManager.notify((int) crc32.getValue(), notificationBuilder.build()); - } - } - - } - } catch (NoSuchAlgorithmException e1) { - Log.d(TAG, "No proper algorithm to decrypt the message " + e1.getLocalizedMessage()); - } catch (NoSuchPaddingException e1) { - Log.d(TAG, "No proper padding to decrypt the message " + e1.getLocalizedMessage()); - } catch (InvalidKeyException e1) { - Log.d(TAG, "Invalid private key " + e1.getLocalizedMessage()); - } - } catch (Exception exception) { - Log.d(TAG, "Something went very wrong" + exception.getLocalizedMessage()); - } - } else { - Log.d(TAG, "The data we received was empty"); - + PersistableBundleCompat persistableBundleCompat = new PersistableBundleCompat(); + persistableBundleCompat.putString(BundleKeys.KEY_NOTIFICATION_SUBJECT, remoteMessage.getData().get + ("subject")); + persistableBundleCompat.putString(BundleKeys.KEY_NOTIFICATION_SIGNATURE, remoteMessage.getData().get + ("signature")); + new JobRequest.Builder(NotificationJob.TAG) + .addExtras(persistableBundleCompat) + .setUpdateCurrent(false) + .startNow() + .build() + .schedule(); } } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java index 328a7b5e7..4a44cef65 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java +++ b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java @@ -28,7 +28,7 @@ public class BundleKeys { public static final String KEY_ORIGINAL_PROTOCOL = "KEY_ORIGINAL_PROTOCOL"; public static final String KEY_ROOM = "KEY_ROOM"; public static final String KEY_OPERATION_CODE = "KEY_OPERATION_CODE"; - public static final String KEY_IS_SHARE = "KEY_IS_SHARE"; + public static final String KEY_MENU_TYPE = "KEY_MENU_TYPE"; public static final String KEY_SHARE_INTENT = "KEY_SHARE_INTENT"; public static final String KEY_APP_ITEM_PACKAGE_NAME = "KEY_APP_ITEM_PACKAGE_NAME"; public static final String KEY_APP_ITEM_NAME = "KEY_APP_ITEM_NAME"; @@ -38,4 +38,8 @@ public class BundleKeys { public static final String KEY_USER_ENTITY = "KEY_USER_ENTITY"; public static final String KEY_NEW_CONVERSATION = "KEY_NEW_CONVERSATION"; public static final String KEY_IS_PUBLIC_CALL = "KEY_IS_PUBLIC_CALL"; + public static final String KEY_CALL_URL = "KEY_CALL_URL"; + public static final String KEY_MODIFIED_BASE_URL = "KEY_MODIFIED_BASE_URL"; + public static final String KEY_NOTIFICATION_SUBJECT = "KEY_NOTIFICATION_SUBJECT"; + public static final String KEY_NOTIFICATION_SIGNATURE = "KEY_NOTIFICATION_SIGNATURE"; } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f2fb6f43b..889796e5e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -28,7 +28,6 @@ Never joined Search - Create a new conversation Check out the certificate Do you trust the until now unknown SSL certificate, issued by %1$s for %2$s, valid from %3$s to %4$s? @@ -61,6 +60,7 @@ No proxy Username Password + Conversation link New password Wrong password About @@ -83,6 +83,9 @@ Make call public Make call private Delete call + Start a new conversation + Join via link + Join via web Select contacts @@ -115,11 +118,14 @@ Sorry, something went wrong! + Target server does not support joining public rooms via mobile phones. + You may attempt to join the call via web browser. OK, all done! OK Call name Proceed The name you entered is the same as the existing one + Conversation link is not valid Hello,\n\nI would like you to join a call with me.\n\nYou can join this call via %1$s/index.php/call/%2$s \n\nTalk soon,\n %1$s