From 4b846bcca80859afbf9cd6f10a33b41c0d115be6 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 24 Apr 2019 11:18:47 +0200 Subject: [PATCH] Started to split LinphoneActivity in multiple activities Added new activities that will replace LinphoneActivity Added About & Dialer activities Fixed back key press Transformed Recordings fragment into activity Started Settings activity Small improvement for Recordings Finished dialer Permission shenanigans Added back History Small history improvements Fixed issue with rotation in History Started contacts More changes & fixes for Chat Improved performances when switching between activities Prevent keyboard from opening automatically on some views Added back workaround for infinite loop if screen off Fixes & improvements Some cleanup but a lot of work still left Switching back to classic fragment fixed issues Lots of fixes & improvements over History & Contacts More work on chat Small refactoring of license header Settings & Chat fixes/improvements More TODO FIXES removal Tablet fixes Fixes & improvements Fixed back button on tablets Got rid of LinphoneActivity Fixed TODO FIXME related to permissions Started chat room group info Lot of fixes & improvements over Chat Fixed sharing feature if LinphoneService isn't running Lifecycle improvements Sharing from outside app finished Fixed quit button Fixed display of missed chat/calls Clean old code for chat rooms unread message count Improved unread message count on tablets This isn't useful anymore Fixed last issue with unread count not updating in chat rooms list using new callbacks Fixed latest TODO FIXME due to CallAcitvity singleton removal Updated remaining TODOs Fixed issue with outgoing call not going to call activity once answered Fixed back key press go home feature Removed dead code Code cleanup thanks to Android Studio inspector Added back device power saver dialog + update registration state changed in menu More auto rework by Android Studio + added back checkForUpdate & isAccountWithAlias method calls More improvements, most of them on layout files Fixed secured group chat rooms creation Improved launch screen by using logo on gray background instead of default white screen Added workaround for faster display of splashscreen Removed noHistory flag on Settings, will be weird when going back from Android native settings Fixed display of call logs list in history details in landscape on smartphone depending on screen size Reorganized activities + fixed dark theme switch Manager & Service cleanup Simplified notification process More manager simplifications Moved audio manager related code from LinphoneManager to dedicated class Core accessor cleanup Exclude XmlRpc & InApp related code from standard APK + moved call related methods from LinphoneManager to CallManager Fixed click on chat bottom bar button doing nothing after going into chatroom through notification or shortcut Fixed chat message fragment update if presence is received while view has already been displayed Improved second to last commit Fixed navigation issue in chat More code improvements --- app/build.gradle | 3 + app/src/main/AndroidManifest.xml | 134 +- .../java/org/linphone/LinphoneActivity.java | 2030 ----------------- .../java/org/linphone/LinphoneManager.java | 2021 +++++----------- .../java/org/linphone/LinphoneService.java | 512 ++--- .../AboutActivity.java} | 157 +- .../linphone/activities/DialerActivity.java | 282 +++ .../LinphoneGenericActivity.java | 19 +- .../LinphoneLauncherActivity.java | 58 +- .../org/linphone/activities/MainActivity.java | 687 ++++++ .../activities/SplashScreenActivity.java | 72 + .../ThemableActivity.java | 22 +- .../AccountConnectionAssistantActivity.java | 5 +- .../linphone/assistant/AssistantActivity.java | 57 +- .../linphone/assistant/CountryAdapter.java | 6 +- .../org/linphone/assistant/CountryPicker.java | 29 +- ...CancellerCalibrationAssistantActivity.java | 20 +- ...ailAccountValidationAssistantActivity.java | 6 +- .../GenericConnectionAssistantActivity.java | 4 +- .../assistant/MenuAssistantActivity.java | 26 +- .../OpenH264DownloadAssistantActivity.java | 7 +- ...PhoneAccountCreationAssistantActivity.java | 5 +- .../PhoneAccountLinkingAssistantActivity.java | 10 +- ...oneAccountValidationAssistantActivity.java | 14 +- .../QrCodeConfigurationAssistantActivity.java | 26 +- .../RemoteConfigurationAssistantActivity.java | 32 +- .../org/linphone/call/BandwidthManager.java | 12 +- .../java/org/linphone/call/CallActivity.java | 351 +-- .../linphone/call/CallIncomingActivity.java | 88 +- .../java/org/linphone/call/CallManager.java | 238 +- .../linphone/call/CallOutgoingActivity.java | 75 +- .../org/linphone/call/CallVideoFragment.java | 50 +- .../java/org/linphone/chat/ChatActivity.java | 293 +++ .../chat/ChatMessageOldViewHolder.java | 107 - .../linphone/chat/ChatMessageViewHolder.java | 22 +- .../ChatMessageViewHolderClickListener.java | 2 +- .../linphone/chat/ChatMessagesAdapter.java | 2 +- .../linphone/chat/ChatMessagesFragment.java | 282 +-- .../chat/ChatMessagesGenericAdapter.java | 2 +- .../linphone/chat/ChatMessagesOldAdapter.java | 662 ------ .../chat/ChatRoomCreationFragment.java | 545 +++-- .../org/linphone/chat/ChatRoomViewHolder.java | 30 +- .../org/linphone/chat/ChatRoomsAdapter.java | 11 +- .../org/linphone/chat/ChatRoomsFragment.java | 211 +- .../org/linphone/chat/ChatScrollListener.java | 4 +- .../linphone/chat/DeviceChildViewHolder.java | 2 +- .../linphone/chat/DeviceGroupViewHolder.java | 2 +- .../org/linphone/chat/DevicesAdapter.java | 2 +- .../org/linphone/chat/DevicesFragment.java | 48 +- .../org/linphone/chat/GroupInfoAdapter.java | 10 +- .../org/linphone/chat/GroupInfoFragment.java | 534 ++--- .../linphone/chat/GroupInfoViewHolder.java | 2 +- .../java/org/linphone/chat/ImdnFragment.java | 59 +- .../org/linphone/chat/ImdnOldFragment.java | 357 --- .../compatibility/ApiTwentyFourPlus.java | 54 +- .../compatibility/ApiTwentyOnePlus.java | 1 - .../compatibility/ApiTwentyThreePlus.java | 4 - .../linphone/compatibility/Compatibility.java | 9 - .../CompatibilityScaleGestureDetector.java | 4 +- .../org/linphone/contacts/AndroidContact.java | 66 +- .../contacts/AsyncContactsLoader.java | 35 +- .../org/linphone/contacts/ContactAddress.java | 21 +- .../contacts/ContactDetailsFragment.java | 350 +-- .../contacts/ContactEditorFragment.java | 212 +- .../linphone/contacts/ContactsActivity.java | 180 ++ .../linphone/contacts/ContactsAdapter.java | 5 +- .../linphone/contacts/ContactsFragment.java | 228 +- .../linphone/contacts/ContactsManager.java | 92 +- .../linphone/contacts/LinphoneContact.java | 40 +- .../contacts/LinphoneNumberOrAddress.java | 2 +- .../contacts/SearchContactsAdapter.java | 19 +- .../linphone/fragments/DialerFragment.java | 235 -- .../fragments/FragmentsAvailable.java | 81 - .../linphone/fragments/StatusFragment.java | 118 +- .../org/linphone/history/HistoryActivity.java | 115 + .../org/linphone/history/HistoryAdapter.java | 24 +- .../history/HistoryDetailFragment.java | 307 ++- .../org/linphone/history/HistoryFragment.java | 244 +- .../linphone/history/HistoryLogAdapter.java | 9 +- .../menu/SideMenuAccountsListAdapter.java | 126 + .../org/linphone/menu/SideMenuAdapter.java | 75 + .../org/linphone/menu/SideMenuFragment.java | 257 +++ .../java/org/linphone/menu/SideMenuItem.java | 34 + .../NotificationBroadcastReceiver.java | 11 +- .../notifications/NotificationsManager.java | 196 +- .../purchase/InAppPurchaseActivity.java | 9 +- .../purchase/InAppPurchaseFragment.java | 16 +- .../purchase/InAppPurchaseHelper.java | 52 +- .../purchase/InAppPurchaseListFragment.java | 3 +- .../purchase/InAppPurchaseListenerBase.java | 35 +- .../receivers/AccountEnableReceiver.java | 7 +- .../linphone/receivers/BluetoothManager.java | 25 +- .../org/linphone/receivers/BootReceiver.java | 13 +- .../org/linphone/receivers/HookReceiver.java | 19 +- .../receivers/PhoneStateChangedReceiver.java | 9 +- .../org/linphone/recording/Recording.java | 2 +- ...sFragment.java => RecordingsActivity.java} | 247 +- .../settings/AccountSettingsFragment.java | 59 +- .../settings/AdvancedSettingsFragment.java | 31 +- .../settings/AudioSettingsFragment.java | 59 +- .../settings/CallSettingsFragment.java | 39 +- .../settings/ChatSettingsFragment.java | 23 +- .../settings/LinphonePreferences.java | 60 +- .../settings/MenuSettingsFragment.java | 223 ++ .../settings/NetworkSettingsFragment.java | 29 +- .../linphone/settings/SettingsActivity.java | 155 ++ .../linphone/settings/SettingsFragment.java | 191 +- .../settings/TunnelSettingsFragment.java | 21 +- .../settings/VideoSettingsFragment.java | 28 +- .../settings/widget/BasicSetting.java | 15 +- .../settings/widget/CheckBoxSetting.java | 4 +- .../linphone/settings/widget/LedSetting.java | 2 +- .../linphone/settings/widget/ListSetting.java | 6 +- .../settings/widget/SettingListener.java | 2 +- .../settings/widget/SwitchSetting.java | 4 +- .../linphone/settings/widget/TextSetting.java | 2 +- .../org/linphone/utils/ActivityMonitor.java | 140 ++ .../linphone/utils/AndroidAudioManager.java | 377 +++ .../java/org/linphone/utils/FileUtils.java | 58 +- .../java/org/linphone/utils/IntentUtils.java | 101 - .../org/linphone/utils/LinphoneUtils.java | 103 +- .../org/linphone/utils/SelectableAdapter.java | 2 +- .../org/linphone/utils/SelectableHelper.java | 14 +- .../java/org/linphone/views/AddressAware.java | 2 +- .../java/org/linphone/views/AddressText.java | 20 +- .../java/org/linphone/views/AddressType.java | 26 + .../java/org/linphone/views/AsyncBitmap.java | 2 +- .../org/linphone/views/BitmapWorkerTask.java | 17 +- .../java/org/linphone/views/CallButton.java | 16 +- .../views/CallIncomingDeclineButton.java | 7 +- .../org/linphone/views/ContactAvatar.java | 4 +- .../org/linphone/views/ContactSelectView.java | 2 +- .../main/java/org/linphone/views/Digit.java | 34 +- .../org/linphone/views/LedPreference.java | 51 - .../views/LinphoneGL2JNIViewOverlay.java | 12 +- .../views/LinphoneTextureViewOverlay.java | 25 +- .../org/linphone/xmlrpc/XmlRpcHelper.java | 2 +- .../linphone/xmlrpc/XmlRpcListenerBase.java | 75 +- app/src/main/res/drawable/launch_screen.xml | 11 + app/src/main/res/layout-land/about.xml | 264 ++- .../assistant_email_account_creation.xml | 1 - .../assistant_generic_connection.xml | 1 - .../main/res/layout-land/assistant_menu.xml | 1 - app/src/main/res/layout-land/call.xml | 3 +- app/src/main/res/layout-land/dialer.xml | 39 +- .../main/res/layout-land/history_detail.xml | 10 +- .../main/res/layout-land/launch_screen.xml | 51 - app/src/main/res/layout-land/main.xml | 78 +- .../main/res/layout-sw533dp-land/dialer.xml | 38 +- app/src/main/res/layout-sw533dp-land/main.xml | 109 +- app/src/main/res/layout-sw533dp/dialer.xml | 38 +- .../res/layout-sw533dp/history_detail.xml | 3 +- app/src/main/res/layout-sw533dp/main.xml | 112 +- app/src/main/res/layout/about.xml | 234 +- .../layout/assistant_account_connection.xml | 1 - .../assistant_echo_canceller_calibration.xml | 1 - .../assistant_email_account_creation.xml | 1 - .../assistant_email_account_validation.xml | 1 - .../layout/assistant_generic_connection.xml | 1 - app/src/main/res/layout/assistant_menu.xml | 1 - .../assistant_openh264_codec_download.xml | 1 - .../assistant_phone_account_creation.xml | 1 - .../assistant_phone_account_linking.xml | 1 - .../assistant_phone_account_validation.xml | 1 - ...assistant_qr_code_remote_configuration.xml | 1 - .../layout/assistant_remote_configuration.xml | 1 - app/src/main/res/layout/audio.xml | 1 - app/src/main/res/layout/call.xml | 3 +- app/src/main/res/layout/call_incoming.xml | 85 +- app/src/main/res/layout/call_outgoing.xml | 3 +- app/src/main/res/layout/chat.xml | 3 +- app/src/main/res/layout/chat_bubble_old.xml | 210 -- app/src/main/res/layout/chat_device_cell.xml | 59 +- .../res/layout/chat_device_cell_as_group.xml | 58 +- app/src/main/res/layout/chat_device_group.xml | 126 +- app/src/main/res/layout/chat_devices.xml | 64 +- app/src/main/res/layout/chat_imdn.xml | 328 ++- app/src/main/res/layout/chat_imdn_cell.xml | 1 - app/src/main/res/layout/chat_imdn_old.xml | 191 -- app/src/main/res/layout/chat_infos.xml | 3 +- app/src/main/res/layout/chat_infos_cell.xml | 233 +- .../main/res/layout/conf_call_control_row.xml | 1 - app/src/main/res/layout/conference_header.xml | 1 - app/src/main/res/layout/contact.xml | 3 +- app/src/main/res/layout/contact_cell.xml | 1 - app/src/main/res/layout/contact_edit.xml | 1 - app/src/main/res/layout/contacts_list.xml | 2 +- app/src/main/res/layout/dialer.xml | 39 +- app/src/main/res/layout/empty_fragment.xml | 1 - app/src/main/res/layout/history.xml | 3 +- app/src/main/res/layout/history_cell.xml | 1 - app/src/main/res/layout/history_detail.xml | 5 +- .../main/res/layout/history_detail_cell.xml | 27 +- app/src/main/res/layout/in_app.xml | 1 - app/src/main/res/layout/in_app_store.xml | 1 - app/src/main/res/layout/launch_screen.xml | 1 - .../res/layout/launch_screen_full_image.xml | 26 - app/src/main/res/layout/main.xml | 80 +- app/src/main/res/layout/recording_cell.xml | 1 - app/src/main/res/layout/recordings_list.xml | 8 +- .../main/res/layout/remote_provisioning.xml | 1 - .../main/res/layout/search_contact_cell.xml | 3 +- app/src/main/res/layout/settings.xml | 3 +- app/src/main/res/layout/settings_account.xml | 3 +- app/src/main/res/layout/settings_advanced.xml | 3 +- app/src/main/res/layout/settings_audio.xml | 3 +- app/src/main/res/layout/settings_call.xml | 3 +- app/src/main/res/layout/settings_chat.xml | 3 +- app/src/main/res/layout/settings_network.xml | 3 +- app/src/main/res/layout/settings_tunnel.xml | 3 +- app/src/main/res/layout/settings_video.xml | 3 +- app/src/main/res/layout/side_menu.xml | 64 + .../res/layout/side_menu_account_cell.xml | 1 - app/src/main/res/layout/status.xml | 141 +- .../res/values/non_localizable_custom.xml | 3 +- app/src/main/res/values/styles.xml | 5 + 216 files changed, 7888 insertions(+), 10814 deletions(-) delete mode 100644 app/src/main/java/org/linphone/LinphoneActivity.java rename app/src/main/java/org/linphone/{fragments/AboutFragment.java => activities/AboutActivity.java} (57%) create mode 100644 app/src/main/java/org/linphone/activities/DialerActivity.java rename app/src/main/java/org/linphone/{utils => activities}/LinphoneGenericActivity.java (69%) rename app/src/main/java/org/linphone/{ => activities}/LinphoneLauncherActivity.java (66%) create mode 100644 app/src/main/java/org/linphone/activities/MainActivity.java create mode 100644 app/src/main/java/org/linphone/activities/SplashScreenActivity.java rename app/src/main/java/org/linphone/{utils => activities}/ThemableActivity.java (70%) create mode 100644 app/src/main/java/org/linphone/chat/ChatActivity.java delete mode 100644 app/src/main/java/org/linphone/chat/ChatMessageOldViewHolder.java delete mode 100644 app/src/main/java/org/linphone/chat/ChatMessagesOldAdapter.java delete mode 100644 app/src/main/java/org/linphone/chat/ImdnOldFragment.java create mode 100644 app/src/main/java/org/linphone/contacts/ContactsActivity.java delete mode 100644 app/src/main/java/org/linphone/fragments/DialerFragment.java delete mode 100644 app/src/main/java/org/linphone/fragments/FragmentsAvailable.java create mode 100644 app/src/main/java/org/linphone/history/HistoryActivity.java create mode 100644 app/src/main/java/org/linphone/menu/SideMenuAccountsListAdapter.java create mode 100644 app/src/main/java/org/linphone/menu/SideMenuAdapter.java create mode 100644 app/src/main/java/org/linphone/menu/SideMenuFragment.java create mode 100644 app/src/main/java/org/linphone/menu/SideMenuItem.java rename app/src/main/java/org/linphone/recording/{RecordingsFragment.java => RecordingsActivity.java} (62%) create mode 100644 app/src/main/java/org/linphone/settings/MenuSettingsFragment.java create mode 100644 app/src/main/java/org/linphone/settings/SettingsActivity.java create mode 100644 app/src/main/java/org/linphone/utils/ActivityMonitor.java create mode 100644 app/src/main/java/org/linphone/utils/AndroidAudioManager.java delete mode 100644 app/src/main/java/org/linphone/utils/IntentUtils.java create mode 100644 app/src/main/java/org/linphone/views/AddressType.java delete mode 100644 app/src/main/java/org/linphone/views/LedPreference.java create mode 100644 app/src/main/res/drawable/launch_screen.xml delete mode 100644 app/src/main/res/layout-land/launch_screen.xml delete mode 100644 app/src/main/res/layout/chat_bubble_old.xml delete mode 100644 app/src/main/res/layout/chat_imdn_old.xml delete mode 100644 app/src/main/res/layout/launch_screen_full_image.xml create mode 100644 app/src/main/res/layout/side_menu.xml diff --git a/app/build.gradle b/app/build.gradle index f5f826cf8..5044efd96 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,6 +30,9 @@ if (!firebaseEnabled()) { excludeFiles.add('**/Firebase*') println '[Push Notification] Firebase disabled' } +// Remove or comment if you want to use those +excludeFiles.add('**/XmlRpc*') +excludeFiles.add('**/InAppPurchase*') def excludePackage = [] diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9361ef5cc..e388541ca 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -62,13 +62,9 @@ android:roundIcon="@mipmap/ic_launcher_round"> + android:theme="@style/LinphoneLauncherStyle"> @@ -77,12 +73,21 @@ + + + + + + + - - - @@ -101,11 +106,32 @@ - - + - + + + + + + + + + + + + @@ -126,12 +152,28 @@ + + + - + + + + + + + + - - - + - - - + - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - @@ -274,6 +271,7 @@ android:name="android.provider.CONTACTS_STRUCTURE" android:resource="@xml/contacts" /> + @@ -287,6 +285,7 @@ + @@ -295,6 +294,7 @@ + @@ -331,8 +331,6 @@ android:resource="@xml/provider_paths" /> - - mSideMenuItems; - private boolean mCallTransfer = false; - private boolean mIsOnBackground = false; - private int mAlwaysChangingPhoneAngle = -1; - - public static boolean isInstanciated() { - return sInstance != null; - } - - public static LinphoneActivity instance() { - if (sInstance != null) return sInstance; - throw new RuntimeException("LinphoneActivity not instantiated yet"); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - // This must be done before calling super.onCreate(). - super.onCreate(savedInstanceState); - - LinphoneService.instance().removeForegroundServiceNotificationIfPossible(); - - if (getResources().getBoolean(R.bool.use_linphone_tag)) { - if (getPackageManager() - .checkPermission( - Manifest.permission.WRITE_SYNC_SETTINGS, getPackageName()) - != PackageManager.PERMISSION_GRANTED) { - checkSyncPermission(); - } - } - - setContentView(R.layout.main); - sInstance = this; - mPendingFragmentTransaction = FragmentsAvailable.UNKNOW; - - initButtons(); - initSideMenu(); - - mCurrentFragment = FragmentsAvailable.EMPTY; - if (savedInstanceState == null) { - changeCurrentFragment(FragmentsAvailable.DIALER, getIntent().getExtras()); - } else { - mCurrentFragment = - (FragmentsAvailable) savedInstanceState.getSerializable("mCurrentFragment"); - } - - mListener = - new CoreListenerStub() { - @Override - public void onMessageReceived(Core lc, ChatRoom cr, ChatMessage message) { - displayMissedChats(LinphoneManager.getInstance().getUnreadMessageCount()); - } - - @Override - public void onRegistrationStateChanged( - Core lc, ProxyConfig proxy, RegistrationState state, String smessage) { - AuthInfo authInfo = - lc.findAuthInfo( - proxy.getRealm(), - proxy.getIdentityAddress().getUsername(), - proxy.getDomain()); - - refreshAccounts(); - - if (getResources().getBoolean(R.bool.use_phone_number_validation) - && authInfo != null - && authInfo.getDomain() - .equals(getString(R.string.default_domain))) { - if (state.equals(RegistrationState.Ok)) { - LinphoneManager.getInstance().isAccountWithAlias(); - } - } - - if (state.equals(RegistrationState.Failed) && mNewProxyConfig) { - mNewProxyConfig = false; - if (proxy.getError() == Reason.Unauthorized) { - displayCustomToast( - getString(R.string.error_unauthorized), Toast.LENGTH_LONG); - } - if (proxy.getError() == Reason.IOError) { - displayCustomToast( - getString(R.string.error_io_error), Toast.LENGTH_LONG); - } - } - - if (state == RegistrationState.Ok) { - // For push notifications to work on Huawei device, - // app must be in "protected mode" in battery settings... - // https://stackoverflow.com/questions/31638986/protected-apps-setting-on-huawei-phones-and-how-to-handle-it - DeviceUtils - .displayDialogIfDeviceHasPowerManagerThatCouldPreventPushNotifications( - LinphoneActivity.this); - } - } - - @Override - public void onCallStateChanged( - Core lc, Call call, Call.State state, String message) { - if (state == State.IncomingReceived) { - // This case will be handled by the service listener - } else if (state == State.OutgoingInit || state == State.OutgoingProgress) { - startActivity( - new Intent( - LinphoneActivity.instance(), - CallOutgoingActivity.class)); - } else if (state == State.End - || state == State.Error - || state == State.Released) { - resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); - } - - int missedCalls = LinphoneManager.getLc().getMissedCallsCount(); - displayMissedCalls(missedCalls); - } - }; - - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - int missedCalls = lc.getMissedCallsCount(); - displayMissedCalls(missedCalls); - } - - int rotation = getWindowManager().getDefaultDisplay().getRotation(); - switch (rotation) { - case Surface.ROTATION_0: - rotation = 0; - break; - case Surface.ROTATION_90: - rotation = 90; - break; - case Surface.ROTATION_180: - rotation = 180; - break; - case Surface.ROTATION_270: - rotation = 270; - break; - } - - mAlwaysChangingPhoneAngle = rotation; - if (LinphoneManager.isInstanciated()) { - LinphoneManager.getLc().setDeviceRotation(rotation); - onNewIntent(getIntent()); - } - } - - @Override - protected void onStart() { - super.onStart(); - - ArrayList permissionsToAskFor = new ArrayList<>(); - String[] permissionsToHave = { - // This one is to allow floating notifications - Manifest.permission.SYSTEM_ALERT_WINDOW, - // Required starting Android 9 to be able to start a foreground service - "android.permission.FOREGROUND_SERVICE", - Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE, - Manifest.permission.WRITE_CONTACTS, - Manifest.permission.READ_CONTACTS - }; - - for (String permissionToHave : permissionsToHave) { - if (!checkPermission(permissionToHave)) { - permissionsToAskFor.add(permissionToHave); - } - } - - if (permissionsToAskFor.size() > 0) { - for (String permission : permissionsToAskFor) { - Log.i("[Permission] Asking for " + permission + " permission"); - } - String[] permissions = new String[permissionsToAskFor.size()]; - permissions = permissionsToAskFor.toArray(permissions); - - KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); - boolean locked = km.inKeyguardRestrictedInputMode(); - if (!locked) { - // This is to workaround an infinite loop of pause/start in LinphoneActivity issue - // if incoming call ends while screen if off and locked - ActivityCompat.requestPermissions( - this, permissions, PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE); - } - } else { - if (getResources().getBoolean(R.bool.check_for_update_when_app_starts)) { - checkForUpdate(); - } - } - - if (checkPermission(Manifest.permission.READ_CONTACTS)) { - ContactsManager.getInstance().enableContactsAccess(); - } - ContactsManager.getInstance().initializeContactManager(this); - - if (DeviceUtils.isAppUserRestricted(this)) { - Log.w( - "[Linphone Activity] Device has been restricted by user (Android 9+), push notifications won't work !"); - } - - int bucket = DeviceUtils.getAppStandbyBucket(this); - if (bucket > 0) { - Log.w( - "[Linphone Activity] Device is in bucket " - + Compatibility.getAppStandbyBucketNameFromValue(bucket)); - } - - if (!PushNotificationUtils.isAvailable(this)) { - Log.w("[Linphone Activity] Push notifications won't work !"); - } - - IntentUtils.handleIntent(this, getIntent()); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - outState.putSerializable("mCurrentFragment", mCurrentFragment); - super.onSaveInstanceState(outState); - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - } - - @Override - protected void onPause() { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.removeListener(mListener); - } - mIsOnBackground = true; - - super.onPause(); - } - - @Override - protected void onResume() { - super.onResume(); - if (!LinphoneService.isReady()) { - startService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class)); - } - - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.addListener(mListener); - } - - if (isTablet()) { - // Prevent fragmentContainer2 to be visible when rotating the device - LinearLayout ll = findViewById(R.id.fragmentContainer2); - if (mCurrentFragment == FragmentsAvailable.DIALER - || mCurrentFragment == FragmentsAvailable.ABOUT - || mCurrentFragment == FragmentsAvailable.SETTINGS - || mCurrentFragment == FragmentsAvailable.SETTINGS_SUBLEVEL - || mCurrentFragment == FragmentsAvailable.ACCOUNT_SETTINGS) { - ll.setVisibility(View.GONE); - } - } - - refreshAccounts(); - - if (getResources().getBoolean(R.bool.enable_in_app_purchase)) { - isTrialAccount(); - } - - displayMissedChats(LinphoneManager.getInstance().getUnreadMessageCount()); - displayMissedCalls(LinphoneManager.getLc().getMissedCallsCount()); - - if (!getIntent().getBooleanExtra("DoNotGoToCallActivity", false)) { - if (LinphoneManager.getLc().getCalls().length > 0) { - Call call = LinphoneManager.getLc().getCalls()[0]; - Call.State onCallStateChanged = call.getState(); - - if (onCallStateChanged == State.IncomingReceived - || onCallStateChanged == State.IncomingEarlyMedia) { - startActivity(new Intent(this, CallIncomingActivity.class)); - } else if (onCallStateChanged == State.OutgoingInit - || onCallStateChanged == State.OutgoingProgress - || onCallStateChanged == State.OutgoingRinging) { - startActivity(new Intent(this, CallOutgoingActivity.class)); - } else { - startIncallActivity(); - } - } - } - } - - @Override - protected void onPostResume() { - super.onPostResume(); - if (mPendingFragmentTransaction != FragmentsAvailable.UNKNOW) { - changeCurrentFragment(mPendingFragmentTransaction, null); - selectMenu(mPendingFragmentTransaction); - mPendingFragmentTransaction = FragmentsAvailable.UNKNOW; - } - } - - @Override - protected void onDestroy() { - if (mOrientationHelper != null) { - mOrientationHelper.disable(); - mOrientationHelper = null; - } - - sInstance = null; - super.onDestroy(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (getIntent() != null && getIntent().getExtras() != null) { - mNewProxyConfig = getIntent().getExtras().getBoolean("isNewProxyConfig"); - } - - if (requestCode == ANDROID_APP_SETTINGS_ACTIVITY) { - LinphoneActivity.instance().goToDialerFragment(); - } else if (resultCode == Activity.RESULT_FIRST_USER && requestCode == SETTINGS_ACTIVITY) { - if (data.getExtras().getBoolean("Exit", false)) { - quit(); - } else { - mPendingFragmentTransaction = - (FragmentsAvailable) data.getExtras().getSerializable("FragmentToDisplay"); - } - } else if (resultCode == Activity.RESULT_FIRST_USER && requestCode == CALL_ACTIVITY) { - getIntent().putExtra("PreviousActivity", CALL_ACTIVITY); - mCallTransfer = data != null && data.getBooleanExtra("Transfer", false); - if (LinphoneManager.getLc().getCallsNb() > 0) { - initInCallMenuLayout(); - } else { - resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); - } - } else if (requestCode == PERMISSIONS_REQUEST_OVERLAY) { - if (Compatibility.canDrawOverlays(this)) { - LinphonePreferences.instance().enableOverlay(true); - } - } else { - super.onActivityResult(requestCode, resultCode, data); - } - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - /*if (getCurrentFragment() == FragmentsAvailable.SETTINGS) { - if (mFragment instanceof SettingsFragment) { - ((SettingsFragment) mFragment).closePreferenceScreen(); - } - }*/ - - Bundle extras = intent.getExtras(); - mCallTransfer = false; - if (extras != null) { - if (extras.getBoolean("GoToChat", false)) { - String localSipUri = extras.getString("LocalSipUri"); - String remoteSipUri = extras.getString("ChatContactSipUri"); - Log.i( - "[Linphone Activity] Intent asked to go to chat, local URI " - + localSipUri - + ", remote URI " - + remoteSipUri); - intent.putExtra("DoNotGoToCallActivity", true); - if (remoteSipUri == null) { - goToChatList(); - } else { - goToChat(localSipUri, remoteSipUri, extras); - } - } else if (extras.getBoolean("GoToHistory", false)) { - Log.i("[Linphone Activity] Intent asked to go to call history"); - intent.putExtra("DoNotGoToCallActivity", true); - changeCurrentFragment(FragmentsAvailable.HISTORY_LIST, null); - } else if (extras.getBoolean("GoToInapp", false)) { - Log.i("[Linphone Activity] Intent asked to go to inapp"); - intent.putExtra("DoNotGoToCallActivity", true); - displayInapp(); - } else if (extras.getBoolean("Notification", false)) { - if (LinphoneManager.getLc().getCallsNb() > 0) { - startIncallActivity(); - } - } else if (extras.getBoolean("StartCall", false)) { - addressWaitingToBeCalled = extras.getString("NumberToCall"); - goToDialerFragment(); - } else if (extras.getBoolean("Transfer", false)) { - intent.putExtra("DoNotGoToCallActivity", true); - mCallTransfer = true; - if (LinphoneManager.getLc().getCallsNb() > 0) { - initInCallMenuLayout(); - } else { - resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); - } - } else if (extras.getBoolean("AddCall", false)) { - intent.putExtra("DoNotGoToCallActivity", true); - } else if (intent.getStringExtra("msgShared") != null) { - String message = intent.getStringExtra("msgShared"); - Log.i( - "[Linphone Activity] Intent asked to go to chat list to share message " - + message); - extras.putString("messageDraft", message); - changeCurrentFragment(FragmentsAvailable.CHAT_LIST, extras); - intent.removeExtra("msgShared"); - } else if (intent.getStringExtra("fileShared") != null - && !intent.getStringExtra("fileShared").equals("")) { - String file = intent.getStringExtra("fileShared"); - Log.i( - "[Linphone Activity] Intent asked to go to chat list to share file(s) " - + file); - extras.putString("fileSharedUri", file); - changeCurrentFragment(FragmentsAvailable.CHAT_LIST, extras); - intent.removeExtra("fileShared"); - } else { - DialerFragment dialerFragment = DialerFragment.instance(); - if (dialerFragment != null) { - if (extras.containsKey("SipUriOrNumber")) { - if (getResources() - .getBoolean( - R.bool.automatically_start_intercepted_outgoing_gsm_call)) { - dialerFragment.newOutgoingCall(extras.getString("SipUriOrNumber")); - } else { - dialerFragment.displayTextInAddressBar( - extras.getString("SipUriOrNumber")); - } - } - } else { - if (extras.containsKey("SipUriOrNumber")) { - addressWaitingToBeCalled = extras.getString("SipUriOrNumber"); - goToDialerFragment(); - } - } - } - } - setIntent(intent); - } - - @Override - public void onRequestPermissionsResult( - int requestCode, String[] permissions, int[] grantResults) { - - // If permission was asked we wait here for the results so dialogs won't conflict - if (getResources().getBoolean(R.bool.check_for_update_when_app_starts)) { - checkForUpdate(); - } - - if (permissions.length <= 0) return; - - int readContactsI = -1; - for (int i = 0; i < permissions.length; i++) { - Log.i( - "[Permission] " - + permissions[i] - + " is " - + (grantResults[i] == PackageManager.PERMISSION_GRANTED - ? "granted" - : "denied")); - if (permissions[i].compareTo(Manifest.permission.READ_CONTACTS) == 0 - || permissions[i].compareTo(Manifest.permission.WRITE_CONTACTS) == 0) - readContactsI = i; - } - - if (readContactsI >= 0 - && grantResults[readContactsI] == PackageManager.PERMISSION_GRANTED) { - ContactsManager.getInstance().enableContactsAccess(); - } - switch (requestCode) { - case PERMISSIONS_REQUEST_SYNC: - ContactsManager.getInstance().initializeContactManager(this); - break; - case PERMISSIONS_RECORD_AUDIO_ECHO_CANCELLER: - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - ((AudioSettingsFragment) mFragment).startEchoCancellerCalibration(); - } - break; - case PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE: - if (permissions[0].compareTo(Manifest.permission.READ_EXTERNAL_STORAGE) != 0) break; - boolean enableRingtone = (grantResults[0] == PackageManager.PERMISSION_GRANTED); - LinphonePreferences.instance().enableDeviceRingtone(enableRingtone); - LinphoneManager.getInstance().enableDeviceRingtone(enableRingtone); - break; - case PERMISSIONS_RECORD_AUDIO_ECHO_TESTER: - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) - ((AudioSettingsFragment) mFragment).startEchoTester(); - break; - } - } - - private void checkForUpdate() { - String url = LinphonePreferences.instance().getCheckReleaseUrl(); - if (url != null && !url.isEmpty()) { - int lastTimestamp = LinphonePreferences.instance().getLastCheckReleaseTimestamp(); - int currentTimeStamp = (int) System.currentTimeMillis(); - int interval = getResources().getInteger(R.integer.time_between_update_check); // 24h - if (lastTimestamp == 0 || currentTimeStamp - lastTimestamp >= interval) { - LinphoneManager.getLcIfManagerNotDestroyedOrNull() - .checkForUpdate(BuildConfig.VERSION_NAME); - LinphonePreferences.instance().setLastCheckReleaseTimestamp(currentTimeStamp); - } - } - } - - private void initButtons() { - mTabBar = findViewById(R.id.footer); - mTopBar = findViewById(R.id.top_bar); - mTopBarTitle = findViewById(R.id.top_bar_title); - - mCancel = findViewById(R.id.cancel); - mCancel.setOnClickListener(this); - - mHistory = findViewById(R.id.history); - mHistory.setOnClickListener(this); - mContacts = findViewById(R.id.contacts); - mContacts.setOnClickListener(this); - mDialer = findViewById(R.id.dialer); - mDialer.setOnClickListener(this); - mChat = findViewById(R.id.chat); - mChat.setOnClickListener(this); - if (getResources().getBoolean(R.bool.disable_chat)) { - mChat.setVisibility(View.GONE); - } - - mHistorySelected = findViewById(R.id.history_select); - mContactsSelected = findViewById(R.id.contacts_select); - mDialerSelected = findViewById(R.id.dialer_select); - mChatSelected = findViewById(R.id.chat_select); - - mMissedCalls = findViewById(R.id.missed_calls); - mMissedChats = findViewById(R.id.missed_chats); - } - - public boolean isTablet() { - return getResources().getBoolean(R.bool.isTablet); - } - - public void hideStatusBar() { - if (isTablet()) { - return; - } - - findViewById(R.id.status).setVisibility(View.GONE); - } - - public void showStatusBar() { - if (isTablet()) { - return; - } - - if (mStatusFragment != null && !mStatusFragment.isVisible()) { - mStatusFragment.getView().setVisibility(View.VISIBLE); - } - findViewById(R.id.status).setVisibility(View.VISIBLE); - } - - public void popBackStack() { - getFragmentManager().popBackStackImmediate(); - mCurrentFragment = FragmentsAvailable.EMPTY; - } - - private void changeCurrentFragment(FragmentsAvailable newFragmentType, Bundle extras) { - if (newFragmentType == mCurrentFragment - && newFragmentType != FragmentsAvailable.CHAT_LIST - && newFragmentType != FragmentsAvailable.CHAT - && newFragmentType != FragmentsAvailable.GROUP_CHAT) { - return; - } - - if (mCurrentFragment == FragmentsAvailable.DIALER) { - try { - DialerFragment dialerFragment = DialerFragment.instance(); - mDialerSavedState = getFragmentManager().saveFragmentInstanceState(dialerFragment); - } catch (Exception e) { - Log.e(e); - } - } - - mFragment = null; - switch (newFragmentType) { - case HISTORY_LIST: - mFragment = new HistoryFragment(); - break; - case HISTORY_DETAIL: - mFragment = new HistoryDetailFragment(); - break; - case CONTACTS_LIST: - mFragment = new ContactsFragment(); - break; - case CONTACT_DETAIL: - mFragment = new ContactDetailsFragment(); - break; - case CONTACT_EDITOR: - mFragment = new ContactEditorFragment(); - break; - case DIALER: - mFragment = new DialerFragment(); - if (extras == null) { - mFragment.setInitialSavedState(mDialerSavedState); - } - break; - case SETTINGS: - mFragment = new SettingsFragment(); - break; - case ACCOUNT_SETTINGS: - mFragment = new AccountSettingsFragment(); - break; - case ABOUT: - mFragment = new AboutFragment(); - break; - case EMPTY: - mFragment = new EmptyFragment(); - break; - case CHAT_LIST: - mFragment = new ChatRoomsFragment(); - break; - case CREATE_CHAT: - mFragment = new ChatRoomCreationFragment(); - break; - case INFO_GROUP_CHAT: - mFragment = new GroupInfoFragment(); - break; - case GROUP_CHAT: - mFragment = new ChatMessagesFragment(); - break; - case MESSAGE_IMDN: - if (getResources().getBoolean(R.bool.use_new_chat_bubbles_layout)) { - mFragment = new ImdnFragment(); - } else { - mFragment = new ImdnOldFragment(); - } - break; - case CONTACT_DEVICES: - mFragment = new DevicesFragment(); - break; - case RECORDING_LIST: - mFragment = new RecordingsFragment(); - break; - default: - break; - } - - applyFragmentChanges(newFragmentType, extras); - } - - private void changeSettingsFragment(Fragment fragment) { - mFragment = fragment; - applyFragmentChanges(FragmentsAvailable.SETTINGS_SUBLEVEL, null); - } - - private void applyFragmentChanges(FragmentsAvailable newFragmentType, Bundle extras) { - if (mFragment != null) { - mFragment.setArguments(extras); - if (isTablet()) { - changeFragmentForTablets(mFragment, newFragmentType); - switch (newFragmentType) { - case HISTORY_LIST: - ((HistoryFragment) mFragment).displayFirstLog(); - break; - case CONTACTS_LIST: - ((ContactsFragment) mFragment).displayFirstContact(); - break; - case CHAT_LIST: - ((ChatRoomsFragment) mFragment).displayFirstChat(); - break; - } - } else { - changeFragment(mFragment, newFragmentType); - } - LinphoneUtils.hideKeyboard(this); - } - } - - private void changeFragment(Fragment newFragment, FragmentsAvailable newFragmentType) { - FragmentManager fm = getFragmentManager(); - FragmentTransaction transaction = fm.beginTransaction(); - - if (newFragmentType != FragmentsAvailable.DIALER - && newFragmentType != FragmentsAvailable.CONTACTS_LIST - && newFragmentType != FragmentsAvailable.CHAT_LIST - && newFragmentType != FragmentsAvailable.HISTORY_LIST) { - transaction.addToBackStack(newFragmentType.toString()); - } else { - while (fm.getBackStackEntryCount() > 0) { - fm.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); - } - } - - Compatibility.setFragmentTransactionReorderingAllowed(transaction, false); - transaction.replace(R.id.fragmentContainer, newFragment, newFragmentType.toString()); - transaction.commitAllowingStateLoss(); - fm.executePendingTransactions(); - - mCurrentFragment = newFragmentType; - } - - private void changeFragmentForTablets( - Fragment newFragment, FragmentsAvailable newFragmentType) { - if (getResources().getBoolean(R.bool.show_statusbar_only_on_dialer)) { - if (newFragmentType == FragmentsAvailable.DIALER) { - showStatusBar(); - } else { - hideStatusBar(); - } - } - mEmptyFragment = false; - LinearLayout ll = findViewById(R.id.fragmentContainer2); - - FragmentTransaction transaction = getFragmentManager().beginTransaction(); - - if (newFragmentType == FragmentsAvailable.EMPTY) { - ll.setVisibility(View.VISIBLE); - mEmptyFragment = true; - transaction.replace(R.id.fragmentContainer2, newFragment); - transaction.commitAllowingStateLoss(); - getFragmentManager().executePendingTransactions(); - } else { - if (newFragmentType.shouldAddItselfToTheRightOf(mCurrentFragment) - || newFragmentType.shouldAddItselfToTheRightOf(mLeftFragment)) { - ll.setVisibility(View.VISIBLE); - - if (newFragmentType == FragmentsAvailable.CONTACT_EDITOR) { - transaction.addToBackStack(newFragmentType.toString()); - } - transaction.replace(R.id.fragmentContainer2, newFragment); - mLeftFragment = mCurrentFragment; - - if (newFragmentType == FragmentsAvailable.GROUP_CHAT - && mLeftFragment != FragmentsAvailable.CHAT_LIST) { - mLeftFragment = FragmentsAvailable.CHAT_LIST; - transaction.replace(R.id.fragmentContainer, new ChatRoomsFragment()); - } - } else { - if (newFragmentType == FragmentsAvailable.EMPTY) { - ll.setVisibility(View.VISIBLE); - transaction.replace(R.id.fragmentContainer2, new EmptyFragment()); - mEmptyFragment = true; - } - - if (newFragmentType == FragmentsAvailable.DIALER - || newFragmentType == FragmentsAvailable.ABOUT - || newFragmentType == FragmentsAvailable.SETTINGS - || newFragmentType == FragmentsAvailable.ACCOUNT_SETTINGS - || newFragmentType == FragmentsAvailable.CREATE_CHAT - || newFragmentType == FragmentsAvailable.INFO_GROUP_CHAT - || newFragmentType == FragmentsAvailable.RECORDING_LIST) { - ll.setVisibility(View.GONE); - } else { - ll.setVisibility(View.VISIBLE); - transaction.replace(R.id.fragmentContainer2, new EmptyFragment()); - } - - transaction.replace(R.id.fragmentContainer, newFragment); - } - transaction.commitAllowingStateLoss(); - getFragmentManager().executePendingTransactions(); - - mCurrentFragment = newFragmentType; - if (newFragmentType == FragmentsAvailable.DIALER - || newFragmentType == FragmentsAvailable.SETTINGS - || newFragmentType == FragmentsAvailable.CONTACTS_LIST - || newFragmentType == FragmentsAvailable.CHAT_LIST - || newFragmentType == FragmentsAvailable.HISTORY_LIST) { - try { - getFragmentManager() - .popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); - } catch (java.lang.IllegalStateException e) { - Log.e(e); - } - } - } - } - - public void displayHistoryDetail(String sipUri, CallLog log) { - Address lAddress; - LinphoneContact c = null; - - lAddress = Factory.instance().createAddress(sipUri); - if (lAddress != null) { - c = ContactsManager.getInstance().findContactFromAddress(lAddress); - } - - String displayName = - c != null ? c.getFullName() : LinphoneUtils.getAddressDisplayName(sipUri); - String pictureUri = - c != null && c.getPhotoUri() != null ? c.getPhotoUri().toString() : null; - - Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2); - if (fragment2 != null - && fragment2.isVisible() - && mCurrentFragment == FragmentsAvailable.HISTORY_DETAIL) { - HistoryDetailFragment historyDetailFragment = (HistoryDetailFragment) fragment2; - historyDetailFragment.changeDisplayedHistory(sipUri, displayName); - } else { - Bundle extras = new Bundle(); - extras.putString("SipUri", sipUri); - if (displayName != null) { - extras.putString("DisplayName", displayName); - extras.putString("PictureUri", pictureUri); - } - - changeCurrentFragment(FragmentsAvailable.HISTORY_DETAIL, extras); - } - } - - public void displayEmptyFragment() { - changeCurrentFragment(FragmentsAvailable.EMPTY, new Bundle()); - } - - public void displayContact(LinphoneContact contact, boolean chatOnly) { - Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2); - if (fragment2 != null - && fragment2.isVisible() - && mCurrentFragment == FragmentsAvailable.CONTACT_DETAIL) { - ContactDetailsFragment contactFragment = (ContactDetailsFragment) fragment2; - contactFragment.changeDisplayedContact(contact); - } else { - Bundle extras = new Bundle(); - extras.putSerializable("Contact", contact); - extras.putBoolean("ChatAddressOnly", chatOnly); - changeCurrentFragment(FragmentsAvailable.CONTACT_DETAIL, extras); - } - } - - public void displayContacts(boolean chatOnly) { - Bundle extras = new Bundle(); - extras.putBoolean("ChatAddressOnly", chatOnly); - changeCurrentFragment(FragmentsAvailable.CONTACTS_LIST, extras); - } - - public void displayContactsForEdition(String sipAddress) { - Bundle extras = new Bundle(); - extras.putBoolean("EditOnClick", true); - extras.putString("SipAddress", sipAddress); - changeCurrentFragment(FragmentsAvailable.CONTACTS_LIST, extras); - } - - private void displayAbout() { - changeCurrentFragment(FragmentsAvailable.ABOUT, null); - } - - private void displayRecordings() { - changeCurrentFragment(FragmentsAvailable.RECORDING_LIST, null); - } - - public void displaySubSettings(Fragment fragment) { - changeSettingsFragment(fragment); - } - - public void displayContactsForEdition(String sipAddress, String displayName) { - Bundle extras = new Bundle(); - extras.putBoolean("EditOnClick", true); - extras.putString("SipAddress", sipAddress); - extras.putString("DisplayName", displayName); - changeCurrentFragment(FragmentsAvailable.CONTACTS_LIST, extras); - } - - private void displayAssistant() { - startActivity(new Intent(LinphoneActivity.this, MenuAssistantActivity.class)); - } - - private void displayInapp() { - startActivity(new Intent(LinphoneActivity.this, InAppPurchaseActivity.class)); - } - - public void goToChatCreator( - String address, - ArrayList selectedContacts, - String subject, - boolean isGoBack, - Bundle shareInfos, - boolean createGroupChat, - boolean isChatRoomEncrypted) { - if (mCurrentFragment == FragmentsAvailable.INFO_GROUP_CHAT && isGoBack) { - getFragmentManager().popBackStackImmediate(); - getFragmentManager().popBackStackImmediate(); - } - Bundle extras = new Bundle(); - extras.putSerializable("selectedContacts", selectedContacts); - extras.putString("subject", subject); - extras.putString("groupChatRoomAddress", address); - extras.putBoolean("createGroupChatRoom", createGroupChat); - extras.putBoolean("encrypted", isChatRoomEncrypted); - - if (shareInfos != null) { - if (shareInfos.getString("fileSharedUri") != null) - extras.putString("fileSharedUri", shareInfos.getString("fileSharedUri")); - if (shareInfos.getString("messageDraft") != null) - extras.putString("messageDraft", shareInfos.getString("messageDraft")); - } - - changeCurrentFragment(FragmentsAvailable.CREATE_CHAT, extras); - } - - public void goToChat(String localSipUri, String remoteSipUri, Bundle shareInfos) { - Bundle extras = new Bundle(); - extras.putString("LocalSipUri", localSipUri); - extras.putString("RemoteSipUri", remoteSipUri); - - if (shareInfos != null) { - if (shareInfos.getString("fileSharedUri") != null) - extras.putString("fileSharedUri", shareInfos.getString("fileSharedUri")); - if (shareInfos.getString("messageDraft") != null) - extras.putString("messageDraft", shareInfos.getString("messageDraft")); - } - - if (isTablet()) { - Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2); - if (fragment2 != null - && fragment2.isVisible() - && mCurrentFragment == FragmentsAvailable.GROUP_CHAT - && !mEmptyFragment) { - ChatMessagesFragment chatFragment = (ChatMessagesFragment) fragment2; - chatFragment.changeDisplayedChat(localSipUri, remoteSipUri); - } else { - changeCurrentFragment(FragmentsAvailable.GROUP_CHAT, extras); - } - } else { - changeCurrentFragment(FragmentsAvailable.GROUP_CHAT, extras); - } - - LinphoneManager.getInstance().updateUnreadCountForChatRoom(localSipUri, remoteSipUri, 0); - displayMissedChats(LinphoneManager.getInstance().getUnreadMessageCount()); - } - - public void goToChatGroupInfos( - String address, - ArrayList contacts, - String subject, - boolean isEditionEnabled, - boolean isGoBack, - Bundle shareInfos, - boolean enableEncryption) { - if (mCurrentFragment == FragmentsAvailable.CREATE_CHAT && isGoBack) { - getFragmentManager().popBackStackImmediate(); - getFragmentManager().popBackStackImmediate(); - } - Bundle extras = new Bundle(); - extras.putString("groupChatRoomAddress", address); - extras.putBoolean("isEditionEnabled", isEditionEnabled); - extras.putSerializable("ContactAddress", contacts); - extras.putString("subject", subject); - extras.putBoolean("encryptionEnabled", enableEncryption); - - if (shareInfos != null) { - if (shareInfos.getString("fileSharedUri") != null) - extras.putString("fileSharedUri", shareInfos.getString("fileSharedUri")); - if (shareInfos.getString("messageDraft") != null) - extras.putString("messageDraft", shareInfos.getString("messageDraft")); - } - - changeCurrentFragment(FragmentsAvailable.INFO_GROUP_CHAT, extras); - } - - public void goToContactDevicesInfos(String localSipUri, String remoteSipUri) { - Bundle extras = new Bundle(); - extras.putSerializable("LocalSipUri", localSipUri); - extras.putSerializable("RemoteSipUri", remoteSipUri); - changeCurrentFragment(FragmentsAvailable.CONTACT_DEVICES, extras); - } - - public void goToChatMessageImdnInfos( - String localSipUri, String remoteSipUri, String messageId) { - Bundle extras = new Bundle(); - extras.putSerializable("LocalSipUri", localSipUri); - extras.putSerializable("RemoteSipUri", remoteSipUri); - extras.putString("MessageId", messageId); - changeCurrentFragment(FragmentsAvailable.MESSAGE_IMDN, extras); - } - - public void goToChatList() { - changeCurrentFragment(FragmentsAvailable.CHAT_LIST, null); - } - - @Override - public void onClick(View v) { - int id = v.getId(); - resetSelection(); - - if (id == R.id.history) { - changeCurrentFragment(FragmentsAvailable.HISTORY_LIST, null); - mHistorySelected.setVisibility(View.VISIBLE); - LinphoneManager.getLc().resetMissedCallsCount(); - displayMissedCalls(0); - } else if (id == R.id.contacts) { - changeCurrentFragment(FragmentsAvailable.CONTACTS_LIST, null); - mContactsSelected.setVisibility(View.VISIBLE); - } else if (id == R.id.dialer) { - changeCurrentFragment(FragmentsAvailable.DIALER, null); - mDialerSelected.setVisibility(View.VISIBLE); - } else if (id == R.id.chat) { - changeCurrentFragment(FragmentsAvailable.CHAT_LIST, null); - mChatSelected.setVisibility(View.VISIBLE); - } else if (id == R.id.cancel) { - if (mCurrentFragment == FragmentsAvailable.SETTINGS_SUBLEVEL && !isTablet()) { - popBackStack(); - } else { - hideTopBar(); - displayDialer(); - } - } - } - - private void resetSelection() { - mHistorySelected.setVisibility(View.GONE); - mContactsSelected.setVisibility(View.GONE); - mDialerSelected.setVisibility(View.GONE); - mChatSelected.setVisibility(View.GONE); - } - - public void hideTabBar(Boolean hide) { - if (hide && !isTablet()) { // do not hide if tablet, otherwise won't be able to navigate... - mTabBar.setVisibility(View.GONE); - } else { - mTabBar.setVisibility(View.VISIBLE); - } - } - - public void hideTopBar() { - mTopBar.setVisibility(View.GONE); - mTopBarTitle.setText(""); - } - - private void showTopBar() { - mTopBar.setVisibility(View.VISIBLE); - } - - private void showTopBarWithTitle(String title) { - showTopBar(); - mTopBarTitle.setText(title); - } - - public void selectMenu(FragmentsAvailable menuToSelect) { - selectMenu(menuToSelect, null); - } - - @SuppressWarnings("incomplete-switch") - public void selectMenu(FragmentsAvailable menuToSelect, String customTitle) { - mCurrentFragment = menuToSelect; - resetSelection(); - hideTopBar(); - boolean hideBottomBar = - getResources().getBoolean(R.bool.hide_bottom_bar_on_second_level_views); - - switch (menuToSelect) { - case HISTORY_LIST: - hideTabBar(false); - mHistorySelected.setVisibility(View.VISIBLE); - break; - case HISTORY_DETAIL: - hideTabBar(hideBottomBar); - mHistorySelected.setVisibility(View.VISIBLE); - break; - case CONTACTS_LIST: - hideTabBar(false); - mContactsSelected.setVisibility(View.VISIBLE); - break; - case CONTACT_DETAIL: - case CONTACT_EDITOR: - hideTabBar(hideBottomBar); - mContactsSelected.setVisibility(View.VISIBLE); - break; - case DIALER: - hideTabBar(false); - mDialerSelected.setVisibility(View.VISIBLE); - break; - case SETTINGS: - case ACCOUNT_SETTINGS: - case SETTINGS_SUBLEVEL: - hideTabBar(hideBottomBar); - if (customTitle == null) { - showTopBarWithTitle(getString(R.string.settings)); - } else { - showTopBarWithTitle(customTitle); - } - break; - case ABOUT: - showTopBarWithTitle(getString(R.string.about)); - hideTabBar(hideBottomBar); - break; - case CHAT_LIST: - hideTabBar(false); - mChatSelected.setVisibility(View.VISIBLE); - break; - case CREATE_CHAT: - case GROUP_CHAT: - case INFO_GROUP_CHAT: - case MESSAGE_IMDN: - case CONTACT_DEVICES: - case CHAT: - hideTabBar(hideBottomBar); - mChatSelected.setVisibility(View.VISIBLE); - break; - case RECORDING_LIST: - hideTabBar(hideBottomBar); - break; - } - } - - public void updateDialerFragment() { - // Hack to maintain soft input flags - getWindow() - .setSoftInputMode( - WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN - | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); - } - - private void goToDialerFragment() { - Bundle extras = new Bundle(); - extras.putString("SipUri", ""); - changeCurrentFragment(FragmentsAvailable.DIALER, extras); - mDialerSelected.setVisibility(View.VISIBLE); - } - - public void updateStatusFragment(StatusFragment fragment) { - mStatusFragment = fragment; - } - - public void displaySettings() { - changeCurrentFragment(FragmentsAvailable.SETTINGS, null); - } - - private void displayDialer() { - changeCurrentFragment(FragmentsAvailable.DIALER, null); - } - - public void displayAccountSettings(int accountNumber) { - Bundle bundle = new Bundle(); - bundle.putInt("Account", accountNumber); - changeCurrentFragment(FragmentsAvailable.ACCOUNT_SETTINGS, bundle); - } - - public void refreshMissedChatCountDisplay() { - displayMissedChats(LinphoneManager.getInstance().getUnreadMessageCount()); - } - - public void displayMissedCalls(final int missedCallsCount) { - if (missedCallsCount > 0) { - mMissedCalls.setText(missedCallsCount + ""); - mMissedCalls.setVisibility(View.VISIBLE); - } else { - if (LinphoneManager.isInstanciated()) LinphoneManager.getLc().resetMissedCallsCount(); - mMissedCalls.clearAnimation(); - mMissedCalls.setVisibility(View.GONE); - } - } - - public void displayMissedChats(final int missedChatCount) { - if (missedChatCount > 0) { - mMissedChats.setText(missedChatCount + ""); - mMissedChats.setVisibility(View.VISIBLE); - } else { - mMissedChats.clearAnimation(); - mMissedChats.setVisibility(View.GONE); - } - if (mCurrentFragment == FragmentsAvailable.CHAT_LIST - && mFragment instanceof ChatRoomsFragment) { - ((ChatRoomsFragment) mFragment).invalidate(); - } - } - - 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 = 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(); - } - - public void displayChatRoomError() { - final Dialog dialog = displayDialog(getString(R.string.chat_room_creation_failed)); - dialog.findViewById(R.id.dialog_delete_button).setVisibility(View.GONE); - Button cancel = dialog.findViewById(R.id.dialog_cancel_button); - cancel.setText(getString(R.string.ok)); - cancel.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View view) { - dialog.dismiss(); - } - }); - - dialog.show(); - } - - public Dialog displayDialog(String text) { - Dialog dialog = new Dialog(this); - dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); - Drawable d = new ColorDrawable(ContextCompat.getColor(this, R.color.dark_grey_color)); - d.setAlpha(200); - dialog.setContentView(R.layout.dialog); - dialog.getWindow() - .setLayout( - WindowManager.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.MATCH_PARENT); - dialog.getWindow().setBackgroundDrawable(d); - - TextView customText = dialog.findViewById(R.id.dialog_message); - customText.setText(text); - return dialog; - } - - public void setAddresGoToDialerAndCall(String number, String name) { - AddressType address = new AddressText(this, null); - address.setText(number); - address.setDisplayedName(name); - if (!mCallTransfer) { - LinphoneManager.getInstance().newOutgoingCall(address); - } else { - addressWaitingToBeCalled = number; - displayDialer(); - } - } - - public void startIncallActivity() { - Intent intent = new Intent(this, CallActivity.class); - startOrientationSensor(); - startActivityForResult(intent, CALL_ACTIVITY); - } - - /** Register a sensor to track phoneOrientation changes */ - private synchronized void startOrientationSensor() { - if (mOrientationHelper == null) { - mOrientationHelper = new LocalOrientationEventListener(this); - } - mOrientationHelper.enable(); - } - - public Boolean isCallTransfer() { - return mCallTransfer; - } - - private void initInCallMenuLayout() { - selectMenu(FragmentsAvailable.DIALER); - DialerFragment dialerFragment = DialerFragment.instance(); - if (dialerFragment != null) { - (dialerFragment).resetLayout(); - } - } - - public void resetClassicMenuLayoutAndGoBackToCallIfStillRunning() { - DialerFragment dialerFragment = DialerFragment.instance(); - if (dialerFragment != null) { - (dialerFragment).resetLayout(); - } - - if (LinphoneManager.isInstanciated() && LinphoneManager.getLc().getCallsNb() > 0) { - Call call = LinphoneManager.getLc().getCalls()[0]; - if (call.getState() == Call.State.IncomingReceived - || call.getState() == State.IncomingEarlyMedia) { - startActivity(new Intent(LinphoneActivity.this, CallIncomingActivity.class)); - } else { - startIncallActivity(); - } - } - } - - public FragmentsAvailable getCurrentFragment() { - return mCurrentFragment; - } - - public void addContact(String displayName, String sipUri) { - Bundle extras = new Bundle(); - extras.putSerializable("NewSipAdress", sipUri); - extras.putSerializable("NewDisplayName", displayName); - changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras); - } - - public void editContact(LinphoneContact contact, String sipUri) { - Bundle extras = new Bundle(); - extras.putSerializable("Contact", contact); - extras.putString("NewSipAdress", sipUri); - changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras); - } - - private void quit() { - finish(); - stopService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class)); - ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); - am.killBackgroundProcesses(getString(R.string.sync_account_type)); - android.os.Process.killProcess(android.os.Process.myPid()); - } - - public boolean checkAndRequestOverlayPermission() { - Log.i( - "[Permission] Draw overlays permission is " - + (Compatibility.canDrawOverlays(this) ? "granted" : "denied")); - if (!Compatibility.canDrawOverlays(this)) { - Log.i("[Permission] Asking for overlay"); - Intent intent = - new Intent( - Settings.ACTION_MANAGE_OVERLAY_PERMISSION, - Uri.parse("package:" + getPackageName())); - startActivityForResult(intent, PERMISSIONS_REQUEST_OVERLAY); - return false; - } - return true; - } - - public void checkAndRequestExternalStoragePermission() { - checkAndRequestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, 0); - } - - public void checkAndRequestReadContactsPermission() { - checkAndRequestPermission(Manifest.permission.READ_CONTACTS, PERMISSIONS_REQUEST_SYNC); - } - - public void checkAndRequestCameraPermission() { - checkAndRequestPermission(Manifest.permission.CAMERA, 0); - } - - public void checkAndRequestRecordAudioPermissionForEchoCanceller() { - checkAndRequestPermission( - Manifest.permission.RECORD_AUDIO, PERMISSIONS_RECORD_AUDIO_ECHO_CANCELLER); - } - - public void checkAndRequestRecordAudioPermissionsForEchoTester() { - checkAndRequestPermission( - Manifest.permission.RECORD_AUDIO, PERMISSIONS_RECORD_AUDIO_ECHO_TESTER); - } - - public void checkAndRequestReadExternalStoragePermissionForDeviceRingtone() { - checkAndRequestPermission( - Manifest.permission.READ_EXTERNAL_STORAGE, - PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE); - } - - public void checkAndRequestPermissionsToSendImage() { - ArrayList permissionsToAskFor = new ArrayList<>(); - String[] permissionsToHave = { - Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA - }; - - for (String permissionToHave : permissionsToHave) { - if (!checkPermission(permissionToHave)) { - permissionsToAskFor.add(permissionToHave); - } - } - - if (permissionsToAskFor.size() > 0) { - String[] permissions = new String[permissionsToAskFor.size()]; - permissions = permissionsToAskFor.toArray(permissions); - ActivityCompat.requestPermissions(this, permissions, 0); - } - } - - private void checkSyncPermission() { - checkAndRequestPermission( - Manifest.permission.WRITE_SYNC_SETTINGS, PERMISSIONS_REQUEST_SYNC); - } - - private boolean checkPermission(String permission) { - int granted = getPackageManager().checkPermission(permission, getPackageName()); - Log.i( - "[Permission] " - + permission - + " permission is " - + (granted == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); - return granted == PackageManager.PERMISSION_GRANTED; - } - - private void checkAndRequestPermission(String permission, int result) { - int permissionGranted = getPackageManager().checkPermission(permission, getPackageName()); - Log.i( - "[Permission] " - + permission - + " is " - + (permissionGranted == PackageManager.PERMISSION_GRANTED - ? "granted" - : "denied")); - - if (!checkPermission(permission)) { - Log.i("[Permission] Asking for " + permission); - ActivityCompat.requestPermissions(this, new String[] {permission}, result); - } - } - - public boolean isOnBackground() { - return mIsOnBackground; - } - - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - switch (mCurrentFragment) { - case DIALER: - case CONTACTS_LIST: - case HISTORY_LIST: - case CHAT_LIST: - if (LinphoneUtils.onKeyBackGoHome(this, keyCode, event)) { - return true; - } - break; - case GROUP_CHAT: - hideTopBar(); // just in case - LinphoneActivity.instance().goToChatList(); - return true; - case SETTINGS_SUBLEVEL: - if (!isTablet()) { - popBackStack(); - return true; - } - case SETTINGS: - case ACCOUNT_SETTINGS: - case ABOUT: - hideTopBar(); // just in case - LinphoneActivity.instance().goToDialerFragment(); - return true; - default: - break; - } - } - return super.onKeyDown(keyCode, event); - } - - // SIDE MENU - private void openOrCloseSideMenu(boolean open) { - if (open) { - mSideMenu.openDrawer(mSideMenuContent); - } else { - mSideMenu.closeDrawer(mSideMenuContent); - } - } - - private void initSideMenu() { - mSideMenu = findViewById(R.id.side_menu); - mSideMenuItems = new ArrayList<>(); - if (getResources().getBoolean(R.bool.show_log_out_in_side_menu)) { - mSideMenuItems.add( - new MenuItem( - getResources().getString(R.string.menu_logout), - R.drawable.quit_default)); - } - if (!getResources().getBoolean(R.bool.hide_assistant_from_side_menu)) { - mSideMenuItems.add( - new MenuItem( - getResources().getString(R.string.menu_assistant), - R.drawable.menu_assistant)); - } - if (!getResources().getBoolean(R.bool.hide_settings_from_side_menu)) { - mSideMenuItems.add( - new MenuItem( - getResources().getString(R.string.menu_settings), - R.drawable.menu_options)); - } - if (getResources().getBoolean(R.bool.enable_in_app_purchase)) { - mSideMenuItems.add( - new MenuItem( - getResources().getString(R.string.inapp), R.drawable.menu_options)); - } - if (!getResources().getBoolean(R.bool.hide_recordings_from_side_menu)) { - mSideMenuItems.add( - new MenuItem( - getResources().getString(R.string.menu_recordings), - R.drawable.menu_recordings)); - } - mSideMenuItems.add( - new MenuItem(getResources().getString(R.string.menu_about), R.drawable.menu_about)); - mSideMenuContent = findViewById(R.id.side_menu_content); - mSideMenuItemList = findViewById(R.id.item_list); - mMenu = findViewById(R.id.side_menu_button); - - mSideMenuItemList.setAdapter( - new MenuAdapter(this, R.layout.side_menu_item_cell, mSideMenuItems)); - mSideMenuItemList.setOnItemClickListener( - new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView adapterView, View view, int i, long l) { - String selectedItem = mSideMenuItemList.getAdapter().getItem(i).toString(); - if (selectedItem.equals(getString(R.string.menu_logout))) { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.setDefaultProxyConfig(null); - lc.clearAllAuthInfo(); - lc.clearProxyConfig(); - startActivity( - new Intent() - .setClass( - LinphoneManager.getInstance().getContext(), - MenuAssistantActivity.class)); - finish(); - } - } else if (selectedItem.equals(getString(R.string.menu_settings))) { - LinphoneActivity.instance().displaySettings(); - } else if (selectedItem.equals(getString(R.string.menu_about))) { - LinphoneActivity.instance().displayAbout(); - } else if (selectedItem.equals(getString(R.string.menu_assistant))) { - LinphoneActivity.instance().displayAssistant(); - } - if (getResources().getBoolean(R.bool.enable_in_app_purchase)) { - if (mSideMenuItemList - .getAdapter() - .getItem(i) - .toString() - .equals(getString(R.string.inapp))) { - LinphoneActivity.instance().displayInapp(); - } - } - if (mSideMenuItemList - .getAdapter() - .getItem(i) - .toString() - .equals(getString(R.string.menu_recordings))) { - LinphoneActivity.instance().displayRecordings(); - } - openOrCloseSideMenu(false); - } - }); - - initAccounts(); - - mMenu.setOnClickListener( - new OnClickListener() { - @Override - public void onClick(View view) { - - if (mSideMenu.isDrawerVisible(Gravity.LEFT)) { - mSideMenu.closeDrawer(mSideMenuContent); - } else { - mSideMenu.openDrawer(mSideMenuContent); - } - } - }); - - mQuitLayout = findViewById(R.id.side_menu_quit); - mQuitLayout.setOnClickListener( - new OnClickListener() { - @Override - public void onClick(View view) { - LinphoneActivity.instance().quit(); - } - }); - } - - private int getStatusIconResource(RegistrationState state) { - try { - if (state == RegistrationState.Ok) { - return R.drawable.led_connected; - } else if (state == RegistrationState.Progress) { - return R.drawable.led_inprogress; - } else if (state == RegistrationState.Failed) { - return R.drawable.led_error; - } else { - return R.drawable.led_disconnected; - } - } catch (Exception e) { - Log.e(e); - } - - return R.drawable.led_disconnected; - } - - private void displayMainAccount() { - mDefaultAccount.setVisibility(View.VISIBLE); - ImageView status = mDefaultAccount.findViewById(R.id.main_account_status); - TextView address = mDefaultAccount.findViewById(R.id.main_account_address); - TextView displayName = mDefaultAccount.findViewById(R.id.main_account_display_name); - - ProxyConfig proxy = LinphoneManager.getLc().getDefaultProxyConfig(); - if (proxy == null) { - displayName.setText(getString(R.string.no_account)); - status.setVisibility(View.GONE); - address.setText(""); - mStatusFragment.resetAccountStatus(); - - mDefaultAccount.setOnClickListener(null); - } else { - address.setText(proxy.getIdentityAddress().asStringUriOnly()); - displayName.setText(LinphoneUtils.getAddressDisplayName(proxy.getIdentityAddress())); - status.setImageResource(getStatusIconResource(proxy.getState())); - status.setVisibility(View.VISIBLE); - - if (!getResources().getBoolean(R.bool.disable_accounts_settings_from_side_menu)) { - mDefaultAccount.setOnClickListener( - new OnClickListener() { - @Override - public void onClick(View view) { - LinphoneActivity.instance() - .displayAccountSettings( - LinphonePreferences.instance() - .getDefaultAccountIndex()); - openOrCloseSideMenu(false); - } - }); - } - } - } - - public void refreshAccounts() { - if (LinphoneManager.getLc().getProxyConfigList() != null - && LinphoneManager.getLc().getProxyConfigList().length > 1) { - mAccountsList.setVisibility(View.VISIBLE); - mAccountsList.setAdapter(new AccountsListAdapter()); - mAccountsList.setOnItemClickListener( - new AdapterView.OnItemClickListener() { - @Override - public void onItemClick( - AdapterView adapterView, View view, int i, long l) { - if (view != null && view.getTag() != null) { - int position = Integer.parseInt(view.getTag().toString()); - LinphoneActivity.instance().displayAccountSettings(position); - } - openOrCloseSideMenu(false); - } - }); - } else { - mAccountsList.setVisibility(View.GONE); - } - displayMainAccount(); - } - - private void initAccounts() { - mAccountsList = findViewById(R.id.accounts_list); - mDefaultAccount = findViewById(R.id.default_account); - } - - // Inapp Purchase - private void isTrialAccount() { - if (LinphoneManager.getLc().getDefaultProxyConfig() != null - && LinphonePreferences.instance().getInappPopupTime() != null) { - XmlRpcHelper helper = new XmlRpcHelper(); - helper.isTrialAccountAsync( - new XmlRpcListenerBase() { - @Override - public void onTrialAccountFetched(boolean isTrial) { - mIsTrialAccount = isTrial; - getExpirationAccount(); - } - - @Override - public void onError() {} - }, - LinphonePreferences.instance() - .getAccountUsername( - LinphonePreferences.instance().getDefaultAccountIndex()), - LinphonePreferences.instance() - .getAccountHa1( - LinphonePreferences.instance().getDefaultAccountIndex())); - } - } - - private void getExpirationAccount() { - if (LinphoneManager.getLc().getDefaultProxyConfig() != null - && LinphonePreferences.instance().getInappPopupTime() != null) { - XmlRpcHelper helper = new XmlRpcHelper(); - helper.getAccountExpireAsync( - new XmlRpcListenerBase() { - @Override - public void onAccountExpireFetched(String result) { - if (result != null) { - long timestamp = Long.parseLong(result); - - Calendar calresult = Calendar.getInstance(); - calresult.setTimeInMillis(timestamp); - - int diff = getDiffDays(calresult, Calendar.getInstance()); - if (diff != -1 - && diff - <= getResources() - .getInteger( - R.integer - .days_notification_shown)) { - displayInappNotification(timestampToHumanDate(calresult)); - } - } - } - - @Override - public void onError() {} - }, - LinphonePreferences.instance() - .getAccountUsername( - LinphonePreferences.instance().getDefaultAccountIndex()), - LinphonePreferences.instance() - .getAccountHa1( - LinphonePreferences.instance().getDefaultAccountIndex())); - } - } - - private void displayInappNotification(String date) { - Timestamp now = new Timestamp(new Date().getTime()); - if (LinphonePreferences.instance().getInappPopupTime() != null - && Long.parseLong(LinphonePreferences.instance().getInappPopupTime()) - > now.getTime()) { - return; - } else { - long newDate = - now.getTime() - + getResources().getInteger(R.integer.time_between_inapp_notification); - LinphonePreferences.instance().setInappPopupTime(String.valueOf(newDate)); - } - if (mIsTrialAccount) { - LinphoneService.instance() - .getNotificationManager() - .displayInappNotification( - String.format( - getString(R.string.inapp_notification_trial_expire), date)); - } else { - LinphoneService.instance() - .getNotificationManager() - .displayInappNotification( - String.format( - getString(R.string.inapp_notification_account_expire), date)); - } - } - - private String timestampToHumanDate(Calendar cal) { - SimpleDateFormat dateFormat; - dateFormat = - new SimpleDateFormat(getResources().getString(R.string.inapp_popup_date_format)); - return dateFormat.format(cal.getTime()); - } - - private int getDiffDays(Calendar cal1, Calendar cal2) { - if (cal1 == null || cal2 == null) { - return -1; - } - if (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) - && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)) { - return cal1.get(Calendar.DAY_OF_YEAR) - cal2.get(Calendar.DAY_OF_YEAR); - } - return -1; - } - - private class LocalOrientationEventListener extends OrientationEventListener { - LocalOrientationEventListener(Context context) { - super(context); - } - - @Override - public void onOrientationChanged(final int o) { - if (o == OrientationEventListener.ORIENTATION_UNKNOWN) { - return; - } - - int degrees = 270; - if (o < 45 || o > 315) degrees = 0; - else if (o < 135) degrees = 90; - else if (o < 225) degrees = 180; - - if (mAlwaysChangingPhoneAngle == degrees) { - return; - } - mAlwaysChangingPhoneAngle = degrees; - - Log.d("Phone orientation changed to ", degrees); - int rotation = (360 - degrees) % 360; - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.setDeviceRotation(rotation); - } - } - } - - class AccountsListAdapter extends BaseAdapter { - List proxy_list; - - AccountsListAdapter() { - proxy_list = new ArrayList<>(); - refresh(); - } - - void refresh() { - proxy_list = new ArrayList<>(); - for (ProxyConfig proxyConfig : LinphoneManager.getLc().getProxyConfigList()) { - if (proxyConfig != LinphoneManager.getLc().getDefaultProxyConfig()) { - proxy_list.add(proxyConfig); - } - } - } - - public int getCount() { - if (proxy_list != null) { - return proxy_list.size(); - } else { - return 0; - } - } - - public Object getItem(int position) { - return proxy_list.get(position); - } - - public long getItemId(int position) { - return position; - } - - public View getView(final int position, View convertView, ViewGroup parent) { - View view; - ProxyConfig lpc = (ProxyConfig) getItem(position); - if (convertView != null) { - view = convertView; - } else { - view = getLayoutInflater().inflate(R.layout.side_menu_account_cell, parent, false); - } - - ImageView status = view.findViewById(R.id.account_status); - TextView address = view.findViewById(R.id.account_address); - String sipAddress = lpc.getIdentityAddress().asStringUriOnly(); - - address.setText(sipAddress); - - int nbAccounts = LinphonePreferences.instance().getAccountCount(); - int accountIndex; - - for (int i = 0; i < nbAccounts; i++) { - String username = LinphonePreferences.instance().getAccountUsername(i); - String domain = LinphonePreferences.instance().getAccountDomain(i); - String id = "sip:" + username + "@" + domain; - if (id.equals(sipAddress)) { - accountIndex = i; - view.setTag(accountIndex); - break; - } - } - status.setImageResource(getStatusIconResource(lpc.getState())); - return view; - } - } - - private class MenuItem { - final String name; - final int icon; - - MenuItem(String name, int icon) { - this.name = name; - this.icon = icon; - } - - public String toString() { - return name; - } - } - - private class MenuAdapter extends ArrayAdapter { - private final List mItems; - private final int mResource; - - MenuAdapter(@NonNull Context context, int resource, @NonNull List objects) { - super(context, resource, objects); - mResource = resource; - mItems = objects; - } - - @Nullable - @Override - public MenuItem getItem(int position) { - return mItems.get(position); - } - - @Override - public int getCount() { - return mItems.size(); - } - - @NonNull - @Override - public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { - LayoutInflater inflater = - (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - View rowView = inflater.inflate(mResource, parent, false); - - TextView textView = rowView.findViewById(R.id.item_name); - ImageView imageView = rowView.findViewById(R.id.item_icon); - - MenuItem item = getItem(position); - textView.setText(item.name); - imageView.setImageResource(item.icon); - - return rowView; - } - } -} diff --git a/app/src/main/java/org/linphone/LinphoneManager.java b/app/src/main/java/org/linphone/LinphoneManager.java index 7f5e26b85..625cbadf0 100644 --- a/app/src/main/java/org/linphone/LinphoneManager.java +++ b/app/src/main/java/org/linphone/LinphoneManager.java @@ -2,7 +2,7 @@ package org.linphone; /* LinphoneManager.java -Copyright (C) 2018 Belledonne Communications, Grenoble, France +Copyright (C) 2018 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 @@ -19,208 +19,127 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import static android.media.AudioManager.MODE_RINGTONE; -import static android.media.AudioManager.STREAM_RING; -import static android.media.AudioManager.STREAM_VOICE_CALL; - import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; -import android.app.ProgressDialog; import android.content.BroadcastReceiver; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Resources; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; -import android.media.AudioManager; -import android.media.MediaPlayer; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; -import android.os.Build; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.WakeLock; -import android.os.Vibrator; -import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; -import android.telephony.TelephonyManager; import android.view.View; import android.widget.Button; import android.widget.CheckBox; -import android.widget.Toast; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Timestamp; import java.util.Date; -import java.util.HashMap; -import java.util.Map; import java.util.Timer; import java.util.TimerTask; import org.linphone.assistant.PhoneAccountLinkingAssistantActivity; -import org.linphone.call.CallActivity; -import org.linphone.call.CallIncomingActivity; import org.linphone.call.CallManager; import org.linphone.contacts.ContactsManager; -import org.linphone.contacts.LinphoneContact; import org.linphone.core.AccountCreator; -import org.linphone.core.AccountCreatorListener; -import org.linphone.core.Address; -import org.linphone.core.AuthInfo; -import org.linphone.core.AuthMethod; +import org.linphone.core.AccountCreatorListenerStub; import org.linphone.core.Call; import org.linphone.core.Call.State; -import org.linphone.core.CallLog; -import org.linphone.core.CallParams; -import org.linphone.core.CallStats; -import org.linphone.core.ChatMessage; -import org.linphone.core.ChatRoom; -import org.linphone.core.ChatRoomCapabilities; import org.linphone.core.ConfiguringState; -import org.linphone.core.Content; import org.linphone.core.Core; -import org.linphone.core.Core.LogCollectionUploadState; -import org.linphone.core.CoreListener; -import org.linphone.core.EcCalibratorStatus; -import org.linphone.core.Event; +import org.linphone.core.CoreListenerStub; import org.linphone.core.Factory; -import org.linphone.core.Friend; import org.linphone.core.FriendList; import org.linphone.core.GlobalState; -import org.linphone.core.InfoMessage; import org.linphone.core.PresenceActivity; import org.linphone.core.PresenceBasicStatus; import org.linphone.core.PresenceModel; import org.linphone.core.ProxyConfig; -import org.linphone.core.PublishState; import org.linphone.core.Reason; -import org.linphone.core.RegistrationState; -import org.linphone.core.SubscriptionState; import org.linphone.core.Tunnel; import org.linphone.core.TunnelConfig; import org.linphone.core.VersionUpdateCheckResult; import org.linphone.core.tools.H264Helper; import org.linphone.core.tools.Log; -import org.linphone.core.tools.OpenH264DownloadHelper; -import org.linphone.core.tools.OpenH264DownloadHelperListener; -import org.linphone.mediastream.Version; import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration; import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration.AndroidCamera; -import org.linphone.mediastream.video.capture.hwconf.Hacks; -import org.linphone.receivers.BluetoothManager; import org.linphone.receivers.HookReceiver; import org.linphone.receivers.OutgoingCallReceiver; import org.linphone.settings.LinphonePreferences; -import org.linphone.utils.FileUtils; +import org.linphone.utils.AndroidAudioManager; import org.linphone.utils.LinphoneUtils; import org.linphone.utils.MediaScanner; -import org.linphone.utils.MediaScannerListener; import org.linphone.utils.PushNotificationUtils; -/** - * Manager of the low level LibLinphone stuff.
- * Including: - * - *
    - *
  • Starting C liblinphone - *
  • Reacting to C liblinphone state changes - *
  • Calling Linphone android service listener methods - *
  • Interacting from Android GUI/service with low level SIP stuff/ - *
- * - *

Add Service Listener to react to Linphone state changes. - */ -public class LinphoneManager implements CoreListener, SensorEventListener, AccountCreatorListener { - - private static final int LINPHONE_VOLUME_STREAM = STREAM_VOICE_CALL; - - private static LinphoneManager sInstance; - private static boolean sExited; - - public final String configFile; - - /** Called when the activity is first created. */ +/** Handles Linphone's Core lifecycle */ +public class LinphoneManager implements SensorEventListener { + private final String mConfigFile; private final String mLPConfigXsd; - + private final String mBasePath; private final String mLinphoneFactoryConfigFile; private final String mLinphoneDynamicConfigFile, mDefaultDynamicConfigFile; - private final String mChatDatabaseFile; private final String mRingSoundFile; private final String mCallLogDatabaseFile; private final String mFriendsDatabaseFile; private final String mUserCertsPath; + private final Context mServiceContext; - private final AudioManager mAudioManager; + private AndroidAudioManager mAudioManager; + private CallManager mCallManager; private final PowerManager mPowerManager; - private final Resources mRessources; - private final LinphonePreferences mPrefs; - private Core mCore; - private OpenH264DownloadHelper mCodecDownloader; - private OpenH264DownloadHelperListener mCodecListener; - private final String mBasePath; - private boolean mAudioFocused; - private boolean mEchoTesterIsRunning; - private boolean mCallGsmON; private final ConnectivityManager mConnectivityManager; private BroadcastReceiver mHookReceiver; private BroadcastReceiver mCallReceiver; - private IntentFilter mHookIntentFilter; - private IntentFilter mCallIntentFilter; - private final Handler mHandler = new Handler(); private WakeLock mProximityWakelock; - private AccountCreator mAccountCreator; private final SensorManager mSensorManager; private final Sensor mProximity; - private boolean mProximitySensingEnabled; - private boolean mHandsetON = false; - private Address mCurrentChatRoomAddress; - private Timer mTimer; - private final Map mUnreadChatsPerRoom; private final MediaScanner mMediaScanner; - private Call mRingingCall; - private MediaPlayer mRingerPlayer; - private final Vibrator mVibrator; - private boolean mIsRinging; + private Timer mTimer; + private final Handler mHandler = new Handler(); + + private final LinphonePreferences mPrefs; + private Core mCore; + private CoreListenerStub mCoreListener; + private AccountCreator mAccountCreator; + private AccountCreatorListenerStub mAccountCreatorListener; + + private boolean mExited; + private boolean mCallGsmON; + private boolean mProximitySensingEnabled; private boolean mHasLastCallSasBeenRejected; - private LinphoneManager(Context c) { - mUnreadChatsPerRoom = new HashMap(); - sExited = false; - mEchoTesterIsRunning = false; + public LinphoneManager(Context c) { + mExited = false; mServiceContext = c; mBasePath = c.getFilesDir().getAbsolutePath(); mLPConfigXsd = mBasePath + "/lpconfig.xsd"; mLinphoneFactoryConfigFile = mBasePath + "/linphonerc"; - configFile = mBasePath + "/.linphonerc"; + mConfigFile = mBasePath + "/.linphonerc"; mLinphoneDynamicConfigFile = mBasePath + "/linphone_assistant_create.rc"; mDefaultDynamicConfigFile = mBasePath + "/default_assistant_create.rc"; - mChatDatabaseFile = mBasePath + "/linphone-history.db"; mCallLogDatabaseFile = mBasePath + "/linphone-log-history.db"; mFriendsDatabaseFile = mBasePath + "/linphone-friends.db"; mRingSoundFile = mBasePath + "/share/sounds/linphone/rings/notes_of_the_optimistic.mkv"; mUserCertsPath = mBasePath + "/user-certs"; mPrefs = LinphonePreferences.instance(); - mAudioManager = ((AudioManager) c.getSystemService(Context.AUDIO_SERVICE)); - mVibrator = (Vibrator) c.getSystemService(Context.VIBRATOR_SERVICE); mPowerManager = (PowerManager) c.getSystemService(Context.POWER_SERVICE); mConnectivityManager = (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE); mSensorManager = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE); mProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); - mRessources = c.getResources(); mHasLastCallSasBeenRejected = false; + mCallManager = new CallManager(c); File f = new File(mUserCertsPath); if (!f.exists()) { @@ -230,439 +149,269 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou } mMediaScanner = new MediaScanner(c); - } - public static synchronized void createAndStart(Context c, boolean isPush) { - if (sInstance != null) { - Log.e( - "[Manager] Linphone Manager is already initialized ! Destroying it and creating a new one..."); - destroy(); - } + mCoreListener = + new CoreListenerStub() { + @Override + public void onGlobalStateChanged( + final Core core, final GlobalState state, final String message) { + Log.i("New global state [", state, "]"); + if (state == GlobalState.On) { + try { + initLiblinphone(core); + } catch (IllegalArgumentException iae) { + Log.e( + "[Manager] Global State Changed Illegal Argument Exception: " + + iae); + } + } + } - sInstance = new LinphoneManager(c); - sInstance.startLibLinphone(c, isPush); - sInstance.initOpenH264DownloadHelper(); + @Override + public void onConfiguringStatus( + Core core, ConfiguringState state, String message) { + Log.d( + "[Manager] Remote provisioning status = " + + state.toString() + + " (" + + message + + ")"); - // H264 codec Management - set to auto mode -> MediaCodec >= android 5.0 >= OpenH264 - H264Helper.setH264Mode(H264Helper.MODE_AUTO, getLc()); + LinphonePreferences prefs = LinphonePreferences.instance(); + if (state == ConfiguringState.Successful) { + prefs.setPushNotificationEnabled(prefs.isPushNotificationEnabled()); + } + } + + @SuppressLint("Wakelock") + @Override + public void onCallStateChanged( + final Core core, + final Call call, + final State state, + final String message) { + Log.i("[Manager] New call state [", state, "]"); + if (state == State.IncomingReceived + && !call.equals(core.getCurrentCall())) { + if (call.getReplacedCall() != null) { + // attended transfer + // it will be accepted automatically. + return; + } + } + + if ((state == State.IncomingReceived || state == State.IncomingEarlyMedia) + && getCallGsmON()) { + if (mCore != null) { + mCore.declineCall(call, Reason.Busy); + } + } else if (state == State.IncomingReceived + && (LinphonePreferences.instance().isAutoAnswerEnabled()) + && !getCallGsmON()) { + TimerTask lTask = + new TimerTask() { + @Override + public void run() { + if (mCore != null) { + if (mCore.getCallsNb() > 0) { + mCallManager.acceptCall(call); + mAudioManager.routeAudioToEarPiece(); + } + } + } + }; + mTimer = new Timer("Auto answer"); + mTimer.schedule(lTask, mPrefs.getAutoAnswerTime()); + } + + if (state == State.End || state == State.Error) { + if (mCore.getCallsNb() == 0) { + // Disabling proximity sensor + enableProximitySensing(false); + } + } + if (state == State.UpdatedByRemote) { + // If the correspondent proposes video while audio call + boolean remoteVideo = call.getRemoteParams().videoEnabled(); + boolean localVideo = call.getCurrentParams().videoEnabled(); + boolean autoAcceptCameraPolicy = + LinphonePreferences.instance() + .shouldAutomaticallyAcceptVideoRequests(); + if (remoteVideo + && !localVideo + && !autoAcceptCameraPolicy + && mCore.getConference() == null) { + mCore.deferCallUpdate(call); + } + } + } + + @Override + public void onVersionUpdateCheckResultReceived( + Core core, + VersionUpdateCheckResult result, + String version, + String url) { + if (result == VersionUpdateCheckResult.NewVersionAvailable) { + final String urlToUse = url; + final String versionAv = version; + mHandler.postDelayed( + new Runnable() { + @Override + public void run() { + AlertDialog.Builder builder = + new AlertDialog.Builder(mServiceContext); + builder.setMessage( + getString(R.string.update_available) + + ": " + + versionAv); + builder.setCancelable(false); + builder.setNeutralButton( + getString(R.string.ok), + new DialogInterface.OnClickListener() { + @Override + public void onClick( + DialogInterface dialogInterface, + int i) { + if (urlToUse != null) { + Intent urlIntent = + new Intent( + Intent.ACTION_VIEW); + urlIntent.setData( + Uri.parse(urlToUse)); + mServiceContext.startActivity( + urlIntent); + } + } + }); + builder.show(); + } + }, + 1000); + } + } + + @Override + public void onFriendListCreated(Core core, FriendList list) { + if (LinphoneService.isReady()) { + list.addListener(ContactsManager.getInstance()); + } + } + + @Override + public void onFriendListRemoved(Core core, FriendList list) { + list.removeListener(ContactsManager.getInstance()); + } + }; + + mAccountCreatorListener = + new AccountCreatorListenerStub() { + @Override + public void onIsAccountExist( + AccountCreator accountCreator, + AccountCreator.Status status, + String resp) { + if (status.equals(AccountCreator.Status.AccountExist)) { + accountCreator.isAccountLinked(); + } + } + + @Override + public void onLinkAccount( + AccountCreator accountCreator, + AccountCreator.Status status, + String resp) { + if (status.equals(AccountCreator.Status.AccountNotLinked)) { + askLinkWithPhoneNumber(); + } + } + + @Override + public void onIsAccountLinked( + AccountCreator accountCreator, + AccountCreator.Status status, + String resp) { + if (status.equals(AccountCreator.Status.AccountNotLinked)) { + askLinkWithPhoneNumber(); + } + } + }; } public static synchronized LinphoneManager getInstance() { - if (sInstance != null) return sInstance; - - if (sExited) { + LinphoneManager manager = LinphoneService.instance().getLinphoneManager(); + if (manager == null) { + throw new RuntimeException( + "[Manager] Linphone Manager should be created before accessed"); + } + if (manager.mExited) { throw new RuntimeException( "[Manager] Linphone Manager was already destroyed. " - + "Better use getLcIfManagerNotDestroyedOrNull and check returned value"); + + "Better use getCore and check returned value"); } - - throw new RuntimeException("[Manager] Linphone Manager should be created before accessed"); + return manager; } - public static synchronized Core getLc() { - return getInstance().mCore; + public static synchronized AndroidAudioManager getAudioManager() { + return getInstance().mAudioManager; } - private static Boolean isProximitySensorNearby(final SensorEvent event) { - float threshold = 4.001f; // <= 4 cm is near - - final float distanceInCm = event.values[0]; - final float maxDistance = event.sensor.getMaximumRange(); - Log.d( - "[Manager] Proximity sensor report [" - + distanceInCm - + "] , for max range [" - + maxDistance - + "]"); - - if (maxDistance <= threshold) { - // Case binary 0/1 and short sensors - threshold = maxDistance; - } - return distanceInCm < threshold; + public static synchronized CallManager getCallManager() { + return getInstance().mCallManager; } - private static void ContactsManagerDestroy() { - if (LinphoneManager.sInstance != null && LinphoneManager.sInstance.mServiceContext != null) - LinphoneManager.sInstance - .mServiceContext - .getContentResolver() - .unregisterContentObserver(ContactsManager.getInstance()); - ContactsManager.getInstance().destroy(); - } - - private static void BluetoothManagerDestroy() { - BluetoothManager.getInstance().destroy(); - } - - public static synchronized void destroy() { - if (sInstance == null) return; - sInstance.changeStatusToOffline(); - sInstance.mMediaScanner.destroy(); - sExited = true; - sInstance.destroyCore(); - sInstance = null; - } - - private static boolean reinviteWithVideo() { - return CallManager.getInstance().reinviteWithVideo(); - } - - public static synchronized Core getLcIfManagerNotDestroyedOrNull() { - if (sExited || sInstance == null) { + public static synchronized Core getCore() { + if (getInstance().mExited) { // Can occur if the UI thread play a posted event but in the meantime the // LinphoneManager was destroyed // Ex: stop call and quickly terminate application. return null; } - return getLc(); + return getInstance().mCore; } - public static boolean isInstanciated() { - return sInstance != null; + /* End of static */ + + public MediaScanner getMediaScanner() { + return mMediaScanner; } - private void routeAudioToSpeakerHelper(boolean speakerOn) { - Log.w( - "[Manager] Routing audio to " - + (speakerOn ? "speaker" : "earpiece") - + ", disabling bluetooth audio route"); - BluetoothManager.getInstance().disableBluetoothSCO(); - - enableSpeaker(speakerOn); + public synchronized void destroy() { + mExited = true; + destroyManager(); } - public boolean isSpeakerEnabled() { - return mAudioManager != null && mAudioManager.isSpeakerphoneOn(); + public void restartCore() { + mCore.stop(); + mCore.start(); } - public void enableSpeaker(boolean enable) { - mAudioManager.setSpeakerphoneOn(enable); - } - - private void initOpenH264DownloadHelper() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { - Log.i("[Manager] Android >= 5.1 we disable the download of OpenH264"); - OpenH264DownloadHelper.setOpenH264DownloadEnabled(false); - return; - } - - mCodecDownloader = Factory.instance().createOpenH264DownloadHelper(getContext()); - mCodecListener = - new OpenH264DownloadHelperListener() { - ProgressDialog progress; - final int ctxt = 0; - - @Override - public void OnProgress(final int current, final int max) { - mHandler.post( - new Runnable() { - @Override - public void run() { - OpenH264DownloadHelper ohcodec = - LinphoneManager.getInstance() - .getOpenH264DownloadHelper(); - if (progress == null) { - progress = - new ProgressDialog( - (Context) ohcodec.getUserData(ctxt)); - progress.setCanceledOnTouchOutside(false); - progress.setCancelable(false); - progress.setProgressStyle( - ProgressDialog.STYLE_HORIZONTAL); - } else if (current <= max) { - progress.setMessage( - getString( - R.string - .assistant_openh264_downloading)); - progress.setMax(max); - progress.setProgress(current); - progress.show(); - } else { - progress.dismiss(); - progress = null; - /*if (Build.VERSION.SDK_INT - >= Build.VERSION_CODES.LOLLIPOP_MR1) { - LinphoneManager.getLc() - .reloadMsPlugins( - AssistantActivity.instance() - .getApplicationInfo() - .nativeLibraryDir); - AssistantActivity.instance().endDownloadCodec(); - } else { - // We need to restart due to bad android linker - AssistantActivity.instance().restartApplication(); - }*/ - } - } - }); - } - - @Override - public void OnError(final String error) { - mHandler.post( - new Runnable() { - @Override - public void run() { - if (progress != null) progress.dismiss(); - AlertDialog.Builder builder = - new AlertDialog.Builder( - (Context) - LinphoneManager.getInstance() - .getOpenH264DownloadHelper() - .getUserData(ctxt)); - builder.setMessage( - getString(R.string.assistant_openh264_error)); - builder.setCancelable(false); - builder.setNeutralButton(getString(R.string.ok), null); - builder.show(); - } - }); - } - }; - mCodecDownloader.setOpenH264HelperListener(mCodecListener); - } - - public OpenH264DownloadHelperListener getOpenH264HelperListener() { - return mCodecListener; - } - - public OpenH264DownloadHelper getOpenH264DownloadHelper() { - return mCodecDownloader; - } - - public void routeAudioToSpeaker() { - routeAudioToSpeakerHelper(true); - } - - public void routeAudioToReceiver() { - routeAudioToSpeakerHelper(false); - } - - private boolean isPresenceModelActivitySet() { - Core lc = getLcIfManagerNotDestroyedOrNull(); - if (isInstanciated() && lc != null) { - return lc.getPresenceModel() != null && lc.getPresenceModel().getActivity() != null; - } - return false; - } - - public void changeStatusToOnline() { - Core lc = getLcIfManagerNotDestroyedOrNull(); - if (lc == null) return; - PresenceModel model = lc.createPresenceModel(); - model.setBasicStatus(PresenceBasicStatus.Open); - lc.setPresenceModel(model); - } - - public void changeStatusToOnThePhone() { - Core lc = getLcIfManagerNotDestroyedOrNull(); - if (lc == null) return; - - if (isInstanciated() - && isPresenceModelActivitySet() - && lc.getPresenceModel().getActivity().getType() - != PresenceActivity.Type.OnThePhone) { - lc.getPresenceModel().getActivity().setType(PresenceActivity.Type.OnThePhone); - } else if (isInstanciated() && !isPresenceModelActivitySet()) { - PresenceModel model = - lc.createPresenceModelWithActivity(PresenceActivity.Type.OnThePhone, null); - lc.setPresenceModel(model); - } - } - - private void changeStatusToOffline() { - Core lc = getLcIfManagerNotDestroyedOrNull(); - if (isInstanciated() && lc != null) { - PresenceModel model = lc.getPresenceModel(); - model.setBasicStatus(PresenceBasicStatus.Closed); - lc.setPresenceModel(model); - } - } - - public void subscribeFriendList(boolean enabled) { - Core lc = getLcIfManagerNotDestroyedOrNull(); - if (lc != null && lc.getFriendsLists() != null && lc.getFriendsLists().length > 0) { - FriendList friendList = (lc.getFriendsLists())[0]; - Log.i("[Manager] Presence list subscription is " + (enabled ? "enabled" : "disabled")); - friendList.enableSubscriptions(enabled); - } - } - - public void newOutgoingCall(AddressType address) { - String to = address.getText().toString(); - newOutgoingCall(to, address.getDisplayedName()); - } - - public void newOutgoingCall(Address to) { - if (to == null) return; - - ProxyConfig lpc = mCore.getDefaultProxyConfig(); - if (mRessources.getBoolean(R.bool.forbid_self_call) - && lpc != null - && to.weakEqual(lpc.getIdentityAddress())) { - return; - } - - boolean isLowBandwidthConnection = - !LinphoneUtils.isHighBandwidthConnection( - LinphoneService.instance().getApplicationContext()); - - if (mCore.isNetworkReachable()) { - if (Version.isVideoCapable()) { - boolean prefVideoEnable = mPrefs.isVideoEnabled(); - boolean prefInitiateWithVideo = mPrefs.shouldInitiateVideoCall(); - CallManager.getInstance() - .inviteAddress( - to, - prefVideoEnable && prefInitiateWithVideo, - isLowBandwidthConnection); - } else { - CallManager.getInstance().inviteAddress(to, false, isLowBandwidthConnection); - } - } else if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance() - .displayCustomToast( - getString(R.string.error_network_unreachable), Toast.LENGTH_LONG); - } else { - Log.e("[Manager] Error: " + getString(R.string.error_network_unreachable)); - } - } - - public void newOutgoingCall(String to, String displayName) { - // If to is only a username, try to find the contact to get an alias if existing - if (!to.startsWith("sip:") || !to.contains("@")) { - LinphoneContact contact = ContactsManager.getInstance().findContactFromPhoneNumber(to); - if (contact != null) { - String alias = contact.getContactFromPresenceModelForUriOrTel(to); - if (alias != null) { - to = alias; - } - } - } - - Address lAddress; - lAddress = mCore.interpretUrl(to); // InterpretUrl does normalizePhoneNumber - if (lAddress == null) { - Log.e("[Manager] Couldn't convert to String to Address : " + to); - return; - } - - if (displayName != null) lAddress.setDisplayName(displayName); - - newOutgoingCall(lAddress); - } - - private void resetCameraFromPreferences() { - boolean useFrontCam = mPrefs.useFrontCam(); - int camId = 0; - AndroidCamera[] cameras = AndroidCameraConfiguration.retrieveCameras(); - for (AndroidCamera androidCamera : cameras) { - if (androidCamera.frontFacing == useFrontCam) { - camId = androidCamera.id; - break; - } - } - String[] devices = getLc().getVideoDevicesList(); - if (camId >= devices.length) { - Log.e( - "[Manager] Trying to use a camera id that's higher than the linphone's devices list, using 0 to prevent crash..."); - camId = 0; - } - String newDevice = devices[camId]; - LinphoneManager.getLc().setVideoDevice(newDevice); - } - - private void enableCamera(Call call, boolean enable) { - if (call != null) { - call.enableCamera(enable); - if (mServiceContext.getResources().getBoolean(R.bool.enable_call_notification)) - LinphoneService.instance() - .getNotificationManager() - .displayCallNotification(mCore.getCurrentCall()); - } - } - - public void playDtmf(ContentResolver r, char dtmf) { - try { - if (Settings.System.getInt(r, Settings.System.DTMF_TONE_WHEN_DIALING) == 0) { - // audible touch disabled: don't play on speaker, only send in outgoing stream - return; - } - } catch (SettingNotFoundException e) { - Log.e("[Manager] playDtmf exception: " + e); - } - - getLc().playDtmf(dtmf, -1); - } - - private void terminateCall() { - if (mCore.inCall()) { - mCore.terminateCall(mCore.getCurrentCall()); - } - } - - public void initTunnelFromConf() { - if (!mCore.tunnelAvailable()) return; - - NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); - Tunnel tunnel = mCore.getTunnel(); - tunnel.cleanServers(); - TunnelConfig config = mPrefs.getTunnelConfig(); - if (config.getHost() != null) { - tunnel.addServer(config); - manageTunnelServer(info); - } - } - - private boolean isTunnelNeeded(NetworkInfo info) { - if (info == null) { - Log.i("[Manager] No connectivity: tunnel should be disabled"); - return false; - } - - String pref = mPrefs.getTunnelMode(); - - if (getString(R.string.tunnel_mode_entry_value_always).equals(pref)) { - return true; - } - - if (info.getType() != ConnectivityManager.TYPE_WIFI - && getString(R.string.tunnel_mode_entry_value_3G_only).equals(pref)) { - Log.i("[Manager] Need tunnel: 'no wifi' connection"); - return true; - } - - return false; - } - - private void manageTunnelServer(NetworkInfo info) { - if (mCore == null) return; - if (!mCore.tunnelAvailable()) return; - Tunnel tunnel = mCore.getTunnel(); - - Log.i("[Manager] Managing tunnel"); - if (isTunnelNeeded(info)) { - Log.i("[Manager] Tunnel need to be activated"); - tunnel.setMode(Tunnel.Mode.Enable); - } else { - Log.i("[Manager] Tunnel should not be used"); - String pref = mPrefs.getTunnelMode(); - tunnel.setMode(Tunnel.Mode.Disable); - if (getString(R.string.tunnel_mode_entry_value_auto).equals(pref)) { - tunnel.setMode(Tunnel.Mode.Auto); - } - } - } - - private synchronized void destroyCore() { + private void destroyCore() { Log.w("[Manager] Destroying Core"); - sExited = true; - ContactsManagerDestroy(); - BluetoothManagerDestroy(); + if (LinphonePreferences.instance() != null) { + // We set network reachable at false before destroy LC to not send register with expires + // at 0 + if (LinphonePreferences.instance().isPushNotificationEnabled()) { + Log.w( + "[Manager] Setting network reachability to False to prevent unregister and allow incoming push notifications"); + mCore.setNetworkReachable(false); + } + } + mCore.stop(); + mCore.removeListener(mCoreListener); + } + + private synchronized void destroyManager() { + Log.w("[Manager] Destroying Manager"); + changeStatusToOffline(); + + mCallManager.destroy(); + mMediaScanner.destroy(); + mAudioManager.destroy(); + try { mTimer.cancel(); - destroyLinphoneCore(); + destroyCore(); } catch (RuntimeException e) { Log.e("[Manager] Destroy Core Runtime Exception: " + e); } finally { @@ -676,21 +425,19 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou } catch (Exception e) { Log.e("[Manager] unregister receiver exception: " + e); } + mCore = null; } } - public void restartCore() { - mCore.stop(); - mCore.start(); - } - - private synchronized void startLibLinphone(Context c, boolean isPush) { + public synchronized void startLibLinphone(boolean isPush) { try { copyAssetsFromPackage(); // traces alway start with traces enable to not missed first initialization - mCore = Factory.instance().createCore(configFile, mLinphoneFactoryConfigFile, c); - mCore.addListener(this); + mCore = + Factory.instance() + .createCore(mConfigFile, mLinphoneFactoryConfigFile, mServiceContext); + mCore.addListener(mCoreListener); if (isPush) { Log.w( "[Manager] We are here because of a received push notification, enter background mode before starting the Core"); @@ -718,14 +465,14 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou } catch (Exception e) { Log.e(e, "[Manager] Cannot start linphone"); } + + // H264 codec Management - set to auto mode -> MediaCodec >= android 5.0 >= OpenH264 + H264Helper.setH264Mode(H264Helper.MODE_AUTO, mCore); } - private void initPushNotificationsService() { - PushNotificationUtils.init(mServiceContext); - } - - private synchronized void initLiblinphone(Core lc) { - mCore = lc; + private synchronized void initLiblinphone(Core core) { + mCore = core; + mAudioManager = new AndroidAudioManager(mServiceContext); mCore.setZrtpSecretsFile(mBasePath + "/zrtp_secrets"); @@ -780,10 +527,11 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou } if (mServiceContext.getResources().getBoolean(R.bool.enable_push_id)) { - initPushNotificationsService(); + PushNotificationUtils.init(mServiceContext); } - mCallIntentFilter = new IntentFilter("android.intent.action.ACTION_NEW_OUTGOING_CALL"); + IntentFilter mCallIntentFilter = + new IntentFilter("android.intent.action.ACTION_NEW_OUTGOING_CALL"); mCallIntentFilter.setPriority(99999999); mCallReceiver = new OutgoingCallReceiver(); try { @@ -796,707 +544,50 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, mServiceContext.getPackageName() + ";manager_proximity_sensor"); - mHookIntentFilter = new IntentFilter("com.base.module.phone.HOOKEVENT"); + IntentFilter mHookIntentFilter = new IntentFilter("com.base.module.phone.HOOKEVENT"); mHookIntentFilter.setPriority(999); mHookReceiver = new HookReceiver(); mServiceContext.registerReceiver(mHookReceiver, mHookIntentFilter); resetCameraFromPreferences(); - mAccountCreator = - LinphoneManager.getLc() - .createAccountCreator(LinphonePreferences.instance().getXmlrpcUrl()); - mAccountCreator.setListener(this); + mAccountCreator = mCore.createAccountCreator(LinphonePreferences.instance().getXmlrpcUrl()); + mAccountCreator.setListener(mAccountCreatorListener); mCallGsmON = false; - - updateMissedChatCount(); } - public void setHandsetMode(Boolean on) { - if (mCore.isIncomingInvitePending() && on) { - mHandsetON = true; - acceptCall(mCore.getCurrentCall()); - LinphoneActivity.instance().startIncallActivity(); - } else if (on && CallActivity.isInstanciated()) { - mHandsetON = true; - CallActivity.instance().setSpeakerEnabled(true); - CallActivity.instance().refreshInCallActions(); - } else if (!on) { - mHandsetON = false; - LinphoneManager.getInstance().terminateCall(); - } - } - - public boolean isHansetModeOn() { - return mHandsetON; - } - - private void copyAssetsFromPackage() throws IOException { - copyIfNotExist(R.raw.linphonerc_default, configFile); - copyFromPackage(R.raw.linphonerc_factory, new File(mLinphoneFactoryConfigFile).getName()); - copyIfNotExist(R.raw.lpconfig, mLPConfigXsd); - copyFromPackage( - R.raw.default_assistant_create, new File(mDefaultDynamicConfigFile).getName()); - copyFromPackage( - R.raw.linphone_assistant_create, new File(mLinphoneDynamicConfigFile).getName()); - } - - private void copyIfNotExist(int ressourceId, String target) throws IOException { - File lFileToCopy = new File(target); - if (!lFileToCopy.exists()) { - copyFromPackage(ressourceId, lFileToCopy.getName()); - } - } - - private void copyFromPackage(int ressourceId, String target) throws IOException { - FileOutputStream lOutputStream = mServiceContext.openFileOutput(target, 0); - InputStream lInputStream = mRessources.openRawResource(ressourceId); - int readByte; - byte[] buff = new byte[8048]; - while ((readByte = lInputStream.read(buff)) != -1) { - lOutputStream.write(buff, 0, readByte); - } - lOutputStream.flush(); - lOutputStream.close(); - lInputStream.close(); - } - - private void destroyLinphoneCore() { - if (LinphonePreferences.instance() != null) { - // We set network reachable at false before destroy LC to not send register with expires - // at 0 - if (LinphonePreferences.instance().isPushNotificationEnabled()) { - Log.w( - "[Manager] Setting network reachability to False to prevent unregister and allow incoming push notifications"); - mCore.setNetworkReachable(false); - } - } - mCore.stop(); - } - - public void enableProximitySensing(boolean enable) { - if (enable) { - if (!mProximitySensingEnabled) { - mSensorManager.registerListener( - this, mProximity, SensorManager.SENSOR_DELAY_NORMAL); - mProximitySensingEnabled = true; - } - } else { - if (mProximitySensingEnabled) { - mSensorManager.unregisterListener(this); - mProximitySensingEnabled = false; - // Don't forgeting to release wakelock if held - if (mProximityWakelock.isHeld()) { - mProximityWakelock.release(); - } - } - } - } - - @Override - public void onSensorChanged(SensorEvent event) { - if (event.timestamp == 0) return; - if (isProximitySensorNearby(event)) { - if (!mProximityWakelock.isHeld()) { - mProximityWakelock.acquire(); - } - } else { - if (mProximityWakelock.isHeld()) { - mProximityWakelock.release(); - } - } - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) {} - - public MediaScanner getMediaScanner() { - return mMediaScanner; - } - - private String getString(int key) { - return mRessources.getString(key); - } - - public void onNewSubscriptionRequested(Core lc, Friend lf, String url) {} - - public void onNotifyPresenceReceived(Core lc, Friend lf) {} - - @Override - public void onEcCalibrationAudioInit(Core lc) {} - - @Override - public void onDtmfReceived(Core lc, Call call, int dtmf) { - Log.d("[Manager] DTMF received: " + dtmf); - } - - @Override - public void onMessageReceived(Core lc, final ChatRoom cr, final ChatMessage message) { - if (mServiceContext.getResources().getBoolean(R.bool.disable_chat)) { - return; - } - - if (mCurrentChatRoomAddress != null - && cr.getPeerAddress() - .asStringUriOnly() - .equals(mCurrentChatRoomAddress.asStringUriOnly())) { - Log.i( - "[Manager] Message received for currently displayed chat room, do not make a notification"); - return; - } - - if (message.getErrorInfo() != null - && message.getErrorInfo().getReason() == Reason.UnsupportedContent) { - Log.w("[Manager] Message received but content is unsupported, do not notify it"); - return; - } - - if (!message.hasTextContent() && message.getFileTransferInformation() == null) { - Log.w( - "[Manager] Message has no text or file transfer information to display, ignoring it..."); - return; - } - - increaseUnreadCountForChatRoom(cr); - - if (mServiceContext.getResources().getBoolean(R.bool.disable_chat_message_notification) - || message.isOutgoing()) { - return; - } - - final Address from = message.getFromAddress(); - final LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(from); - final String textMessage = - (message.hasTextContent()) - ? message.getTextContent() - : getString(R.string.content_description_incoming_file); - - String file = null; - for (Content c : message.getContents()) { - if (c.isFile()) { - file = c.getFilePath(); - getMediaScanner() - .scanFile( - new File(file), - new MediaScannerListener() { - @Override - public void onMediaScanned(String path, Uri uri) { - createNotification( - cr, - contact, - from, - textMessage, - message.getTime(), - uri, - FileUtils.getMimeFromFile(path)); - } - }); + private void resetCameraFromPreferences() { + boolean useFrontCam = mPrefs.useFrontCam(); + int camId = 0; + AndroidCamera[] cameras = AndroidCameraConfiguration.retrieveCameras(); + for (AndroidCamera androidCamera : cameras) { + if (androidCamera.frontFacing == useFrontCam) { + camId = androidCamera.id; break; } } - - if (file == null) { - createNotification(cr, contact, from, textMessage, message.getTime(), null, null); + String[] devices = mCore.getVideoDevicesList(); + if (camId >= devices.length) { + Log.e( + "[Manager] Trying to use a camera id that's higher than the linphone's devices list, using 0 to prevent crash..."); + camId = 0; } + String newDevice = devices[camId]; + mCore.setVideoDevice(newDevice); } - private void createNotification( - ChatRoom cr, - LinphoneContact contact, - Address from, - String textMessage, - long time, - Uri file, - String mime) { - if (cr.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { - if (contact != null) { - LinphoneService.instance() - .getNotificationManager() - .displayMessageNotification( - cr.getPeerAddress().asStringUriOnly(), - contact.getFullName(), - contact.getThumbnailUri(), - textMessage, - cr.getLocalAddress(), - time, - file, - mime); - } else { - LinphoneService.instance() - .getNotificationManager() - .displayMessageNotification( - cr.getPeerAddress().asStringUriOnly(), - from.getUsername(), - null, - textMessage, - cr.getLocalAddress(), - time, - file, - mime); - } - } else { - String subject = cr.getSubject(); - if (contact != null) { - LinphoneService.instance() - .getNotificationManager() - .displayGroupChatMessageNotification( - subject, - cr.getPeerAddress().asStringUriOnly(), - contact.getFullName(), - contact.getThumbnailUri(), - textMessage, - cr.getLocalAddress(), - time, - file, - mime); - } else { - LinphoneService.instance() - .getNotificationManager() - .displayGroupChatMessageNotification( - subject, - cr.getPeerAddress().asStringUriOnly(), - from.getUsername(), - null, - textMessage, - cr.getLocalAddress(), - time, - file, - mime); - } - } - } - - public void setCurrentChatRoomAddress(Address address) { - mCurrentChatRoomAddress = address; - LinphoneService.instance() - .setCurrentlyDisplayedChatRoom(address != null ? address.asStringUriOnly() : null); - } - - @Override - public void onEcCalibrationResult(Core lc, EcCalibratorStatus status, int delay_ms) { - ((AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE)) - .setMode(AudioManager.MODE_NORMAL); - mAudioManager.abandonAudioFocus(null); - Log.i("[Manager] Set audio mode on 'Normal'"); - } - - public void onGlobalStateChanged(final Core lc, final GlobalState state, final String message) { - Log.i("New global state [", state, "]"); - if (state == GlobalState.On) { - try { - initLiblinphone(lc); - } catch (IllegalArgumentException iae) { - Log.e("[Manager] Global State Changed Illegal Argument Exception: " + iae); - } - } - } - - public void onRegistrationStateChanged( - final Core lc, - final ProxyConfig proxy, - final RegistrationState state, - final String message) { - Log.i("[Manager] New registration state [" + state + "]"); - - if (state == RegistrationState.Failed) { - ConnectivityManager connectivityManager = - (ConnectivityManager) - mServiceContext.getSystemService(Context.CONNECTIVITY_SERVICE); - - NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); - Log.i("[Manager] Active network type: " + activeNetworkInfo.getTypeName()); - if (activeNetworkInfo.isAvailable() && activeNetworkInfo.isConnected()) { - Log.i("[Manager] Active network is available"); - } - Log.i( - "[Manager] Active network reason and extra info: " - + activeNetworkInfo.getReason() - + " / " - + activeNetworkInfo.getExtraInfo()); - Log.i( - "[Manager] Active network state " - + activeNetworkInfo.getState() - + " / " - + activeNetworkInfo.getDetailedState()); - } - } - - public Context getContext() { - try { - if (LinphoneActivity.isInstanciated()) return LinphoneActivity.instance(); - else if (CallActivity.isInstanciated()) return CallActivity.instance(); - else if (CallIncomingActivity.isInstanciated()) return CallIncomingActivity.instance(); - else if (mServiceContext != null) return mServiceContext; - else if (LinphoneService.isReady()) - return LinphoneService.instance().getApplicationContext(); - } catch (Exception e) { - Log.e(e); - } - return null; - } - - public void setAudioManagerModeNormal() { - mAudioManager.setMode(AudioManager.MODE_NORMAL); - } - - private void setAudioManagerInCallMode() { - if (mAudioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) { - Log.w("[Manager][AudioManager] already in MODE_IN_COMMUNICATION, skipping..."); - return; - } - Log.d("[Manager][AudioManager] Mode: MODE_IN_COMMUNICATION"); - - mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); - } - - @SuppressLint("Wakelock") - public void onCallStateChanged( - final Core lc, final Call call, final State state, final String message) { - Log.i("[Manager] New call state [", state, "]"); - if (state == State.IncomingReceived && !call.equals(lc.getCurrentCall())) { - if (call.getReplacedCall() != null) { - // attended transfer - // it will be accepted automatically. - return; - } - } - - if ((state == State.IncomingReceived || state == State.IncomingEarlyMedia) - && getCallGsmON()) { - if (mCore != null) { - mCore.declineCall(call, Reason.Busy); - } - } else if (state == State.IncomingReceived - && (LinphonePreferences.instance().isAutoAnswerEnabled()) - && !getCallGsmON()) { - TimerTask lTask = - new TimerTask() { - @Override - public void run() { - if (mCore != null) { - if (mCore.getCallsNb() > 0) { - acceptCall(call); - if (LinphoneManager.getInstance() != null) { - LinphoneManager.getInstance().routeAudioToReceiver(); - if (LinphoneActivity.instance() != null) - LinphoneActivity.instance().startIncallActivity(); - } - } - } - } - }; - mTimer = new Timer("Auto answer"); - mTimer.schedule(lTask, mPrefs.getAutoAnswerTime()); - } else if (state == State.IncomingReceived - || (state == State.IncomingEarlyMedia - && mRessources.getBoolean(R.bool.allow_ringing_while_early_media))) { - // Brighten screen for at least 10 seconds - if (mCore.getCallsNb() == 1) { - requestAudioFocus(STREAM_RING); - - mRingingCall = call; - startRinging(); - // otherwise there is the beep - } - } else if (call == mRingingCall && mIsRinging) { - // previous state was ringing, so stop ringing - stopRinging(); - } - - if (state == State.Connected) { - if (mCore.getCallsNb() == 1) { - // It is for incoming calls, because outgoing calls enter MODE_IN_COMMUNICATION - // immediately when they start. - // However, incoming call first use the MODE_RINGING to play the local ring. - if (call.getDir() == Call.Dir.Incoming) { - setAudioManagerInCallMode(); - // mAudioManager.abandonAudioFocus(null); - requestAudioFocus(STREAM_VOICE_CALL); - } - } - - if (Hacks.needSoftvolume()) { - Log.w("[Manager] Using soft volume audio hack"); - adjustVolume(0); // Synchronize - } - } - - if (state == State.End || state == State.Error) { - if (mCore.getCallsNb() == 0) { - // Disabling proximity sensor - enableProximitySensing(false); - Context activity = getContext(); - if (mAudioFocused) { - int res = mAudioManager.abandonAudioFocus(null); - Log.d( - "[Manager] Audio focus released a bit later: " - + (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED - ? "Granted" - : "Denied")); - mAudioFocused = false; - } - if (activity != null) { - TelephonyManager tm = - (TelephonyManager) activity.getSystemService(Context.TELEPHONY_SERVICE); - if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) { - Log.d("[Manager] ---AudioManager: back to MODE_NORMAL"); - mAudioManager.setMode(AudioManager.MODE_NORMAL); - Log.d("[Manager] All call terminated, routing back to earpiece"); - routeAudioToReceiver(); - } - } - } - } - if (state == State.UpdatedByRemote) { - // If the correspondent proposes video while audio call - boolean remoteVideo = call.getRemoteParams().videoEnabled(); - boolean localVideo = call.getCurrentParams().videoEnabled(); - boolean autoAcceptCameraPolicy = - LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests(); - if (remoteVideo - && !localVideo - && !autoAcceptCameraPolicy - && LinphoneManager.getLc().getConference() == null) { - LinphoneManager.getLc().deferCallUpdate(call); - } - } - if (state == State.OutgoingInit) { - // Enter the MODE_IN_COMMUNICATION mode as soon as possible, so that ringback - // is heard normally in earpiece or bluetooth receiver. - setAudioManagerInCallMode(); - requestAudioFocus(STREAM_VOICE_CALL); - startBluetooth(); - } - - if (state == State.StreamsRunning) { - startBluetooth(); - setAudioManagerInCallMode(); - } - } - - private void startBluetooth() { - if (BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) { - BluetoothManager.getInstance().routeAudioToBluetooth(); - } - } - - public void onCallStatsUpdated(final Core lc, final Call call, final CallStats stats) {} - - @Override - public void onChatRoomStateChanged(Core lc, ChatRoom cr, ChatRoom.State state) {} - - @Override - public void onQrcodeFound(Core lc, String result) {} - - public void onCallEncryptionChanged( - Core lc, Call call, boolean encrypted, String authenticationToken) {} - - public void startEcCalibration() { - routeAudioToSpeaker(); - setAudioManagerInCallMode(); - Log.i("[Manager] Set audio mode on 'Voice Communication'"); - requestAudioFocus(STREAM_VOICE_CALL); - int oldVolume = mAudioManager.getStreamVolume(STREAM_VOICE_CALL); - int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL); - mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0); - mCore.startEchoCancellerCalibration(); - mAudioManager.setStreamVolume(STREAM_VOICE_CALL, oldVolume, 0); - } - - public int startEchoTester() { - routeAudioToSpeaker(); - setAudioManagerInCallMode(); - Log.i("[Manager] Set audio mode on 'Voice Communication'"); - requestAudioFocus(STREAM_VOICE_CALL); - int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL); - int sampleRate; - mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0); - String sampleRateProperty = - mAudioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); - sampleRate = Integer.parseInt(sampleRateProperty); - mCore.startEchoTester(sampleRate); - mEchoTesterIsRunning = true; - return 1; - } - - public int stopEchoTester() { - mEchoTesterIsRunning = false; - mCore.stopEchoTester(); - routeAudioToReceiver(); - ((AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE)) - .setMode(AudioManager.MODE_NORMAL); - Log.i("[Manager] Set audio mode on 'Normal'"); - return 1; // status; - } - - public boolean getEchoTesterStatus() { - return mEchoTesterIsRunning; - } - - private void requestAudioFocus(int stream) { - if (!mAudioFocused) { - int res = - mAudioManager.requestAudioFocus( - null, stream, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE); - Log.d( - "[Manager] Audio focus requested: " - + (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED - ? "Granted" - : "Denied")); - if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) mAudioFocused = true; - } - } - - public void enableDeviceRingtone(boolean use) { - if (use) { - mCore.setRing(null); - } else { - mCore.setRing(mRingSoundFile); - } - } - - private synchronized void startRinging() { - if (!LinphonePreferences.instance().isDeviceRingtoneEnabled()) { - // Enable speaker audio route, linphone library will do the ringing itself automatically - routeAudioToSpeaker(); - return; - } - - if (mRessources.getBoolean(R.bool.allow_ringing_while_early_media)) { - routeAudioToSpeaker(); // Need to be able to ear the ringtone during the early media - } - - // if (Hacks.needGalaxySAudioHack()) - mAudioManager.setMode(MODE_RINGTONE); - - try { - if ((mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE - || mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) - && mVibrator != null - && LinphonePreferences.instance().isIncomingCallVibrationEnabled()) { - long[] patern = {0, 1000, 1000}; - mVibrator.vibrate(patern, 1); - } - if (mRingerPlayer == null) { - requestAudioFocus(STREAM_RING); - mRingerPlayer = new MediaPlayer(); - mRingerPlayer.setAudioStreamType(STREAM_RING); - - String ringtone = - LinphonePreferences.instance() - .getRingtone(Settings.System.DEFAULT_RINGTONE_URI.toString()); - try { - if (ringtone.startsWith("content://")) { - mRingerPlayer.setDataSource(mServiceContext, Uri.parse(ringtone)); - } else { - FileInputStream fis = new FileInputStream(ringtone); - mRingerPlayer.setDataSource(fis.getFD()); - fis.close(); - } - } catch (IOException e) { - Log.e(e, "[Manager] Cannot set ringtone"); - } - - mRingerPlayer.prepare(); - mRingerPlayer.setLooping(true); - mRingerPlayer.start(); - } else { - Log.w("[Manager] Already ringing"); - } - } catch (Exception e) { - Log.e(e, "[Manager] Cannot handle incoming call"); - } - mIsRinging = true; - } - - private synchronized void stopRinging() { - if (mRingerPlayer != null) { - mRingerPlayer.stop(); - mRingerPlayer.release(); - mRingerPlayer = null; - } - if (mVibrator != null) { - mVibrator.cancel(); - } - - if (Hacks.needGalaxySAudioHack()) mAudioManager.setMode(AudioManager.MODE_NORMAL); - - mIsRinging = false; - // You may need to call galaxys audio hack after this method - if (!BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) { - if (mServiceContext.getResources().getBoolean(R.bool.isTablet)) { - Log.d("[Manager] Stopped ringing, routing back to speaker"); - routeAudioToSpeaker(); - } else { - Log.d("[Manager] Stopped ringing, routing back to earpiece"); - routeAudioToReceiver(); - } - } - } - - /** @return false if already in video call. */ - public boolean addVideo() { - Call call = mCore.getCurrentCall(); - enableCamera(call, true); - return reinviteWithVideo(); - } - - public boolean acceptCall(Call call) { - if (call == null) return false; - - CallParams params = LinphoneManager.getLc().createCallParams(call); - - boolean isLowBandwidthConnection = - !LinphoneUtils.isHighBandwidthConnection( - LinphoneService.instance().getApplicationContext()); - - if (params != null) { - params.enableLowBandwidth(isLowBandwidthConnection); - params.setRecordFile( - FileUtils.getCallRecordingFilename(getContext(), call.getRemoteAddress())); - } else { - Log.e("[Manager] Could not create call params for call"); - return false; - } - - mCore.acceptCallWithParams(call, params); - return true; - } - - public void adjustVolume(int i) { - // starting from ICS, volume must be adjusted by the application, at least for - // STREAM_VOICE_CALL volume stream - mAudioManager.adjustStreamVolume( - LINPHONE_VOLUME_STREAM, - i < 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_RAISE, - AudioManager.FLAG_SHOW_UI); - } + /* Account linking */ public void isAccountWithAlias() { - if (!LinphonePreferences.instance().isLinkPopupEnabled()) return; - - if (LinphoneManager.getLc().getDefaultProxyConfig() != null) { - + if (mCore.getDefaultProxyConfig() != null) { long now = new Timestamp(new Date().getTime()).getTime(); - if (LinphonePreferences.instance().getLinkPopupTime() != null - && Long.parseLong(LinphonePreferences.instance().getLinkPopupTime()) >= now) - return; - - long future = - new Timestamp( - LinphoneActivity.instance() - .getResources() - .getInteger(R.integer.popup_time_interval)) - .getTime(); - long newDate = now + future; - - if (mAccountCreator != null) { + if (mAccountCreator != null && LinphonePreferences.instance().getLinkPopupTime() == null + || Long.parseLong(LinphonePreferences.instance().getLinkPopupTime()) < now) { mAccountCreator.setUsername( LinphonePreferences.instance() .getAccountUsername( LinphonePreferences.instance().getDefaultAccountIndex())); mAccountCreator.isAccountExist(); - LinphonePreferences.instance().setLinkPopupTime(String.valueOf(newDate)); } } else { LinphonePreferences.instance().setLinkPopupTime(null); @@ -1512,7 +603,7 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou long future = new Timestamp( - LinphoneActivity.instance() + mServiceContext .getResources() .getInteger( R.integer.phone_number_linking_popup_time_interval)) @@ -1522,14 +613,13 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou LinphonePreferences.instance().setLinkPopupTime(String.valueOf(newDate)); final Dialog dialog = - LinphoneActivity.instance() - .displayDialog( - String.format( - getString(R.string.link_account_popup), - LinphoneManager.getLc() - .getDefaultProxyConfig() - .getIdentityAddress() - .asStringUriOnly())); + LinphoneUtils.getDialog( + mServiceContext, + String.format( + getString(R.string.link_account_popup), + mCore.getDefaultProxyConfig() + .getIdentityAddress() + .asStringUriOnly())); Button delete = dialog.findViewById(R.id.dialog_delete_button); delete.setVisibility(View.GONE); Button ok = dialog.findViewById(R.id.dialog_ok_button); @@ -1555,8 +645,7 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou public void onClick(View view) { Intent assistant = new Intent(); assistant.setClass( - LinphoneActivity.instance(), - PhoneAccountLinkingAssistantActivity.class); + mServiceContext, PhoneAccountLinkingAssistantActivity.class); mServiceContext.startActivity(assistant); dialog.dismiss(); } @@ -1575,6 +664,215 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou dialog.show(); } + /* Assets stuff */ + + private void copyAssetsFromPackage() throws IOException { + copyIfNotExist(R.raw.linphonerc_default, mConfigFile); + copyFromPackage(R.raw.linphonerc_factory, new File(mLinphoneFactoryConfigFile).getName()); + copyIfNotExist(R.raw.lpconfig, mLPConfigXsd); + copyFromPackage( + R.raw.default_assistant_create, new File(mDefaultDynamicConfigFile).getName()); + copyFromPackage( + R.raw.linphone_assistant_create, new File(mLinphoneDynamicConfigFile).getName()); + } + + private void copyIfNotExist(int ressourceId, String target) throws IOException { + File lFileToCopy = new File(target); + if (!lFileToCopy.exists()) { + copyFromPackage(ressourceId, lFileToCopy.getName()); + } + } + + private void copyFromPackage(int ressourceId, String target) throws IOException { + FileOutputStream lOutputStream = mServiceContext.openFileOutput(target, 0); + InputStream lInputStream = mServiceContext.getResources().openRawResource(ressourceId); + int readByte; + byte[] buff = new byte[8048]; + while ((readByte = lInputStream.read(buff)) != -1) { + lOutputStream.write(buff, 0, readByte); + } + lOutputStream.flush(); + lOutputStream.close(); + lInputStream.close(); + } + + /* Presence stuff */ + + private boolean isPresenceModelActivitySet() { + if (mCore != null) { + return mCore.getPresenceModel() != null + && mCore.getPresenceModel().getActivity() != null; + } + return false; + } + + public void changeStatusToOnline() { + if (mCore == null) return; + PresenceModel model = mCore.createPresenceModel(); + model.setBasicStatus(PresenceBasicStatus.Open); + mCore.setPresenceModel(model); + } + + public void changeStatusToOnThePhone() { + if (mCore == null) return; + + if (isPresenceModelActivitySet() + && mCore.getPresenceModel().getActivity().getType() + != PresenceActivity.Type.OnThePhone) { + mCore.getPresenceModel().getActivity().setType(PresenceActivity.Type.OnThePhone); + } else if (!isPresenceModelActivitySet()) { + PresenceModel model = + mCore.createPresenceModelWithActivity(PresenceActivity.Type.OnThePhone, null); + mCore.setPresenceModel(model); + } + } + + private void changeStatusToOffline() { + if (mCore != null) { + PresenceModel model = mCore.getPresenceModel(); + model.setBasicStatus(PresenceBasicStatus.Closed); + mCore.setPresenceModel(model); + } + } + + /* Tunnel stuff */ + + public void initTunnelFromConf() { + if (!mCore.tunnelAvailable()) return; + + NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); + Tunnel tunnel = mCore.getTunnel(); + tunnel.cleanServers(); + TunnelConfig config = mPrefs.getTunnelConfig(); + if (config.getHost() != null) { + tunnel.addServer(config); + manageTunnelServer(info); + } + } + + private boolean isTunnelNeeded(NetworkInfo info) { + if (info == null) { + Log.i("[Manager] No connectivity: tunnel should be disabled"); + return false; + } + + String pref = mPrefs.getTunnelMode(); + + if (getString(R.string.tunnel_mode_entry_value_always).equals(pref)) { + return true; + } + + if (info.getType() != ConnectivityManager.TYPE_WIFI + && getString(R.string.tunnel_mode_entry_value_3G_only).equals(pref)) { + Log.i("[Manager] Need tunnel: 'no wifi' connection"); + return true; + } + + return false; + } + + private void manageTunnelServer(NetworkInfo info) { + if (mCore == null) return; + if (!mCore.tunnelAvailable()) return; + Tunnel tunnel = mCore.getTunnel(); + + Log.i("[Manager] Managing tunnel"); + if (isTunnelNeeded(info)) { + Log.i("[Manager] Tunnel need to be activated"); + tunnel.setMode(Tunnel.Mode.Enable); + } else { + Log.i("[Manager] Tunnel should not be used"); + String pref = mPrefs.getTunnelMode(); + tunnel.setMode(Tunnel.Mode.Disable); + if (getString(R.string.tunnel_mode_entry_value_auto).equals(pref)) { + tunnel.setMode(Tunnel.Mode.Auto); + } + } + } + + /* Proximity sensor stuff */ + + public void enableProximitySensing(boolean enable) { + if (enable) { + if (!mProximitySensingEnabled) { + mSensorManager.registerListener( + this, mProximity, SensorManager.SENSOR_DELAY_NORMAL); + mProximitySensingEnabled = true; + } + } else { + if (mProximitySensingEnabled) { + mSensorManager.unregisterListener(this); + mProximitySensingEnabled = false; + // Don't forgeting to release wakelock if held + if (mProximityWakelock.isHeld()) { + mProximityWakelock.release(); + } + } + } + } + + private Boolean isProximitySensorNearby(final SensorEvent event) { + float threshold = 4.001f; // <= 4 cm is near + + final float distanceInCm = event.values[0]; + final float maxDistance = event.sensor.getMaximumRange(); + Log.d( + "[Manager] Proximity sensor report [" + + distanceInCm + + "] , for max range [" + + maxDistance + + "]"); + + if (maxDistance <= threshold) { + // Case binary 0/1 and short sensors + threshold = maxDistance; + } + return distanceInCm < threshold; + } + + @Override + public void onSensorChanged(SensorEvent event) { + if (event.timestamp == 0) return; + if (isProximitySensorNearby(event)) { + if (!mProximityWakelock.isHeld()) { + mProximityWakelock.acquire(); + } + } else { + if (mProximityWakelock.isHeld()) { + mProximityWakelock.release(); + } + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) {} + + /* Other stuff */ + + public void checkForUpdate() { + String url = LinphonePreferences.instance().getCheckReleaseUrl(); + if (url != null && !url.isEmpty()) { + int lastTimestamp = LinphonePreferences.instance().getLastCheckReleaseTimestamp(); + int currentTimeStamp = (int) System.currentTimeMillis(); + int interval = + mServiceContext + .getResources() + .getInteger(R.integer.time_between_update_check); // 24h + if (lastTimestamp == 0 || currentTimeStamp - lastTimestamp >= interval) { + mCore.checkForUpdate(BuildConfig.VERSION_NAME); + LinphonePreferences.instance().setLastCheckReleaseTimestamp(currentTimeStamp); + } + } + } + + public void enableDeviceRingtone(boolean use) { + if (use) { + mCore.setRing(null); + } else { + mCore.setRing(mRingSoundFile); + } + } + public String getDefaultDynamicConfigFile() { return mDefaultDynamicConfigFile; } @@ -1583,6 +881,10 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou return mLinphoneDynamicConfigFile; } + public String getConfigFile() { + return mConfigFile; + } + public boolean getCallGsmON() { return mCallGsmON; } @@ -1591,293 +893,8 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou mCallGsmON = on; } - @Override - public void onTransferStateChanged(Core lc, Call call, State new_call_state) {} - - @Override - public void onInfoReceived(Core lc, Call call, InfoMessage info) { - Log.d("[Manager] Info message received from " + call.getRemoteAddress().asString()); - Content ct = info.getContent(); - if (ct != null) { - Log.d( - "[Manager] Info received with body with mime type " - + ct.getType() - + "/" - + ct.getSubtype() - + " and data [" - + ct.getStringBuffer() - + "]"); - } - } - - @Override - public void onSubscriptionStateChanged(Core lc, Event ev, SubscriptionState state) { - Log.d( - "[Manager] Subscription state changed to " - + state - + " event name is " - + ev.getName()); - } - - @Override - public void onCallLogUpdated(Core lc, CallLog newcl) {} - - @Override - public void onNotifyReceived(Core lc, Event ev, String eventName, Content content) { - Log.d("[Manager] Notify received for event " + eventName); - if (content != null) - Log.d( - "[Manager] With content " - + content.getType() - + "/" - + content.getSubtype() - + " data:" - + content.getStringBuffer()); - } - - @Override - public void onSubscribeReceived(Core lc, Event lev, String subscribeEvent, Content body) {} - - @Override - public void onPublishStateChanged(Core lc, Event ev, PublishState state) { - Log.d("[Manager] Publish state changed to " + state + " for event name " + ev.getName()); - } - - @Override - public void onIsComposingReceived(Core lc, ChatRoom cr) { - Log.d("[Manager] Composing received for chatroom " + cr.getPeerAddress().asStringUriOnly()); - } - - @Override - public void onMessageReceivedUnableDecrypt(Core lc, ChatRoom room, ChatMessage message) {} - - @Override - public void onConfiguringStatus(Core lc, ConfiguringState state, String message) { - Log.d("[Manager] Remote provisioning status = " + state.toString() + " (" + message + ")"); - - LinphonePreferences prefs = LinphonePreferences.instance(); - if (state == ConfiguringState.Successful) { - prefs.setPushNotificationEnabled(prefs.isPushNotificationEnabled()); - } - } - - @Override - public void onCallCreated(Core lc, Call call) {} - - @Override - public void onLogCollectionUploadProgressIndication(Core linphoneCore, int offset, int total) { - if (total > 0) - Log.d( - "[Manager] Log upload progress: currently uploaded = " - + offset - + " , total = " - + total - + ", % = " - + String.valueOf((offset * 100) / total)); - } - - @Override - public void onVersionUpdateCheckResultReceived( - Core lc, VersionUpdateCheckResult result, String version, String url) { - if (result == VersionUpdateCheckResult.NewVersionAvailable) { - final String urlToUse = url; - final String versionAv = version; - mHandler.postDelayed( - new Runnable() { - @Override - public void run() { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setMessage( - getString(R.string.update_available) + ": " + versionAv); - builder.setCancelable(false); - builder.setNeutralButton( - getString(R.string.ok), - new DialogInterface.OnClickListener() { - @Override - public void onClick( - DialogInterface dialogInterface, int i) { - if (urlToUse != null) { - Intent urlIntent = new Intent(Intent.ACTION_VIEW); - urlIntent.setData(Uri.parse(urlToUse)); - getContext().startActivity(urlIntent); - } - } - }); - builder.show(); - } - }, - 1000); - } - } - - @Override - public void onEcCalibrationAudioUninit(Core lc) {} - - private void sendLogs(String info) { - Context context = LinphoneActivity.instance(); - final String appName = context.getString(R.string.app_name); - - Intent i = new Intent(Intent.ACTION_SEND); - i.putExtra( - Intent.EXTRA_EMAIL, - new String[] {context.getString(R.string.about_bugreport_email)}); - i.putExtra(Intent.EXTRA_SUBJECT, appName + " Logs"); - i.putExtra(Intent.EXTRA_TEXT, info); - i.setType("application/zip"); - - try { - context.startActivity(Intent.createChooser(i, "Send mail...")); - } catch (android.content.ActivityNotFoundException ex) { - Log.e(ex); - } - } - - @Override - public void onLogCollectionUploadStateChanged( - Core linphoneCore, LogCollectionUploadState state, String info) { - Log.d("[Manager] Log upload state: " + state.toString() + ", info = " + info); - if (state == LogCollectionUploadState.Delivered) { - ClipboardManager clipboard = - (ClipboardManager) mServiceContext.getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("Logs url", info); - clipboard.setPrimaryClip(clip); - Toast.makeText( - LinphoneActivity.instance(), - getString(R.string.logs_url_copied_to_clipboard), - Toast.LENGTH_SHORT) - .show(); - sendLogs(info); - } - } - - @Override - public void onFriendListCreated(Core lc, FriendList list) { - if (LinphoneService.isReady()) { - list.addListener(ContactsManager.getInstance()); - } - } - - @Override - public void onFriendListRemoved(Core lc, FriendList list) { - list.removeListener(ContactsManager.getInstance()); - } - - @Override - public void onReferReceived(Core lc, String refer_to) {} - - @Override - public void onNetworkReachable(Core lc, boolean enable) {} - - @Override - public void onAuthenticationRequested(Core lc, AuthInfo authInfo, AuthMethod method) { - // TODO Auto-generated method stub - - } - - @Override - public void onNotifyPresenceReceivedForUriOrTel( - Core lc, Friend lf, String uri_or_tel, PresenceModel presence_model) {} - - @Override - public void onBuddyInfoUpdated(Core lc, Friend lf) {} - - @Override - public void onIsAccountExist( - AccountCreator accountCreator, AccountCreator.Status status, String resp) { - if (status.equals(AccountCreator.Status.AccountExist)) { - accountCreator.isAccountLinked(); - } - } - - @Override - public void onCreateAccount( - AccountCreator accountCreator, AccountCreator.Status status, String resp) {} - - @Override - public void onActivateAccount( - AccountCreator accountCreator, AccountCreator.Status status, String resp) {} - - @Override - public void onLinkAccount( - AccountCreator accountCreator, AccountCreator.Status status, String resp) { - if (status.equals(AccountCreator.Status.AccountNotLinked)) { - askLinkWithPhoneNumber(); - } - } - - @Override - public void onActivateAlias( - AccountCreator accountCreator, AccountCreator.Status status, String resp) {} - - @Override - public void onIsAccountActivated( - AccountCreator accountCreator, AccountCreator.Status status, String resp) {} - - @Override - public void onRecoverAccount( - AccountCreator accountCreator, AccountCreator.Status status, String resp) {} - - @Override - public void onIsAccountLinked( - AccountCreator accountCreator, AccountCreator.Status status, String resp) { - if (status.equals(AccountCreator.Status.AccountNotLinked)) { - askLinkWithPhoneNumber(); - } - } - - @Override - public void onIsAliasUsed( - AccountCreator accountCreator, AccountCreator.Status status, String resp) {} - - @Override - public void onUpdateAccount( - AccountCreator accountCreator, AccountCreator.Status status, String resp) {} - - private void updateMissedChatCount() { - for (ChatRoom cr : LinphoneManager.getLc().getChatRooms()) { - updateUnreadCountForChatRoom(cr, cr.getUnreadMessagesCount()); - } - } - - public int getUnreadMessageCount() { - int count = 0; - for (ChatRoom room : mCore.getChatRooms()) { - count += room.getUnreadMessagesCount(); - } - return count; - } - - public void updateUnreadCountForChatRoom( - String localSipUri, String remoteSipUri, Integer value) { - String key = localSipUri + "//" + remoteSipUri; - mUnreadChatsPerRoom.put(key, value); - } - - public void updateUnreadCountForChatRoom(ChatRoom cr, Integer value) { - String localSipUri = cr.getLocalAddress().asStringUriOnly(); - String remoteSipUri = cr.getPeerAddress().asStringUriOnly(); - updateUnreadCountForChatRoom(localSipUri, remoteSipUri, value); - } - - private void increaseUnreadCountForChatRoom(ChatRoom cr) { - String localSipUri = cr.getLocalAddress().asStringUriOnly(); - String remoteSipUri = cr.getPeerAddress().asStringUriOnly(); - String key = localSipUri + "//" + remoteSipUri; - if (mUnreadChatsPerRoom.containsKey(key)) { - mUnreadChatsPerRoom.put(key, mUnreadChatsPerRoom.get(key) + 1); - } else { - mUnreadChatsPerRoom.put(key, 1); - } - } - - public interface AddressType { - CharSequence getText(); - - void setText(CharSequence s); - - String getDisplayedName(); - - void setDisplayedName(String s); + private String getString(int key) { + return mServiceContext.getString(key); } public boolean hasLastCallSasBeenRejected() { diff --git a/app/src/main/java/org/linphone/LinphoneService.java b/app/src/main/java/org/linphone/LinphoneService.java index 32dda0e91..e397e8949 100644 --- a/app/src/main/java/org/linphone/LinphoneService.java +++ b/app/src/main/java/org/linphone/LinphoneService.java @@ -2,7 +2,7 @@ package org.linphone; /* LinphoneService.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -26,13 +26,12 @@ import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; -import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.provider.ContactsContract; import android.view.WindowManager; -import java.util.ArrayList; import org.linphone.call.CallIncomingActivity; +import org.linphone.call.CallOutgoingActivity; import org.linphone.contacts.ContactsManager; import org.linphone.core.Call; import org.linphone.core.Call.State; @@ -50,6 +49,7 @@ import org.linphone.mediastream.Version; import org.linphone.notifications.NotificationsManager; import org.linphone.receivers.BluetoothManager; import org.linphone.settings.LinphonePreferences; +import org.linphone.utils.ActivityMonitor; import org.linphone.utils.LinphoneUtils; import org.linphone.views.LinphoneGL2JNIViewOverlay; import org.linphone.views.LinphoneOverlay; @@ -67,25 +67,15 @@ import org.linphone.views.LinphoneTextureViewOverlay; *

  • Delegating GUI state change actions to GUI listener */ public final class LinphoneService extends Service { - /* Listener needs to be implemented in the Service as it calls - * setLatestEventInfo and startActivity() which needs a context. - */ private static final String START_LINPHONE_LOGS = " ==== Phone information dump ===="; - private static LinphoneService sInstance; public final Handler handler = new Handler(); - - private boolean mTestDelayElapsed = true; - private CoreListenerStub mListener; - private WindowManager mWindowManager; private LinphoneOverlay mOverlay; + private WindowManager mWindowManager; private Application.ActivityLifecycleCallbacks mActivityCallbacks; - private NotificationsManager mNotificationManager; - private String mIncomingReceivedActivityName; - private Class mIncomingReceivedActivity = CallIncomingActivity.class; - private LoggingServiceListener mJavaLoggingService = + private final LoggingServiceListener mJavaLoggingService = new LoggingServiceListener() { @Override public void onLogMessageWritten( @@ -110,57 +100,88 @@ public final class LinphoneService extends Service { } } }; + private CoreListenerStub mListener; + private NotificationsManager mNotificationManager; + private LinphoneManager mLinphoneManager; + private ContactsManager mContactsManager; + private BluetoothManager mBluetoothManager; - public LoggingServiceListener getJavaLoggingService() { - return mJavaLoggingService; - } + private Class mIncomingReceivedActivity = CallIncomingActivity.class; - public static boolean isReady() { - return sInstance != null && sInstance.mTestDelayElapsed; - } + @SuppressWarnings("unchecked") + @Override + public void onCreate() { + super.onCreate(); - public static LinphoneService instance() { - if (isReady()) return sInstance; + setupActivityMonitor(); - throw new RuntimeException("LinphoneService not instantiated yet"); - } - - public NotificationsManager getNotificationManager() { - return mNotificationManager; - } - - public void removeForegroundServiceNotificationIfPossible() { - mNotificationManager.removeForegroundServiceNotificationIfPossible(); - } - - public Class getIncomingReceivedActivity() { - return mIncomingReceivedActivity; - } - - public void setCurrentlyDisplayedChatRoom(String address) { - if (address != null) { - mNotificationManager.resetMessageNotifCount(address); + // Needed in order for the two next calls to succeed, libraries must have been loaded first + LinphonePreferences.instance().setContext(this); + Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); + boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled(); + LinphoneUtils.configureLoggingService(isDebugEnabled, getString(R.string.app_name)); + // LinphoneService isn't ready yet so we have to manually set up the Java logging service + if (LinphonePreferences.instance().useJavaLogger()) { + Factory.instance().getLoggingService().addListener(mJavaLoggingService); } - } - private void onBackgroundMode() { - Log.i("[Service] App has entered background mode"); - if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) { - LinphoneManager.getLcIfManagerNotDestroyedOrNull().enterBackground(); + // Dump some debugging information to the logs + Log.i(START_LINPHONE_LOGS); + dumpDeviceInformation(); + dumpInstalledLinphoneInformation(); + + String incomingReceivedActivityName = + LinphonePreferences.instance().getActivityToLaunchOnIncomingReceived(); + try { + mIncomingReceivedActivity = + (Class) Class.forName(incomingReceivedActivityName); + } catch (ClassNotFoundException e) { + Log.e(e); } - } - private void onForegroundMode() { - Log.i("[Service] App has left background mode"); - if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) { - LinphoneManager.getLcIfManagerNotDestroyedOrNull().enterForeground(); - } - } + mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); - private void setupActivityMonitor() { - if (mActivityCallbacks != null) return; - getApplication() - .registerActivityLifecycleCallbacks(mActivityCallbacks = new ActivityMonitor()); + mListener = + new CoreListenerStub() { + @Override + public void onCallStateChanged( + Core core, Call call, Call.State state, String message) { + if (sInstance == null) { + Log.i( + "[Service] Service not ready, discarding call state change to ", + state.toString()); + return; + } + + if (getResources().getBoolean(R.bool.enable_call_notification)) { + mNotificationManager.displayCallNotification(call); + } + + if (state == Call.State.IncomingReceived + || state == State.IncomingEarlyMedia) { + if (!mLinphoneManager.getCallGsmON()) onIncomingReceived(); + } else if (state == State.OutgoingInit) { + onOutgoingStarted(); + } else if (state == State.End + || state == State.Released + || state == State.Error) { + destroyOverlay(); + + if (state == State.Released + && call.getCallLog().getStatus() == Call.Status.Missed) { + mNotificationManager.displayMissedCallNotification(call); + } + } + } + + @Override + public void onGlobalStateChanged( + Core core, GlobalState state, String message) {} + + @Override + public void onRegistrationStateChanged( + Core core, ProxyConfig cfg, RegistrationState state, String smessage) {} + }; } @Override @@ -178,64 +199,12 @@ public final class LinphoneService extends Service { return START_STICKY; } - LinphoneManager.createAndStart(this, isPush); - + mLinphoneManager = new LinphoneManager(this); sInstance = this; // sInstance is ready once linphone manager has been created + mLinphoneManager.startLibLinphone(isPush); + LinphoneManager.getCore().addListener(mListener); + mNotificationManager = new NotificationsManager(this); - LinphoneManager.getLc() - .addListener( - mListener = - new CoreListenerStub() { - @Override - public void onCallStateChanged( - Core lc, Call call, Call.State state, String message) { - if (sInstance == null) { - Log.i( - "[Service] Service not ready, discarding call state change to ", - state.toString()); - return; - } - - if (getResources() - .getBoolean(R.bool.enable_call_notification)) { - mNotificationManager.displayCallNotification(call); - } - - if (state == Call.State.IncomingReceived - || state == State.IncomingEarlyMedia) { - if (!LinphoneManager.getInstance().getCallGsmON()) - onIncomingReceived(); - } - - if (state == State.End - || state == State.Released - || state == State.Error) { - destroyOverlay(); - } - - if (state == State.Released - && call.getCallLog().getStatus() - == Call.Status.Missed) { - mNotificationManager.displayMissedCallNotification( - call); - } - } - - @Override - public void onGlobalStateChanged( - Core lc, GlobalState state, String message) { - // TODO global state if ON - } - - @Override - public void onRegistrationStateChanged( - Core lc, - ProxyConfig cfg, - RegistrationState state, - String smessage) { - // TODO registration status - } - }); if (Version.sdkAboveOrEqual(Version.API26_O_80) && intent != null @@ -243,71 +212,114 @@ public final class LinphoneService extends Service { mNotificationManager.startForeground(); } + mContactsManager = new ContactsManager(this, handler); if (!Version.sdkAboveOrEqual(Version.API26_O_80) - || (ContactsManager.getInstance() != null - && ContactsManager.getInstance().hasReadContactsAccess())) { + || (mContactsManager.hasReadContactsAccess())) { getContentResolver() .registerContentObserver( - ContactsContract.Contacts.CONTENT_URI, - true, - ContactsManager.getInstance()); + ContactsContract.Contacts.CONTENT_URI, true, mContactsManager); } - if (!mTestDelayElapsed) { - // Only used when testing. Simulates a 5 seconds delay for launching service - handler.postDelayed( - new Runnable() { - @Override - public void run() { - mTestDelayElapsed = true; - } - }, - 5000); - } - - BluetoothManager.getInstance().initBluetooth(); + mBluetoothManager = new BluetoothManager(); return START_STICKY; } - @SuppressWarnings("unchecked") @Override - public void onCreate() { - super.onCreate(); + public void onTaskRemoved(Intent rootIntent) { + boolean serviceNotif = LinphonePreferences.instance().getServiceNotificationVisibility(); + if (serviceNotif) { + Log.i("[Service] Service is running in foreground, don't stop it"); + } else if (getResources().getBoolean(R.bool.kill_service_with_task_manager)) { + Log.i("[Service] Task removed, stop service"); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.terminateAllCalls(); + } - setupActivityMonitor(); + // If push is enabled, don't unregister account, otherwise do unregister + if (LinphonePreferences.instance().isPushNotificationEnabled()) { + if (core != null) core.setNetworkReachable(false); + } + stopSelf(); + } + super.onTaskRemoved(rootIntent); + } + + @SuppressWarnings("UnusedAssignment") + @Override + public synchronized void onDestroy() { + if (mActivityCallbacks != null) { + getApplication().unregisterActivityLifecycleCallbacks(mActivityCallbacks); + mActivityCallbacks = null; + } + destroyOverlay(); + + Core core = LinphoneManager.getCore(); + if (core != null) { + core.removeListener(mListener); + core = null; // To allow the gc calls below to free the Core + } + + mLinphoneManager.destroy(); + sInstance = null; + + // Make sure our notification is gone. + if (mNotificationManager != null) { + mNotificationManager.destroy(); + } + mContactsManager.destroy(); + mBluetoothManager.destroy(); - // Needed in order for the two next calls to succeed, libraries must have been loaded first - LinphonePreferences.instance().setContext(getBaseContext()); - Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); - boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled(); - LinphoneUtils.configureLoggingService(isDebugEnabled, getString(R.string.app_name)); - // LinphoneService isn't ready yet so we have to manually set up the Java logging service if (LinphonePreferences.instance().useJavaLogger()) { - Factory.instance().getLoggingService().addListener(mJavaLoggingService); + Factory.instance().getLoggingService().removeListener(mJavaLoggingService); } + LinphonePreferences.instance().destroy(); - // Dump some debugging information to the logs - Log.i(START_LINPHONE_LOGS); - dumpDeviceInformation(); - dumpInstalledLinphoneInformation(); + super.onDestroy(); + } - mIncomingReceivedActivityName = - LinphonePreferences.instance().getActivityToLaunchOnIncomingReceived(); - try { - mIncomingReceivedActivity = - (Class) Class.forName(mIncomingReceivedActivityName); - } catch (ClassNotFoundException e) { - Log.e(e); - } + @Override + public IBinder onBind(Intent intent) { + return null; + } - mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); + public static boolean isReady() { + return sInstance != null; + } + + public static LinphoneService instance() { + if (isReady()) return sInstance; + + throw new RuntimeException("LinphoneService not instantiated yet"); + } + + /* Managers accessors */ + + public LoggingServiceListener getJavaLoggingService() { + return mJavaLoggingService; + } + + public NotificationsManager getNotificationManager() { + return mNotificationManager; + } + + public LinphoneManager getLinphoneManager() { + return mLinphoneManager; + } + + public ContactsManager getContactsManager() { + return mContactsManager; + } + + public BluetoothManager getBluetoothManager() { + return mBluetoothManager; } public void createOverlay() { if (mOverlay != null) destroyOverlay(); - Core core = LinphoneManager.getLc(); + Core core = LinphoneManager.getCore(); Call call = core.getCurrentCall(); if (call == null || !call.getCurrentParams().videoEnabled()) return; @@ -330,6 +342,12 @@ public final class LinphoneService extends Service { mOverlay = null; } + private void setupActivityMonitor() { + if (mActivityCallbacks != null) return; + getApplication() + .registerActivityLifecycleCallbacks(mActivityCallbacks = new ActivityMonitor()); + } + private void dumpDeviceInformation() { StringBuilder sb = new StringBuilder(); sb.append("DEVICE=").append(Build.DEVICE).append("\n"); @@ -361,183 +379,17 @@ public final class LinphoneService extends Service { } } - @Override - public IBinder onBind(Intent intent) { - return null; - } - - @Override - public void onTaskRemoved(Intent rootIntent) { - boolean serviceNotif = LinphonePreferences.instance().getServiceNotificationVisibility(); - if (serviceNotif) { - Log.i("[Service] Service is running in foreground, don't stop it"); - } else if (getResources().getBoolean(R.bool.kill_service_with_task_manager)) { - Log.i("[Service] Task removed, stop service"); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.terminateAllCalls(); - } - - // If push is enabled, don't unregister account, otherwise do unregister - if (LinphonePreferences.instance().isPushNotificationEnabled()) { - if (lc != null) lc.setNetworkReachable(false); - } - stopSelf(); - } - super.onTaskRemoved(rootIntent); - } - - @Override - public synchronized void onDestroy() { - if (mActivityCallbacks != null) { - getApplication().unregisterActivityLifecycleCallbacks(mActivityCallbacks); - mActivityCallbacks = null; - } - destroyOverlay(); - - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.removeListener(mListener); - lc = null; // To allow the gc calls below to free the Core - } - - sInstance = null; - LinphoneManager.destroy(); - - // Make sure our notification is gone. - if (mNotificationManager != null) { - mNotificationManager.destroy(); - } - - // This will prevent the app from crashing if the service gets killed in background mode - if (LinphoneActivity.isInstanciated()) { - Log.w("[Service] Service is getting destroyed, finish LinphoneActivity"); - LinphoneActivity.instance().finish(); - } - - if (LinphonePreferences.instance().useJavaLogger()) { - Factory.instance().getLoggingService().removeListener(mJavaLoggingService); - } - - super.onDestroy(); - } - - @SuppressWarnings("unchecked") - public void setActivityToLaunchOnIncomingReceived(String activityName) { - try { - mIncomingReceivedActivity = (Class) Class.forName(activityName); - mIncomingReceivedActivityName = activityName; - LinphonePreferences.instance() - .setActivityToLaunchOnIncomingReceived(mIncomingReceivedActivityName); - } catch (ClassNotFoundException e) { - Log.e(e); - } - } - private void onIncomingReceived() { Intent intent = new Intent().setClass(this, mIncomingReceivedActivity); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().startActivity(intent); - } else { - // This flag is required to start an Activity from a Service context - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - } + // This flag is required to start an Activity from a Service context + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); } - /*Believe me or not, but knowing the application visibility state on Android is a nightmare. - After two days of hard work I ended with the following class, that does the job more or less reliabily. - */ - class ActivityMonitor implements Application.ActivityLifecycleCallbacks { - private final ArrayList activities = new ArrayList<>(); - private boolean mActive = false; - private int mRunningActivities = 0; - private InactivityChecker mLastChecker; - - @Override - public synchronized void onActivityCreated(Activity activity, Bundle savedInstanceState) { - Log.i("[Service] Activity created:" + activity); - if (!activities.contains(activity)) activities.add(activity); - } - - @Override - public void onActivityStarted(Activity activity) { - Log.i("Activity started:" + activity); - } - - @Override - public synchronized void onActivityResumed(Activity activity) { - Log.i("[Service] Activity resumed:" + activity); - if (activities.contains(activity)) { - mRunningActivities++; - Log.i("[Service] runningActivities=" + mRunningActivities); - checkActivity(); - } - } - - @Override - public synchronized void onActivityPaused(Activity activity) { - Log.i("[Service] Activity paused:" + activity); - if (activities.contains(activity)) { - mRunningActivities--; - Log.i("[Service] runningActivities=" + mRunningActivities); - checkActivity(); - } - } - - @Override - public void onActivityStopped(Activity activity) { - Log.i("[Service] Activity stopped:" + activity); - } - - @Override - public void onActivitySaveInstanceState(Activity activity, Bundle outState) {} - - @Override - public synchronized void onActivityDestroyed(Activity activity) { - Log.i("[Service] Activity destroyed:" + activity); - activities.remove(activity); - } - - void startInactivityChecker() { - if (mLastChecker != null) mLastChecker.cancel(); - LinphoneService.this.handler.postDelayed( - (mLastChecker = new InactivityChecker()), 2000); - } - - void checkActivity() { - if (mRunningActivities == 0) { - if (mActive) startInactivityChecker(); - } else if (mRunningActivities > 0) { - if (!mActive) { - mActive = true; - LinphoneService.this.onForegroundMode(); - } - if (mLastChecker != null) { - mLastChecker.cancel(); - mLastChecker = null; - } - } - } - - class InactivityChecker implements Runnable { - private boolean isCanceled; - - void cancel() { - isCanceled = true; - } - - @Override - public void run() { - synchronized (LinphoneService.this) { - if (!isCanceled) { - if (ActivityMonitor.this.mRunningActivities == 0 && mActive) { - mActive = false; - LinphoneService.this.onBackgroundMode(); - } - } - } - } - } + private void onOutgoingStarted() { + Intent intent = new Intent(LinphoneService.this, CallOutgoingActivity.class); + // This flag is required to start an Activity from a Service context + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); } } diff --git a/app/src/main/java/org/linphone/fragments/AboutFragment.java b/app/src/main/java/org/linphone/activities/AboutActivity.java similarity index 57% rename from app/src/main/java/org/linphone/fragments/AboutFragment.java rename to app/src/main/java/org/linphone/activities/AboutActivity.java index e67486b8e..6d45dfe93 100644 --- a/app/src/main/java/org/linphone/fragments/AboutFragment.java +++ b/app/src/main/java/org/linphone/activities/AboutActivity.java @@ -1,7 +1,8 @@ -package org.linphone.fragments; +package org.linphone.activities; + /* -AboutFragment.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +AboutActivity.java +Copyright (C) 2019 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 @@ -18,7 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import android.app.Fragment; import android.app.ProgressDialog; import android.content.Intent; import android.graphics.drawable.ColorDrawable; @@ -27,34 +27,43 @@ import android.net.Uri; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.WindowManager; +import android.widget.Button; +import android.widget.LinearLayout; import android.widget.TextView; import androidx.core.content.ContextCompat; import org.linphone.BuildConfig; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.core.Core; -import org.linphone.core.Core.LogCollectionUploadState; import org.linphone.core.CoreListenerStub; import org.linphone.settings.LinphonePreferences; -public class AboutFragment extends Fragment implements OnClickListener { - private View mSendLogButton = null; - private View mResetLogButton = null; +public class AboutActivity extends MainActivity { private CoreListenerStub mListener; private ProgressDialog mProgress; private boolean mUploadInProgress; @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.about, container, false); + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mOnBackPressGoHome = false; - TextView aboutVersion = view.findViewById(R.id.about_android_version); - TextView aboutLiblinphoneVersion = view.findViewById(R.id.about_liblinphone_sdk_version); + // Uses the fragment container layout to inflate the about view instead of using a fragment + View aboutView = LayoutInflater.from(this).inflate(R.layout.about, null, false); + LinearLayout fragmentContainer = findViewById(R.id.fragmentContainer); + LinearLayout.LayoutParams params = + new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + fragmentContainer.addView(aboutView, params); + + if (isTablet()) { + findViewById(R.id.fragmentContainer2).setVisibility(View.GONE); + } + + TextView aboutVersion = findViewById(R.id.about_android_version); + TextView aboutLiblinphoneVersion = findViewById(R.id.about_liblinphone_sdk_version); aboutLiblinphoneVersion.setText( String.format( getString(R.string.about_liblinphone_sdk_version), @@ -68,9 +77,9 @@ public class AboutFragment extends Fragment implements OnClickListener { getString(R.string.about_version), BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")")); - TextView privacyPolicy = view.findViewById(R.id.privacy_policy_link); + TextView privacyPolicy = findViewById(R.id.privacy_policy_link); privacyPolicy.setOnClickListener( - new OnClickListener() { + new View.OnClickListener() { @Override public void onClick(View v) { Intent browserIntent = @@ -81,9 +90,9 @@ public class AboutFragment extends Fragment implements OnClickListener { } }); - TextView license = view.findViewById(R.id.about_text); + TextView license = findViewById(R.id.about_text); license.setOnClickListener( - new OnClickListener() { + new View.OnClickListener() { @Override public void onClick(View v) { Intent browserIntent = @@ -94,36 +103,77 @@ public class AboutFragment extends Fragment implements OnClickListener { } }); - mSendLogButton = view.findViewById(R.id.send_log); - mSendLogButton.setOnClickListener(this); - mSendLogButton.setVisibility( + Button sendLogs = findViewById(R.id.send_log); + sendLogs.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Core core = LinphoneManager.getCore(); + if (core != null) { + core.uploadLogCollection(); + } + } + }); + sendLogs.setVisibility( LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE); - mResetLogButton = view.findViewById(R.id.reset_log); - mResetLogButton.setOnClickListener(this); - mResetLogButton.setVisibility( + Button resetLogs = findViewById(R.id.reset_log); + resetLogs.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Core core = LinphoneManager.getCore(); + if (core != null) { + core.resetLogCollection(); + } + } + }); + resetLogs.setVisibility( LinphonePreferences.instance().isDebugEnabled() ? View.VISIBLE : View.GONE); mListener = new CoreListenerStub() { @Override public void onLogCollectionUploadProgressIndication( - Core lc, int offset, int total) {} + Core core, int offset, int total) {} @Override public void onLogCollectionUploadStateChanged( - Core lc, LogCollectionUploadState state, String info) { - if (state == LogCollectionUploadState.InProgress) { + Core core, Core.LogCollectionUploadState state, String info) { + if (state == Core.LogCollectionUploadState.InProgress) { displayUploadLogsInProgress(); - } else if (state == LogCollectionUploadState.Delivered - || state == LogCollectionUploadState.NotDelivered) { + } else if (state == Core.LogCollectionUploadState.Delivered + || state == Core.LogCollectionUploadState.NotDelivered) { mUploadInProgress = false; if (mProgress != null) mProgress.dismiss(); } } }; + } - return view; + @Override + public void onPause() { + Core core = LinphoneManager.getCore(); + if (core != null) { + core.removeListener(mListener); + } + + super.onPause(); + } + + @Override + public void onResume() { + super.onResume(); + + showTopBarWithTitle(getString(R.string.about)); + if (getResources().getBoolean(R.bool.hide_bottom_bar_on_second_level_views)) { + hideTabBar(); + } + + Core core = LinphoneManager.getCore(); + if (core != null) { + core.addListener(mListener); + } } private void displayUploadLogsInProgress() { @@ -132,9 +182,8 @@ public class AboutFragment extends Fragment implements OnClickListener { } mUploadInProgress = true; - mProgress = ProgressDialog.show(LinphoneActivity.instance(), null, null); - Drawable d = - new ColorDrawable(ContextCompat.getColor(getActivity(), R.color.light_grey_color)); + mProgress = ProgressDialog.show(this, null, null); + Drawable d = new ColorDrawable(ContextCompat.getColor(this, R.color.light_grey_color)); d.setAlpha(200); mProgress .getWindow() @@ -145,44 +194,4 @@ public class AboutFragment extends Fragment implements OnClickListener { mProgress.setContentView(R.layout.wait_layout); mProgress.show(); } - - @Override - public void onPause() { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.removeListener(mListener); - } - - super.onPause(); - } - - @Override - public void onResume() { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.addListener(mListener); - } - - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.ABOUT); - } - - super.onResume(); - } - - @Override - public void onClick(View v) { - if (LinphoneActivity.isInstanciated()) { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (v == mSendLogButton) { - if (lc != null) { - lc.uploadLogCollection(); - } - } else if (v == mResetLogButton) { - if (lc != null) { - lc.resetLogCollection(); - } - } - } - } } diff --git a/app/src/main/java/org/linphone/activities/DialerActivity.java b/app/src/main/java/org/linphone/activities/DialerActivity.java new file mode 100644 index 000000000..70540b7cc --- /dev/null +++ b/app/src/main/java/org/linphone/activities/DialerActivity.java @@ -0,0 +1,282 @@ +package org.linphone.activities; + +/* +DialerActivity.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.Manifest; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import org.linphone.LinphoneManager; +import org.linphone.R; +import org.linphone.call.CallActivity; +import org.linphone.contacts.ContactsActivity; +import org.linphone.contacts.ContactsManager; +import org.linphone.core.Call; +import org.linphone.core.Core; +import org.linphone.core.CoreListenerStub; +import org.linphone.core.tools.Log; +import org.linphone.views.AddressAware; +import org.linphone.views.AddressText; +import org.linphone.views.CallButton; +import org.linphone.views.EraseButton; + +public class DialerActivity extends MainActivity implements AddressText.AddressChangedListener { + private static final String ACTION_CALL_LINPHONE = "org.linphone.intent.action.CallLaunched"; + + private AddressAware mNumpad; + private AddressText mAddress; + private CallButton mStartCall, mAddCall, mTransferCall; + private ImageView mAddContact, mBackToCall; + + private boolean mIsTransfer; + private CoreListenerStub mListener; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Uses the fragment container layout to inflate the dialer view instead of using a fragment + View dialerView = LayoutInflater.from(this).inflate(R.layout.dialer, null, false); + LinearLayout fragmentContainer = findViewById(R.id.fragmentContainer); + LinearLayout.LayoutParams params = + new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + fragmentContainer.addView(dialerView, params); + + if (isTablet()) { + findViewById(R.id.fragmentContainer2).setVisibility(View.GONE); + } + + mAddress = findViewById(R.id.address); + mAddress.setAddressListener(this); + + EraseButton erase = findViewById(R.id.erase); + erase.setAddressWidget(mAddress); + + mStartCall = findViewById(R.id.start_call); + mStartCall.setAddressWidget(mAddress); + mStartCall.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + LinphoneManager.getCallManager().newOutgoingCall(mAddress); + } + }); + + mAddCall = findViewById(R.id.add_call); + mAddCall.setAddressWidget(mAddress); + mAddCall.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + LinphoneManager.getCallManager().newOutgoingCall(mAddress); + } + }); + + mTransferCall = findViewById(R.id.transfer_call); + mTransferCall.setAddressWidget(mAddress); + mTransferCall.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Core core = LinphoneManager.getCore(); + if (core.getCurrentCall() == null) { + return; + } + core.transferCall(core.getCurrentCall(), mAddress.getText().toString()); + } + }); + + mNumpad = findViewById(R.id.numpad); + if (mNumpad != null) { + mNumpad.setAddressWidget(mAddress); + } + + mAddContact = findViewById(R.id.add_contact); + mAddContact.setEnabled(false); + mAddContact.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(DialerActivity.this, ContactsActivity.class); + intent.putExtra("EditOnClick", true); + intent.putExtra("SipAddress", mAddress.getText().toString()); + startActivity(intent); + } + }); + + mBackToCall = findViewById(R.id.back_to_call); + mBackToCall.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(DialerActivity.this, CallActivity.class)); + } + }); + + mIsTransfer = false; + if (getIntent() != null) { + mIsTransfer = getIntent().getBooleanExtra("Transfer", false); + mAddress.setText(getIntent().getStringExtra("SipUri")); + } + + mListener = + new CoreListenerStub() { + @Override + public void onCallStateChanged( + Core core, Call call, Call.State state, String message) { + updateLayout(); + } + }; + + // On dialer we ask for all permissions + mPermissionsToHave = + new String[] { + // This one is to allow floating notifications + Manifest.permission.SYSTEM_ALERT_WINDOW, + // Required starting Android 9 to be able to start a foreground service + "android.permission.FOREGROUND_SERVICE", + Manifest.permission.WRITE_CONTACTS, + Manifest.permission.READ_CONTACTS + }; + + handleIntentParams(getIntent()); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + handleIntentParams(intent); + } + + @Override + protected void onResume() { + super.onResume(); + + mDialerSelected.setVisibility(View.VISIBLE); + + Core core = LinphoneManager.getCore(); + if (core != null) { + core.addListener(mListener); + } + + boolean isOrientationLandscape = + getResources().getConfiguration().orientation + == Configuration.ORIENTATION_LANDSCAPE; + if (isOrientationLandscape && !isTablet()) { + ((LinearLayout) mNumpad).setVisibility(View.GONE); + } else { + ((LinearLayout) mNumpad).setVisibility(View.VISIBLE); + } + + updateLayout(); + } + + @Override + protected void onPause() { + super.onPause(); + + Core core = LinphoneManager.getCore(); + if (core != null) { + core.removeListener(mListener); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putSerializable("isTransfer", mIsTransfer); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + mIsTransfer = savedInstanceState.getBoolean("isTransfer"); + } + + @Override + public void onAddressChanged() { + Core core = LinphoneManager.getCore(); + mAddContact.setEnabled( + core != null && core.getCallsNb() > 0 || !mAddress.getText().toString().equals("")); + } + + private void updateLayout() { + Core core = LinphoneManager.getCore(); + if (core == null) { + return; + } + + boolean atLeastOneCall = core.getCallsNb() > 0; + mStartCall.setVisibility(atLeastOneCall ? View.GONE : View.VISIBLE); + mAddContact.setVisibility(atLeastOneCall ? View.GONE : View.VISIBLE); + if (!atLeastOneCall) { + if (core.getVideoActivationPolicy().getAutomaticallyInitiate()) { + mStartCall.setImageResource(R.drawable.call_video_start); + } else { + mStartCall.setImageResource(R.drawable.call_audio_start); + } + } + + mBackToCall.setVisibility(atLeastOneCall ? View.VISIBLE : View.GONE); + mAddCall.setVisibility(atLeastOneCall && !mIsTransfer ? View.VISIBLE : View.GONE); + mTransferCall.setVisibility(atLeastOneCall && mIsTransfer ? View.VISIBLE : View.GONE); + } + + private void handleIntentParams(Intent intent) { + if (intent == null) return; + + String action = intent.getAction(); + String addressToCall = null; + if (ACTION_CALL_LINPHONE.equals(action) + && (intent.getStringExtra("NumberToCall") != null)) { + String numberToCall = intent.getStringExtra("NumberToCall"); + Log.i("[Dialer] ACTION_CALL_LINPHONE with number: " + numberToCall); + LinphoneManager.getCallManager().newOutgoingCall(numberToCall, null); + } else if (Intent.ACTION_CALL.equals(action)) { + if (intent.getData() != null) { + addressToCall = intent.getData().toString(); + addressToCall = addressToCall.replace("%40", "@"); + addressToCall = addressToCall.replace("%3A", ":"); + if (addressToCall.startsWith("sip:")) { + addressToCall = addressToCall.substring("sip:".length()); + } else if (addressToCall.startsWith("tel:")) { + addressToCall = addressToCall.substring("tel:".length()); + } + Log.i("[Dialer] ACTION_CALL with number: " + addressToCall); + } + } else if (Intent.ACTION_VIEW.equals(action)) { + addressToCall = + ContactsManager.getInstance() + .getAddressOrNumberForAndroidContact( + getContentResolver(), intent.getData()); + Log.i("[Dialer] ACTION_VIEW with number: " + addressToCall); + } + + if (addressToCall != null) { + mAddress.setText(addressToCall); + } + } +} diff --git a/app/src/main/java/org/linphone/utils/LinphoneGenericActivity.java b/app/src/main/java/org/linphone/activities/LinphoneGenericActivity.java similarity index 69% rename from app/src/main/java/org/linphone/utils/LinphoneGenericActivity.java rename to app/src/main/java/org/linphone/activities/LinphoneGenericActivity.java index 73925d363..055741b8a 100644 --- a/app/src/main/java/org/linphone/utils/LinphoneGenericActivity.java +++ b/app/src/main/java/org/linphone/activities/LinphoneGenericActivity.java @@ -1,8 +1,8 @@ -package org.linphone.utils; +package org.linphone.activities; /* LinphoneGenericActivity.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -20,22 +20,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import android.os.Bundle; -import org.linphone.LinphoneLauncherActivity; -import org.linphone.LinphoneManager; import org.linphone.LinphoneService; -public class LinphoneGenericActivity extends ThemableActivity { - +public abstract class LinphoneGenericActivity extends ThemableActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - /*After a crash, Android restart the last Activity so we need to check - * if all dependencies are load - */ - if (!LinphoneService.isReady() || !LinphoneManager.isInstanciated()) { - finish(); + // After a crash, Android restart the last Activity so we need to check + // if all dependencies are loaded + if (!LinphoneService.isReady()) { startActivity(getIntent().setClass(this, LinphoneLauncherActivity.class)); + finish(); } } } diff --git a/app/src/main/java/org/linphone/LinphoneLauncherActivity.java b/app/src/main/java/org/linphone/activities/LinphoneLauncherActivity.java similarity index 66% rename from app/src/main/java/org/linphone/LinphoneLauncherActivity.java rename to app/src/main/java/org/linphone/activities/LinphoneLauncherActivity.java index 71d2a7629..99e4c889d 100644 --- a/app/src/main/java/org/linphone/LinphoneLauncherActivity.java +++ b/app/src/main/java/org/linphone/activities/LinphoneLauncherActivity.java @@ -1,8 +1,8 @@ -package org.linphone; +package org.linphone.activities; /* LinphoneLauncherActivity.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -19,44 +19,42 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import static android.content.Intent.ACTION_MAIN; - import android.app.Activity; import android.content.Intent; -import android.content.pm.ActivityInfo; import android.os.Bundle; import android.os.Handler; +import org.linphone.LinphoneManager; +import org.linphone.LinphoneService; +import org.linphone.R; import org.linphone.assistant.MenuAssistantActivity; +import org.linphone.chat.ChatActivity; import org.linphone.settings.LinphonePreferences; -/** Launch Linphone main activity when Service is ready. */ +/** Creates LinphoneService and wait until Core is ready to start main Activity */ public class LinphoneLauncherActivity extends Activity { - private Handler mHandler; - private ServiceWaitThread mServiceThread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // Hack to avoid to draw twice LinphoneActivity on tablets - if (getResources().getBoolean(R.bool.orientation_portrait_only)) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - } - if (getResources().getBoolean(R.bool.use_full_screen_image_splashscreen)) { - setContentView(R.layout.launch_screen_full_image); - } else { + + if (!getResources().getBoolean(R.bool.use_full_screen_image_splashscreen)) { setContentView(R.layout.launch_screen); - } + } // Otherwise use drawable/launch_screen layer list up until first activity starts mHandler = new Handler(); + } + + @Override + protected void onStart() { + super.onStart(); if (LinphoneService.isReady()) { onServiceReady(); } else { - // start linphone as background - startService(new Intent(ACTION_MAIN).setClass(this, LinphoneService.class)); - mServiceThread = new ServiceWaitThread(); - mServiceThread.start(); + startService( + new Intent().setClass(LinphoneLauncherActivity.this, LinphoneService.class)); + new ServiceWaitThread().start(); } } @@ -68,7 +66,16 @@ public class LinphoneLauncherActivity extends Activity { if (useFirstLoginActivity && LinphonePreferences.instance().isFirstLaunch()) { classToStart = MenuAssistantActivity.class; } else { - classToStart = LinphoneActivity.class; + if (getIntent().getExtras() != null + && "Chat".equals(getIntent().getExtras().getString("Activity", null))) { + classToStart = ChatActivity.class; + } else { + classToStart = DialerActivity.class; + } + } + + if (getResources().getBoolean(R.bool.check_for_update_when_app_starts)) { + LinphoneManager.getInstance().checkForUpdate(); } mHandler.postDelayed( @@ -80,10 +87,16 @@ public class LinphoneLauncherActivity extends Activity { if (getIntent() != null && getIntent().getExtras() != null) { intent.putExtras(getIntent().getExtras()); } + intent.setAction(getIntent().getAction()); + intent.setType(getIntent().getType()); startActivity(intent); + + LinphoneService.instance() + .getNotificationManager() + .removeForegroundServiceNotificationIfPossible(); } }, - 500); + 100); LinphoneManager.getInstance().changeStatusToOnline(); } @@ -104,7 +117,6 @@ public class LinphoneLauncherActivity extends Activity { onServiceReady(); } }); - mServiceThread = null; } } } diff --git a/app/src/main/java/org/linphone/activities/MainActivity.java b/app/src/main/java/org/linphone/activities/MainActivity.java new file mode 100644 index 000000000..e14826acd --- /dev/null +++ b/app/src/main/java/org/linphone/activities/MainActivity.java @@ -0,0 +1,687 @@ +package org.linphone.activities; + +/* +MainActivity.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.Manifest; +import android.app.ActivityManager; +import android.app.Dialog; +import android.app.Fragment; +import android.app.FragmentManager; +import android.app.FragmentTransaction; +import android.app.KeyguardManager; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; +import androidx.core.app.ActivityCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import java.util.ArrayList; +import org.linphone.LinphoneManager; +import org.linphone.LinphoneService; +import org.linphone.R; +import org.linphone.chat.ChatActivity; +import org.linphone.compatibility.Compatibility; +import org.linphone.contacts.ContactsActivity; +import org.linphone.contacts.ContactsManager; +import org.linphone.contacts.LinphoneContact; +import org.linphone.core.Address; +import org.linphone.core.AuthInfo; +import org.linphone.core.Call; +import org.linphone.core.ChatMessage; +import org.linphone.core.ChatRoom; +import org.linphone.core.Core; +import org.linphone.core.CoreListenerStub; +import org.linphone.core.ProxyConfig; +import org.linphone.core.RegistrationState; +import org.linphone.core.tools.Log; +import org.linphone.fragments.EmptyFragment; +import org.linphone.fragments.StatusFragment; +import org.linphone.history.HistoryActivity; +import org.linphone.menu.SideMenuFragment; +import org.linphone.settings.LinphonePreferences; +import org.linphone.settings.SettingsActivity; +import org.linphone.utils.DeviceUtils; +import org.linphone.utils.LinphoneUtils; +import org.linphone.utils.PushNotificationUtils; + +public abstract class MainActivity extends LinphoneGenericActivity + implements StatusFragment.MenuClikedListener, SideMenuFragment.QuitClikedListener { + private static final int MAIN_PERMISSIONS = 1; + private static final int FRAGMENT_SPECIFIC_PERMISSION = 2; + + private TextView mMissedCalls; + private TextView mMissedMessages; + protected View mContactsSelected; + protected View mHistorySelected; + View mDialerSelected; + protected View mChatSelected; + private LinearLayout mTopBar; + private TextView mTopBarTitle; + private LinearLayout mTabBar; + + private SideMenuFragment mSideMenuFragment; + private StatusFragment mStatusFragment; + + protected boolean mOnBackPressGoHome; + protected String[] mPermissionsToHave; + + private CoreListenerStub mListener; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.main); + + mOnBackPressGoHome = true; + + RelativeLayout history = findViewById(R.id.history); + history.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(MainActivity.this, HistoryActivity.class); + addFlagsToIntent(intent); + startActivity(intent); + } + }); + RelativeLayout contacts = findViewById(R.id.contacts); + contacts.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(MainActivity.this, ContactsActivity.class); + addFlagsToIntent(intent); + startActivity(intent); + } + }); + RelativeLayout dialer = findViewById(R.id.dialer); + dialer.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(MainActivity.this, DialerActivity.class); + addFlagsToIntent(intent); + startActivity(intent); + } + }); + RelativeLayout chat = findViewById(R.id.chat); + chat.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(MainActivity.this, ChatActivity.class); + addFlagsToIntent(intent); + startActivity(intent); + } + }); + + mMissedCalls = findViewById(R.id.missed_calls); + mMissedMessages = findViewById(R.id.missed_chats); + + mHistorySelected = findViewById(R.id.history_select); + mContactsSelected = findViewById(R.id.contacts_select); + mDialerSelected = findViewById(R.id.dialer_select); + mChatSelected = findViewById(R.id.chat_select); + + mTabBar = findViewById(R.id.footer); + mTopBar = findViewById(R.id.top_bar); + mTopBarTitle = findViewById(R.id.top_bar_title); + + ImageView back = findViewById(R.id.cancel); + back.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + goBack(); + } + }); + + mStatusFragment = + (StatusFragment) getFragmentManager().findFragmentById(R.id.status_fragment); + + DrawerLayout mSideMenu = findViewById(R.id.side_menu); + RelativeLayout mSideMenuContent = findViewById(R.id.side_menu_content); + mSideMenuFragment = + (SideMenuFragment) + getSupportFragmentManager().findFragmentById(R.id.side_menu_fragment); + mSideMenuFragment.setDrawer(mSideMenu, mSideMenuContent); + + if (getResources().getBoolean(R.bool.disable_chat)) { + chat.setVisibility(View.GONE); + } + + mListener = + new CoreListenerStub() { + @Override + public void onCallStateChanged( + Core core, Call call, Call.State state, String message) { + if (state == Call.State.End || state == Call.State.Released) { + displayMissedCalls(); + } + } + + @Override + public void onMessageReceived(Core core, ChatRoom room, ChatMessage message) { + displayMissedChats(); + } + + @Override + public void onChatRoomRead(Core core, ChatRoom room) { + displayMissedChats(); + } + + @Override + public void onMessageReceivedUnableDecrypt( + Core core, ChatRoom room, ChatMessage message) { + displayMissedChats(); + } + + @Override + public void onRegistrationStateChanged( + Core core, + ProxyConfig proxyConfig, + RegistrationState state, + String message) { + mSideMenuFragment.displayAccountsInSideMenu(); + + if (state == RegistrationState.Ok) { + // For push notifications to work on some devices, + // app must be in "protected mode" in battery settings... + // https://stackoverflow.com/questions/31638986/protected-apps-setting-on-huawei-phones-and-how-to-handle-it + DeviceUtils + .displayDialogIfDeviceHasPowerManagerThatCouldPreventPushNotifications( + MainActivity.this); + + if (getResources().getBoolean(R.bool.use_phone_number_validation)) { + AuthInfo authInfo = + core.findAuthInfo( + proxyConfig.getRealm(), + proxyConfig.getIdentityAddress().getUsername(), + proxyConfig.getDomain()); + if (authInfo != null + && authInfo.getDomain() + .equals(getString(R.string.default_domain))) { + LinphoneManager.getInstance().isAccountWithAlias(); + } + } + } + } + + @Override + public void onLogCollectionUploadStateChanged( + Core core, Core.LogCollectionUploadState state, String info) { + Log.d( + "[Main Activity] Log upload state: " + + state.toString() + + ", info = " + + info); + if (state == Core.LogCollectionUploadState.Delivered) { + ClipboardManager clipboard = + (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("Logs url", info); + clipboard.setPrimaryClip(clip); + Toast.makeText( + MainActivity.this, + getString(R.string.logs_url_copied_to_clipboard), + Toast.LENGTH_SHORT) + .show(); + shareUploadedLogsUrl(info); + } + } + }; + } + + @Override + protected void onStart() { + super.onStart(); + + requestRequiredPermissions(); + + if (checkPermission(Manifest.permission.READ_CONTACTS)) { + ContactsManager.getInstance().enableContactsAccess(); + } + ContactsManager.getInstance().initializeContactManager(); + + if (DeviceUtils.isAppUserRestricted(this)) { + Log.w( + "[Main Activity] Device has been restricted by user (Android 9+), push notifications won't work !"); + } + + int bucket = DeviceUtils.getAppStandbyBucket(this); + if (bucket > 0) { + Log.w( + "[Main Activity] Device is in bucket " + + Compatibility.getAppStandbyBucketNameFromValue(bucket)); + } + + if (!PushNotificationUtils.isAvailable(this)) { + Log.w("[Main Activity] Push notifications won't work !"); + } + } + + @Override + protected void onResume() { + super.onResume(); + + hideTopBar(); + showTabBar(); + + mHistorySelected.setVisibility(View.GONE); + mContactsSelected.setVisibility(View.GONE); + mDialerSelected.setVisibility(View.GONE); + mChatSelected.setVisibility(View.GONE); + + mStatusFragment.setMenuListener(this); + mSideMenuFragment.setQuitListener(this); + mSideMenuFragment.displayAccountsInSideMenu(); + + if (mSideMenuFragment.isOpened()) { + mSideMenuFragment.closeDrawer(); + } + + Core core = LinphoneManager.getCore(); + if (core != null) { + core.addListener(mListener); + displayMissedChats(); + displayMissedCalls(); + } + } + + @Override + protected void onPause() { + mStatusFragment.setMenuListener(null); + mSideMenuFragment.setQuitListener(null); + + Core core = LinphoneManager.getCore(); + if (core != null) { + core.removeListener(mListener); + } + + super.onPause(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + try { + super.onSaveInstanceState(outState); + } catch (IllegalStateException ise) { + // Do not log this exception + } + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + try { + super.onRestoreInstanceState(savedInstanceState); + } catch (IllegalStateException ise) { + // Do not log this exception + } + } + + @Override + public void onMenuCliked() { + if (mSideMenuFragment.isOpened()) { + mSideMenuFragment.openOrCloseSideMenu(false, true); + } else { + mSideMenuFragment.openOrCloseSideMenu(true, true); + } + } + + @Override + public void onQuitClicked() { + quit(); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + if (mOnBackPressGoHome) { + if (getFragmentManager().getBackStackEntryCount() == 0) { + goHomeAndClearStack(); + return true; + } + } + goBack(); + return true; + } + return super.onKeyDown(keyCode, event); + } + + public boolean popBackStack() { + if (getFragmentManager().getBackStackEntryCount() > 0) { + getFragmentManager().popBackStackImmediate(); + return true; + } + return false; + } + + public void goBack() { + finish(); + } + + protected boolean isTablet() { + return getResources().getBoolean(R.bool.isTablet); + } + + private void goHomeAndClearStack() { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(intent); + } + + private void quit() { + goHomeAndClearStack(); + stopService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class)); + ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + am.killBackgroundProcesses(getString(R.string.sync_account_type)); + android.os.Process.killProcess(android.os.Process.myPid()); + } + + // Tab, Top and Status bars + + public void hideStatusBar() { + findViewById(R.id.status_fragment).setVisibility(View.GONE); + } + + public void showStatusBar() { + findViewById(R.id.status_fragment).setVisibility(View.VISIBLE); + } + + public void hideTabBar() { + if (!isTablet()) { // do not hide if tablet, otherwise won't be able to navigate... + mTabBar.setVisibility(View.GONE); + } + } + + public void showTabBar() { + mTabBar.setVisibility(View.VISIBLE); + } + + protected void hideTopBar() { + mTopBar.setVisibility(View.GONE); + mTopBarTitle.setText(""); + } + + private void showTopBar() { + mTopBar.setVisibility(View.VISIBLE); + } + + protected void showTopBarWithTitle(String title) { + showTopBar(); + mTopBarTitle.setText(title); + } + + // Permissions + + private boolean checkPermission(String permission) { + int granted = getPackageManager().checkPermission(permission, getPackageName()); + Log.i( + "[Permission] " + + permission + + " permission is " + + (granted == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); + return granted == PackageManager.PERMISSION_GRANTED; + } + + public void requestPermissionIfNotGranted(String permission) { + if (!checkPermission(permission)) { + Log.i("[Permission] Requesting " + permission + " permission"); + + String[] permissions = new String[] {permission}; + KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); + boolean locked = km.inKeyguardRestrictedInputMode(); + if (!locked) { + // This is to workaround an infinite loop of pause/start in Activity issue + // if incoming call ends while screen if off and locked + ActivityCompat.requestPermissions(this, permissions, FRAGMENT_SPECIFIC_PERMISSION); + } + } + } + + public void requestPermissionsIfNotGranted(String[] perms) { + requestPermissionsIfNotGranted(perms, FRAGMENT_SPECIFIC_PERMISSION); + } + + private void requestPermissionsIfNotGranted(String[] perms, int resultCode) { + ArrayList permissionsToAskFor = new ArrayList<>(); + if (perms != null) { // This is created (or not) by the child activity + for (String permissionToHave : perms) { + if (!checkPermission(permissionToHave)) { + permissionsToAskFor.add(permissionToHave); + } + } + } + + if (permissionsToAskFor.size() > 0) { + for (String permission : permissionsToAskFor) { + Log.i("[Permission] Requesting " + permission + " permission"); + } + String[] permissions = new String[permissionsToAskFor.size()]; + permissions = permissionsToAskFor.toArray(permissions); + + KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); + boolean locked = km.inKeyguardRestrictedInputMode(); + if (!locked) { + // This is to workaround an infinite loop of pause/start in Activity issue + // if incoming call ends while screen if off and locked + ActivityCompat.requestPermissions(this, permissions, resultCode); + } + } + } + + private void requestRequiredPermissions() { + requestPermissionsIfNotGranted(mPermissionsToHave, MAIN_PERMISSIONS); + } + + @Override + public void onRequestPermissionsResult( + int requestCode, String[] permissions, int[] grantResults) { + if (permissions.length <= 0) return; + + for (int i = 0; i < permissions.length; i++) { + Log.i( + "[Permission] " + + permissions[i] + + " is " + + (grantResults[i] == PackageManager.PERMISSION_GRANTED + ? "granted" + : "denied")); + if (permissions[i].equals(Manifest.permission.READ_CONTACTS) + || permissions[i].equals(Manifest.permission.WRITE_CONTACTS)) { + if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + ContactsManager.getInstance().enableContactsAccess(); + } + } else if (permissions[i].equals(Manifest.permission.READ_EXTERNAL_STORAGE)) { + boolean enableRingtone = grantResults[i] == PackageManager.PERMISSION_GRANTED; + LinphonePreferences.instance().enableDeviceRingtone(enableRingtone); + LinphoneManager.getInstance().enableDeviceRingtone(enableRingtone); + } + } + } + + // Missed calls & chat indicators + + protected void displayMissedCalls() { + int count = 0; + Core core = LinphoneManager.getCore(); + if (core != null) { + count = core.getMissedCallsCount(); + } + + if (count > 0) { + mMissedCalls.setText(String.valueOf(count)); + mMissedCalls.setVisibility(View.VISIBLE); + } else { + mMissedCalls.clearAnimation(); + mMissedCalls.setVisibility(View.GONE); + } + } + + public void displayMissedChats() { + int count = 0; + Core core = LinphoneManager.getCore(); + if (core != null) { + count = core.getUnreadChatMessageCountFromActiveLocals(); + } + + if (count > 0) { + mMissedMessages.setText(String.valueOf(count)); + mMissedMessages.setVisibility(View.VISIBLE); + } else { + mMissedMessages.clearAnimation(); + mMissedMessages.setVisibility(View.GONE); + } + } + + // Navigation between actvities + + private void addFlagsToIntent(Intent intent) { + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + } + + protected void changeFragment(Fragment fragment, String name, boolean isChild) { + FragmentManager fragmentManager = getFragmentManager(); + FragmentTransaction transaction = fragmentManager.beginTransaction(); + if (transaction.isAddToBackStackAllowed()) { + int count = fragmentManager.getBackStackEntryCount(); + if (count > 0) { + FragmentManager.BackStackEntry entry = + fragmentManager.getBackStackEntryAt(count - 1); + if (entry != null && name.equals(entry.getName())) { + fragmentManager.popBackStack(); + if (!isChild) { + // We just removed it's duplicate from the back stack + // And we want at least one in it + transaction.addToBackStack(name); + } + } + } + + if (isChild) { + transaction.addToBackStack(name); + } + } + + Compatibility.setFragmentTransactionReorderingAllowed(transaction, false); + if (isChild && isTablet()) { + transaction.replace(R.id.fragmentContainer2, fragment, name); + findViewById(R.id.fragmentContainer2).setVisibility(View.VISIBLE); + } else { + transaction.replace(R.id.fragmentContainer, fragment, name); + } + transaction.commitAllowingStateLoss(); + fragmentManager.executePendingTransactions(); + } + + public void showEmptyChildFragment() { + changeFragment(new EmptyFragment(), "Empty", true); + } + + public void showAccountSettings(int accountIndex) { + Intent intent = new Intent(this, SettingsActivity.class); + addFlagsToIntent(intent); + intent.putExtra("Account", accountIndex); + startActivity(intent); + } + + public void showContactDetails(LinphoneContact contact) { + Intent intent = new Intent(this, ContactsActivity.class); + addFlagsToIntent(intent); + intent.putExtra("Contact", contact); + startActivity(intent); + } + + public void showContactsListForCreationOrEdition(Address address) { + if (address == null) return; + + Intent intent = new Intent(this, ContactsActivity.class); + addFlagsToIntent(intent); + intent.putExtra("CreateOrEdit", true); + intent.putExtra("SipUri", address.asStringUriOnly()); + if (address.getDisplayName() != null) { + intent.putExtra("DisplayName", address.getDisplayName()); + } + startActivity(intent); + } + + public void showChatRoom(Address localAddress, Address peerAddress) { + Intent intent = new Intent(this, ChatActivity.class); + addFlagsToIntent(intent); + if (localAddress != null) { + intent.putExtra("LocalSipUri", localAddress.asStringUriOnly()); + } + if (peerAddress != null) { + intent.putExtra("RemoteSipUri", peerAddress.asStringUriOnly()); + } + startActivity(intent); + } + + // Dialogs + + public Dialog displayDialog(String text) { + return LinphoneUtils.getDialog(this, text); + } + + public void displayChatRoomError() { + final Dialog dialog = displayDialog(getString(R.string.chat_room_creation_failed)); + dialog.findViewById(R.id.dialog_delete_button).setVisibility(View.GONE); + Button cancel = dialog.findViewById(R.id.dialog_cancel_button); + cancel.setText(getString(R.string.ok)); + cancel.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View view) { + dialog.dismiss(); + } + }); + + dialog.show(); + } + + // Logs + + private void shareUploadedLogsUrl(String info) { + final String appName = getString(R.string.app_name); + + Intent i = new Intent(Intent.ACTION_SEND); + i.putExtra(Intent.EXTRA_EMAIL, new String[] {getString(R.string.about_bugreport_email)}); + i.putExtra(Intent.EXTRA_SUBJECT, appName + " Logs"); + i.putExtra(Intent.EXTRA_TEXT, info); + i.setType("application/zip"); + + try { + startActivity(Intent.createChooser(i, "Send mail...")); + } catch (android.content.ActivityNotFoundException ex) { + Log.e(ex); + } + } +} diff --git a/app/src/main/java/org/linphone/activities/SplashScreenActivity.java b/app/src/main/java/org/linphone/activities/SplashScreenActivity.java new file mode 100644 index 000000000..dad916748 --- /dev/null +++ b/app/src/main/java/org/linphone/activities/SplashScreenActivity.java @@ -0,0 +1,72 @@ +package org.linphone.activities; + +/* +SplashScreenActivity.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import android.app.Activity; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.os.Bundle; +import android.os.Handler; +import org.linphone.R; + +/** + * This activity does pretty much nothing except starting the linphone launcher that will be + * starting the Service which takes time and will delay the splashscreen UI creation to later, and + * until that time it will display the default windowBackground. This activity will load faster, + * thus showing the splashscreen sooner. + */ +public class SplashScreenActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (getResources().getBoolean(R.bool.orientation_portrait_only)) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + + if (!getResources().getBoolean(R.bool.use_full_screen_image_splashscreen)) { + setContentView(R.layout.launch_screen); + } // Otherwise use drawable/launch_screen layer list up until first activity starts + } + + @Override + protected void onResume() { + super.onResume(); + // Start the linphone launcher asynchronously otherwise it will wait for launcher to be + // loaded which will render this workaround useless. + new Handler() + .postDelayed( + new Runnable() { + @Override + public void run() { + Intent intent = new Intent(); + intent.setClass( + SplashScreenActivity.this, LinphoneLauncherActivity.class); + if (getIntent() != null && getIntent().getExtras() != null) { + intent.putExtras(getIntent().getExtras()); + } + intent.setAction(getIntent().getAction()); + intent.setType(getIntent().getType()); + startActivity(intent); + } + }, + 100); + } +} diff --git a/app/src/main/java/org/linphone/utils/ThemableActivity.java b/app/src/main/java/org/linphone/activities/ThemableActivity.java similarity index 70% rename from app/src/main/java/org/linphone/utils/ThemableActivity.java rename to app/src/main/java/org/linphone/activities/ThemableActivity.java index 79e9caa3a..0494e4561 100644 --- a/app/src/main/java/org/linphone/utils/ThemableActivity.java +++ b/app/src/main/java/org/linphone/activities/ThemableActivity.java @@ -1,4 +1,4 @@ -package org.linphone.utils; +package org.linphone.activities; /* ThemableActivity.java @@ -25,11 +25,14 @@ import androidx.appcompat.app.AppCompatActivity; import org.linphone.R; import org.linphone.settings.LinphonePreferences; -public class ThemableActivity extends AppCompatActivity { +public abstract class ThemableActivity extends AppCompatActivity { + private int mTheme; @Override protected void onCreate(Bundle savedInstanceState) { + mTheme = R.style.LinphoneStyleLight; if (LinphonePreferences.instance().isDarkModeEnabled()) { + mTheme = R.style.LinphoneStyleDark; setTheme(R.style.LinphoneStyleDark); } @@ -39,4 +42,19 @@ public class ThemableActivity extends AppCompatActivity { super.onCreate(savedInstanceState); } + + @Override + protected void onResume() { + super.onResume(); + + if (LinphonePreferences.instance().isDarkModeEnabled()) { + if (mTheme != R.style.LinphoneStyleDark) { + recreate(); + } + } else { + if (mTheme != R.style.LinphoneStyleLight) { + recreate(); + } + } + } } diff --git a/app/src/main/java/org/linphone/assistant/AccountConnectionAssistantActivity.java b/app/src/main/java/org/linphone/assistant/AccountConnectionAssistantActivity.java index 14c338cfb..9d0399a94 100644 --- a/app/src/main/java/org/linphone/assistant/AccountConnectionAssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/AccountConnectionAssistantActivity.java @@ -42,7 +42,6 @@ public class AccountConnectionAssistantActivity extends AssistantActivity { private Switch mUsernameConnectionSwitch; private EditText mPrefix, mPhoneNumber, mUsername, mPassword; private TextView mCountryPicker, mError, mConnect; - private ImageView mPhoneNumberInfos; private AccountCreatorListenerStub mListener; @@ -157,8 +156,8 @@ public class AccountConnectionAssistantActivity extends AssistantActivity { } }); - mPhoneNumberInfos = findViewById(R.id.info_phone_number); - mPhoneNumberInfos.setOnClickListener( + ImageView phoneNumberInfos = findViewById(R.id.info_phone_number); + phoneNumberInfos.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/app/src/main/java/org/linphone/assistant/AssistantActivity.java b/app/src/main/java/org/linphone/assistant/AssistantActivity.java index 98e9ebc24..61e9f4bb0 100644 --- a/app/src/main/java/org/linphone/assistant/AssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/AssistantActivity.java @@ -27,9 +27,10 @@ import android.view.View; import android.view.WindowManager; import android.widget.EditText; import android.widget.ImageView; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; +import org.linphone.activities.DialerActivity; +import org.linphone.activities.ThemableActivity; import org.linphone.core.AccountCreator; import org.linphone.core.Core; import org.linphone.core.DialPlan; @@ -37,17 +38,15 @@ import org.linphone.core.Factory; import org.linphone.core.ProxyConfig; import org.linphone.core.tools.Log; import org.linphone.settings.LinphonePreferences; -import org.linphone.utils.ThemableActivity; public abstract class AssistantActivity extends ThemableActivity implements CountryPicker.CountryPickedListener { - protected static AccountCreator mAccountCreator; + static AccountCreator mAccountCreator; - protected View mTopBar, mStatusBar; - protected ImageView mBack; - protected AlertDialog mCountryPickerDialog; + ImageView mBack; + private AlertDialog mCountryPickerDialog; - protected CountryPicker mCountryPicker; + private CountryPicker mCountryPicker; @Override protected void onCreate(Bundle savedInstanceState) { @@ -55,7 +54,7 @@ public abstract class AssistantActivity extends ThemableActivity if (mAccountCreator == null) { String url = LinphonePreferences.instance().getXmlrpcUrl(); - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); core.loadConfigFromXml(LinphoneManager.getInstance().getDefaultDynamicConfigFile()); mAccountCreator = core.createAccountCreator(url); } @@ -67,14 +66,14 @@ public abstract class AssistantActivity extends ThemableActivity getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); - mStatusBar = findViewById(R.id.status); + View statusBar = findViewById(R.id.status); if (getResources().getBoolean(R.bool.assistant_hide_status_bar)) { - mStatusBar.setVisibility(View.GONE); + statusBar.setVisibility(View.GONE); } - mTopBar = findViewById(R.id.top_bar); + View topBar = findViewById(R.id.top_bar); if (getResources().getBoolean(R.bool.assistant_hide_top_bar)) { - mTopBar.setVisibility(View.GONE); + topBar.setVisibility(View.GONE); } mBack = findViewById(R.id.back); @@ -95,8 +94,8 @@ public abstract class AssistantActivity extends ThemableActivity } } - protected void createProxyConfigAndLeaveAssistant() { - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + void createProxyConfigAndLeaveAssistant() { + Core core = LinphoneManager.getCore(); boolean useLinphoneDefaultValues = getString(R.string.default_domain).equals(mAccountCreator.getDomain()); if (useLinphoneDefaultValues) { @@ -119,8 +118,9 @@ public abstract class AssistantActivity extends ThemableActivity } } - protected void goToLinphoneActivity() { - boolean needsEchoCalibration = LinphoneManager.getLc().isEchoCancellerCalibrationRequired(); + void goToLinphoneActivity() { + boolean needsEchoCalibration = + LinphoneManager.getCore().isEchoCancellerCalibrationRequired(); boolean echoCalibrationDone = LinphonePreferences.instance().isEchoCancellationCalibrationDone(); Log.i( @@ -144,14 +144,13 @@ public abstract class AssistantActivity extends ThemableActivity if (openH264 && abiSupported && androidVersionOk && !codecFound) { intent = new Intent(this, OpenH264DownloadAssistantActivity.class); } else {*/ - intent = new Intent(this, LinphoneActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + intent = new Intent(this, DialerActivity.class); // } } startActivity(intent); } - protected void showPhoneNumberDialog() { + void showPhoneNumberDialog() { new AlertDialog.Builder(this) .setTitle(getString(R.string.phone_number_info_title)) .setMessage( @@ -162,18 +161,18 @@ public abstract class AssistantActivity extends ThemableActivity .show(); } - protected void showAccountAlreadyExistsDialog() { + void showAccountAlreadyExistsDialog() { new AlertDialog.Builder(this) .setTitle(getString(R.string.account_already_exist)) .setMessage(getString(R.string.assistant_phone_number_unavailable)) .show(); } - protected void showGenericErrorDialog(AccountCreator.Status status) { + void showGenericErrorDialog(AccountCreator.Status status) { String message; switch (status) { - // TODO + // TODO handle other possible status case PhoneNumberInvalid: message = getString(R.string.phone_number_invalid); break; @@ -194,7 +193,7 @@ public abstract class AssistantActivity extends ThemableActivity .show(); } - protected void showCountryPickerDialog() { + void showCountryPickerDialog() { if (mCountryPicker == null) { mCountryPicker = new CountryPicker(this, this); } @@ -202,7 +201,7 @@ public abstract class AssistantActivity extends ThemableActivity new AlertDialog.Builder(this).setView(mCountryPicker.getView()).show(); } - protected DialPlan getDialPlanForCurrentCountry() { + DialPlan getDialPlanForCurrentCountry() { try { TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); String countryIso = tm.getNetworkCountryIso(); @@ -213,7 +212,7 @@ public abstract class AssistantActivity extends ThemableActivity return null; } - protected String getDevicePhoneNumber() { + String getDevicePhoneNumber() { try { TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); return tm.getLine1Number(); @@ -223,7 +222,7 @@ public abstract class AssistantActivity extends ThemableActivity return null; } - protected DialPlan getDialPlanFromPrefix(String prefix) { + DialPlan getDialPlanFromPrefix(String prefix) { if (prefix == null || prefix.isEmpty()) return null; for (DialPlan c : Factory.instance().getDialPlans()) { @@ -232,7 +231,7 @@ public abstract class AssistantActivity extends ThemableActivity return null; } - protected DialPlan getDialPlanFromCountryCode(String countryCode) { + private DialPlan getDialPlanFromCountryCode(String countryCode) { if (countryCode == null || countryCode.isEmpty()) return null; for (DialPlan c : Factory.instance().getDialPlans()) { @@ -241,7 +240,7 @@ public abstract class AssistantActivity extends ThemableActivity return null; } - protected int arePhoneNumberAndPrefixOk(EditText prefixEditText, EditText phoneNumberEditText) { + int arePhoneNumberAndPrefixOk(EditText prefixEditText, EditText phoneNumberEditText) { String prefix = prefixEditText.getText().toString(); if (prefix.startsWith("+")) { prefix = prefix.substring(1); @@ -251,7 +250,7 @@ public abstract class AssistantActivity extends ThemableActivity return mAccountCreator.setPhoneNumber(phoneNumber, prefix); } - protected String getErrorFromPhoneNumberStatus(int status) { + String getErrorFromPhoneNumberStatus(int status) { AccountCreator.PhoneNumberStatus phoneNumberStatus = AccountCreator.PhoneNumberStatus.fromInt(status); switch (phoneNumberStatus) { diff --git a/app/src/main/java/org/linphone/assistant/CountryAdapter.java b/app/src/main/java/org/linphone/assistant/CountryAdapter.java index cdde6614d..c5f24a57e 100644 --- a/app/src/main/java/org/linphone/assistant/CountryAdapter.java +++ b/app/src/main/java/org/linphone/assistant/CountryAdapter.java @@ -34,9 +34,9 @@ import org.linphone.R; import org.linphone.core.DialPlan; import org.linphone.core.Factory; -public class CountryAdapter extends BaseAdapter implements Filterable { - private Context mContext; - private LayoutInflater mInflater; +class CountryAdapter extends BaseAdapter implements Filterable { + private final Context mContext; + private final LayoutInflater mInflater; private final DialPlan[] mAllCountries; private List mFilteredCountries; diff --git a/app/src/main/java/org/linphone/assistant/CountryPicker.java b/app/src/main/java/org/linphone/assistant/CountryPicker.java index bfeb075db..4c979bfc3 100644 --- a/app/src/main/java/org/linphone/assistant/CountryPicker.java +++ b/app/src/main/java/org/linphone/assistant/CountryPicker.java @@ -31,28 +31,24 @@ import android.widget.ListView; import org.linphone.R; import org.linphone.core.DialPlan; -public class CountryPicker { - private Context mContext; - private LayoutInflater mInflater; - private CountryAdapter mAdapter; - private ListView mList; +class CountryPicker { + private final LayoutInflater mInflater; + private final CountryAdapter mAdapter; private EditText mSearch; - private ImageView mClear; - private CountryPickedListener mListener; + private final CountryPickedListener mListener; public CountryPicker(Context context, CountryPickedListener listener) { - mContext = context; mListener = listener; - mInflater = LayoutInflater.from(mContext); - mAdapter = new CountryAdapter(mContext, mInflater); + mInflater = LayoutInflater.from(context); + mAdapter = new CountryAdapter(context, mInflater); } private View createView() { View view = mInflater.inflate(R.layout.assistant_country_list, null, false); - mList = view.findViewById(R.id.countryList); - mList.setAdapter(mAdapter); - mList.setOnItemClickListener( + ListView list = view.findViewById(R.id.countryList); + list.setAdapter(mAdapter); + list.setOnItemClickListener( new AdapterView.OnItemClickListener() { @Override public void onItemClick( @@ -85,8 +81,8 @@ public class CountryPicker { }); mSearch.setText(""); - mClear = view.findViewById(R.id.clear_field); - mClear.setOnClickListener( + ImageView clear = view.findViewById(R.id.clear_field); + clear.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { @@ -98,8 +94,7 @@ public class CountryPicker { } public View getView() { - View view = createView(); - return view; + return createView(); } public interface CountryPickedListener { diff --git a/app/src/main/java/org/linphone/assistant/EchoCancellerCalibrationAssistantActivity.java b/app/src/main/java/org/linphone/assistant/EchoCancellerCalibrationAssistantActivity.java index d3f53fe31..37802c292 100644 --- a/app/src/main/java/org/linphone/assistant/EchoCancellerCalibrationAssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/EchoCancellerCalibrationAssistantActivity.java @@ -76,14 +76,12 @@ public class EchoCancellerCalibrationAssistantActivity extends AssistantActivity : "denied")); } - switch (requestCode) { - case RECORD_AUDIO_PERMISSION_RESULT: - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - startEchoCancellerCalibration(); - } else { - // TODO: permission denied, display something to the user - } - break; + if (requestCode == RECORD_AUDIO_PERMISSION_RESULT) { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + startEchoCancellerCalibration(); + } else { + // TODO: permission denied, display something to the user + } } } @@ -111,7 +109,7 @@ public class EchoCancellerCalibrationAssistantActivity extends AssistantActivity } private void startEchoCancellerCalibration() { - LinphoneManager.getLc() + LinphoneManager.getCore() .addListener( new CoreListenerStub() { @Override @@ -119,13 +117,13 @@ public class EchoCancellerCalibrationAssistantActivity extends AssistantActivity Core core, EcCalibratorStatus status, int delayMs) { if (status == EcCalibratorStatus.InProgress) return; core.removeListener(this); - LinphoneManager.getInstance().routeAudioToReceiver(); + LinphoneManager.getAudioManager().routeAudioToEarPiece(); goToLinphoneActivity(); ((AudioManager) getSystemService(Context.AUDIO_SERVICE)) .setMode(AudioManager.MODE_NORMAL); } }); - LinphoneManager.getInstance().startEcCalibration(); + LinphoneManager.getAudioManager().startEcCalibration(); } } diff --git a/app/src/main/java/org/linphone/assistant/EmailAccountValidationAssistantActivity.java b/app/src/main/java/org/linphone/assistant/EmailAccountValidationAssistantActivity.java index 4d7bb92aa..c0cf6100c 100644 --- a/app/src/main/java/org/linphone/assistant/EmailAccountValidationAssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/EmailAccountValidationAssistantActivity.java @@ -30,7 +30,7 @@ import org.linphone.core.AccountCreatorListenerStub; import org.linphone.core.tools.Log; public class EmailAccountValidationAssistantActivity extends AssistantActivity { - private TextView mEmail, mFinishCreation; + private TextView mFinishCreation; private AccountCreatorListenerStub mListener; @@ -40,8 +40,8 @@ public class EmailAccountValidationAssistantActivity extends AssistantActivity { setContentView(R.layout.assistant_email_account_validation); - mEmail = findViewById(R.id.send_email); - mEmail.setText(mAccountCreator.getEmail()); + TextView email = findViewById(R.id.send_email); + email.setText(mAccountCreator.getEmail()); mFinishCreation = findViewById(R.id.assistant_check); mFinishCreation.setOnClickListener( diff --git a/app/src/main/java/org/linphone/assistant/GenericConnectionAssistantActivity.java b/app/src/main/java/org/linphone/assistant/GenericConnectionAssistantActivity.java index 107e24f40..c9b48239e 100644 --- a/app/src/main/java/org/linphone/assistant/GenericConnectionAssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/GenericConnectionAssistantActivity.java @@ -67,7 +67,7 @@ public class GenericConnectionAssistantActivity extends AssistantActivity implem mTransport = findViewById(R.id.assistant_transports); mAccountCreator = - LinphoneManager.getLcIfManagerNotDestroyedOrNull() + LinphoneManager.getCore() .createAccountCreator(LinphonePreferences.instance().getXmlrpcUrl()); } @@ -76,7 +76,7 @@ public class GenericConnectionAssistantActivity extends AssistantActivity implem mAccountCreator.setDomain(mDomain.getText().toString()); mAccountCreator.setPassword(mPassword.getText().toString()); mAccountCreator.setDisplayName(mDisplayName.getText().toString()); - // TODO: mUserId + // TODO: add support for user-id in account creator switch (mTransport.getCheckedRadioButtonId()) { case R.id.transport_udp: diff --git a/app/src/main/java/org/linphone/assistant/MenuAssistantActivity.java b/app/src/main/java/org/linphone/assistant/MenuAssistantActivity.java index c9ab0d7fe..8948df6c8 100644 --- a/app/src/main/java/org/linphone/assistant/MenuAssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/MenuAssistantActivity.java @@ -26,11 +26,9 @@ import android.view.View; import android.widget.TextView; import androidx.annotation.Nullable; import org.linphone.R; -import org.linphone.core.tools.Log; import org.linphone.settings.LinphonePreferences; public class MenuAssistantActivity extends AssistantActivity { - private TextView mAccountCreation, mAccountConnection, mGenericConnection, mRemoteConfiguration; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -38,10 +36,8 @@ public class MenuAssistantActivity extends AssistantActivity { setContentView(R.layout.assistant_menu); - Log.e("###"); - - mAccountCreation = findViewById(R.id.account_creation); - mAccountCreation.setOnClickListener( + TextView accountCreation = findViewById(R.id.account_creation); + accountCreation.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { @@ -62,8 +58,8 @@ public class MenuAssistantActivity extends AssistantActivity { } }); - mAccountConnection = findViewById(R.id.account_connection); - mAccountConnection.setOnClickListener( + TextView accountConnection = findViewById(R.id.account_connection); + accountConnection.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { @@ -74,11 +70,11 @@ public class MenuAssistantActivity extends AssistantActivity { } }); if (getResources().getBoolean(R.bool.hide_linphone_accounts_in_assistant)) { - mAccountConnection.setVisibility(View.GONE); + accountConnection.setVisibility(View.GONE); } - mGenericConnection = findViewById(R.id.generic_connection); - mGenericConnection.setOnClickListener( + TextView genericConnection = findViewById(R.id.generic_connection); + genericConnection.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { @@ -89,11 +85,11 @@ public class MenuAssistantActivity extends AssistantActivity { } }); if (getResources().getBoolean(R.bool.hide_generic_accounts_in_assistant)) { - mGenericConnection.setVisibility(View.GONE); + genericConnection.setVisibility(View.GONE); } - mRemoteConfiguration = findViewById(R.id.remote_configuration); - mRemoteConfiguration.setOnClickListener( + TextView remoteConfiguration = findViewById(R.id.remote_configuration); + remoteConfiguration.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { @@ -104,7 +100,7 @@ public class MenuAssistantActivity extends AssistantActivity { } }); if (getResources().getBoolean(R.bool.hide_remote_provisioning_in_assistant)) { - mRemoteConfiguration.setVisibility(View.GONE); + remoteConfiguration.setVisibility(View.GONE); } if (getResources().getBoolean(R.bool.assistant_use_linphone_login_as_first_fragment)) { diff --git a/app/src/main/java/org/linphone/assistant/OpenH264DownloadAssistantActivity.java b/app/src/main/java/org/linphone/assistant/OpenH264DownloadAssistantActivity.java index 316a1da30..f29763d25 100644 --- a/app/src/main/java/org/linphone/assistant/OpenH264DownloadAssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/OpenH264DownloadAssistantActivity.java @@ -27,6 +27,7 @@ import androidx.annotation.Nullable; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.core.Core; +import org.linphone.core.Factory; import org.linphone.core.PayloadType; import org.linphone.core.tools.Log; import org.linphone.core.tools.OpenH264DownloadHelper; @@ -45,7 +46,7 @@ public class OpenH264DownloadAssistantActivity extends AssistantActivity { super.onCreate(savedInstanceState); setContentView(R.layout.assistant_openh264_codec_download); - mHelper = LinphoneManager.getInstance().getOpenH264DownloadHelper(); + mHelper = Factory.instance().createOpenH264DownloadHelper(this); LinphonePreferences.instance().setOpenH264CodecDownloadEnabled(false); mProgress = findViewById(R.id.progress_bar); @@ -83,7 +84,7 @@ public class OpenH264DownloadAssistantActivity extends AssistantActivity { mProgress.setMax(max); mProgress.setProgress(current); } else { - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null) { core.reloadMsPlugins(getApplicationInfo().nativeLibraryDir); enableH264(); @@ -115,7 +116,7 @@ public class OpenH264DownloadAssistantActivity extends AssistantActivity { } private void enableH264() { - for (PayloadType pt : LinphoneManager.getLc().getVideoPayloadTypes()) { + for (PayloadType pt : LinphoneManager.getCore().getVideoPayloadTypes()) { if (pt.getMimeType().equals("H264")) { pt.enable(true); break; diff --git a/app/src/main/java/org/linphone/assistant/PhoneAccountCreationAssistantActivity.java b/app/src/main/java/org/linphone/assistant/PhoneAccountCreationAssistantActivity.java index d5f5a9886..f71aa91b7 100644 --- a/app/src/main/java/org/linphone/assistant/PhoneAccountCreationAssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/PhoneAccountCreationAssistantActivity.java @@ -37,7 +37,6 @@ import org.linphone.core.tools.Log; public class PhoneAccountCreationAssistantActivity extends AssistantActivity { private TextView mCountryPicker, mError, mSipUri, mCreate; private EditText mPrefix, mPhoneNumber; - private ImageView mPhoneNumberInfos; private AccountCreatorListenerStub mListener; @@ -122,8 +121,8 @@ public class PhoneAccountCreationAssistantActivity extends AssistantActivity { } }); - mPhoneNumberInfos = findViewById(R.id.info_phone_number); - mPhoneNumberInfos.setOnClickListener( + ImageView phoneNumberInfos = findViewById(R.id.info_phone_number); + phoneNumberInfos.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/app/src/main/java/org/linphone/assistant/PhoneAccountLinkingAssistantActivity.java b/app/src/main/java/org/linphone/assistant/PhoneAccountLinkingAssistantActivity.java index f812e923a..c6b62620e 100644 --- a/app/src/main/java/org/linphone/assistant/PhoneAccountLinkingAssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/PhoneAccountLinkingAssistantActivity.java @@ -43,10 +43,8 @@ import org.linphone.core.tools.Log; public class PhoneAccountLinkingAssistantActivity extends AssistantActivity { private TextView mCountryPicker, mError, mLink; private EditText mPrefix, mPhoneNumber; - private ImageView mPhoneNumberInfos; private AccountCreatorListenerStub mListener; - private ProxyConfig mProxyConfig; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -56,7 +54,7 @@ public class PhoneAccountLinkingAssistantActivity extends AssistantActivity { if (getIntent() != null && getIntent().hasExtra("AccountNumber")) { int proxyConfigIndex = getIntent().getExtras().getInt("AccountNumber"); - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core == null) { Log.e("[Account Linking] Core not available"); unexpectedError(); @@ -64,7 +62,7 @@ public class PhoneAccountLinkingAssistantActivity extends AssistantActivity { ProxyConfig[] proxyConfigs = core.getProxyConfigList(); if (proxyConfigIndex >= 0 && proxyConfigIndex < proxyConfigs.length) { - mProxyConfig = proxyConfigs[proxyConfigIndex]; + ProxyConfig mProxyConfig = proxyConfigs[proxyConfigIndex]; Address identity = mProxyConfig.getIdentityAddress(); if (identity == null) { @@ -160,8 +158,8 @@ public class PhoneAccountLinkingAssistantActivity extends AssistantActivity { } }); - mPhoneNumberInfos = findViewById(R.id.info_phone_number); - mPhoneNumberInfos.setOnClickListener( + ImageView phoneNumberInfos = findViewById(R.id.info_phone_number); + phoneNumberInfos.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/app/src/main/java/org/linphone/assistant/PhoneAccountValidationAssistantActivity.java b/app/src/main/java/org/linphone/assistant/PhoneAccountValidationAssistantActivity.java index 1af31cc27..819fce942 100644 --- a/app/src/main/java/org/linphone/assistant/PhoneAccountValidationAssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/PhoneAccountValidationAssistantActivity.java @@ -35,12 +35,12 @@ import org.linphone.core.tools.Log; import org.linphone.settings.LinphonePreferences; public class PhoneAccountValidationAssistantActivity extends AssistantActivity { - private TextView mPhoneNumber, mFinishCreation; + private TextView mFinishCreation; private EditText mSmsCode; private ClipboardManager mClipboard; private int mActivationCodeLength; - private boolean mIsLogin, mIsLinking; + private boolean mIsLinking; private AccountCreatorListenerStub mListener; @Override @@ -49,10 +49,8 @@ public class PhoneAccountValidationAssistantActivity extends AssistantActivity { setContentView(R.layout.assistant_phone_account_validation); - mIsLogin = mIsLinking = false; if (getIntent() != null && getIntent().getBooleanExtra("isLoginVerification", false)) { findViewById(R.id.title_account_creation).setVisibility(View.VISIBLE); - mIsLogin = true; } else if (getIntent() != null && getIntent().getBooleanExtra("isLinkingVerification", false)) { mIsLinking = true; @@ -64,8 +62,8 @@ public class PhoneAccountValidationAssistantActivity extends AssistantActivity { mActivationCodeLength = getResources().getInteger(R.integer.phone_number_validation_code_length); - mPhoneNumber = findViewById(R.id.phone_number); - mPhoneNumber.setText(mAccountCreator.getPhoneNumber()); + TextView phoneNumber = findViewById(R.id.phone_number); + phoneNumber.setText(mAccountCreator.getPhoneNumber()); mSmsCode = findViewById(R.id.sms_code); mSmsCode.addTextChangedListener( @@ -124,7 +122,7 @@ public class PhoneAccountValidationAssistantActivity extends AssistantActivity { showGenericErrorDialog(status); if (status.equals(AccountCreator.Status.WrongActivationCode)) { - // TODO + // TODO do something so the server re-send a SMS } } } @@ -141,7 +139,7 @@ public class PhoneAccountValidationAssistantActivity extends AssistantActivity { showGenericErrorDialog(status); if (status.equals(AccountCreator.Status.WrongActivationCode)) { - // TODO + // TODO do something so the server re-send a SMS } } } diff --git a/app/src/main/java/org/linphone/assistant/QrCodeConfigurationAssistantActivity.java b/app/src/main/java/org/linphone/assistant/QrCodeConfigurationAssistantActivity.java index 6bbee59d2..8e2434604 100644 --- a/app/src/main/java/org/linphone/assistant/QrCodeConfigurationAssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/QrCodeConfigurationAssistantActivity.java @@ -46,7 +46,7 @@ public class QrCodeConfigurationAssistantActivity extends AssistantActivity { mListener = new CoreListenerStub() { @Override - public void onQrcodeFound(Core lc, String result) { + public void onQrcodeFound(Core core, String result) { Intent resultIntent = new Intent(); resultIntent.putExtra("URL", result); setResult(Activity.RESULT_OK, resultIntent); @@ -56,32 +56,40 @@ public class QrCodeConfigurationAssistantActivity extends AssistantActivity { } private void enableQrcodeReader(boolean enable) { - LinphoneManager.getLc().enableQrcodeVideoPreview(enable); - LinphoneManager.getLc().enableVideoPreview(enable); + Core core = LinphoneManager.getCore(); + if (core == null) return; + + core.enableQrcodeVideoPreview(enable); + core.enableVideoPreview(enable); if (enable) { - LinphoneManager.getLc().addListener(mListener); + core.addListener(mListener); } else { - LinphoneManager.getLc().removeListener(mListener); + core.removeListener(mListener); } } private void setBackCamera() { + Core core = LinphoneManager.getCore(); + if (core == null) return; + int camId = 0; AndroidCameraConfiguration.AndroidCamera[] cameras = AndroidCameraConfiguration.retrieveCameras(); for (AndroidCameraConfiguration.AndroidCamera androidCamera : cameras) { if (!androidCamera.frontFacing) camId = androidCamera.id; } - String[] devices = LinphoneManager.getLc().getVideoDevicesList(); + String[] devices = core.getVideoDevicesList(); String newDevice = devices[camId]; - LinphoneManager.getLc().setVideoDevice(newDevice); + core.setVideoDevice(newDevice); } private void launchQrcodeReader() { - LinphoneManager.getLc().setNativePreviewWindowId(mQrcodeView); - setBackCamera(); + Core core = LinphoneManager.getCore(); + if (core == null) return; + core.setNativePreviewWindowId(mQrcodeView); + setBackCamera(); enableQrcodeReader(true); } diff --git a/app/src/main/java/org/linphone/assistant/RemoteConfigurationAssistantActivity.java b/app/src/main/java/org/linphone/assistant/RemoteConfigurationAssistantActivity.java index a5b3999bb..d201250b4 100644 --- a/app/src/main/java/org/linphone/assistant/RemoteConfigurationAssistantActivity.java +++ b/app/src/main/java/org/linphone/assistant/RemoteConfigurationAssistantActivity.java @@ -46,7 +46,7 @@ public class RemoteConfigurationAssistantActivity extends AssistantActivity { private static final int QR_CODE_ACTIVITY_RESULT = 1; private static final int CAMERA_PERMISSION_RESULT = 2; - private TextView mFetchAndApply, mQrCode; + private TextView mFetchAndApply; private EditText mRemoteConfigurationUrl; private RelativeLayout mWaitLayout; @@ -72,9 +72,9 @@ public class RemoteConfigurationAssistantActivity extends AssistantActivity { mWaitLayout.setVisibility(View.VISIBLE); mFetchAndApply.setEnabled(false); LinphonePreferences.instance().setRemoteProvisioningUrl(url); - LinphoneManager.getLc().getConfig().sync(); - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null) { + core.getConfig().sync(); core.addListener(mListener); } LinphoneManager.getInstance().restartCore(); @@ -106,8 +106,8 @@ public class RemoteConfigurationAssistantActivity extends AssistantActivity { }); mRemoteConfigurationUrl.setText(LinphonePreferences.instance().getRemoteProvisioningUrl()); - mQrCode = findViewById(R.id.qr_code); - mQrCode.setOnClickListener( + TextView qrCode = findViewById(R.id.qr_code); + qrCode.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { @@ -186,18 +186,16 @@ public class RemoteConfigurationAssistantActivity extends AssistantActivity { : "denied")); } - switch (requestCode) { - case CAMERA_PERMISSION_RESULT: - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - startActivityForResult( - new Intent( - RemoteConfigurationAssistantActivity.this, - QrCodeConfigurationAssistantActivity.class), - QR_CODE_ACTIVITY_RESULT); - } else { - // TODO: permission denied, display something to the user - } - break; + if (requestCode == CAMERA_PERMISSION_RESULT) { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + startActivityForResult( + new Intent( + RemoteConfigurationAssistantActivity.this, + QrCodeConfigurationAssistantActivity.class), + QR_CODE_ACTIVITY_RESULT); + } else { + // TODO: permission denied, display something to the user + } } } } diff --git a/app/src/main/java/org/linphone/call/BandwidthManager.java b/app/src/main/java/org/linphone/call/BandwidthManager.java index a6f63105b..9c417f599 100644 --- a/app/src/main/java/org/linphone/call/BandwidthManager.java +++ b/app/src/main/java/org/linphone/call/BandwidthManager.java @@ -22,26 +22,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import org.linphone.core.CallParams; public class BandwidthManager { - private static final int HIGH_RESOLUTION = 0; private static final int LOW_RESOLUTION = 1; private static final int LOW_BANDWIDTH = 2; - private static BandwidthManager sInstance; + private static final int currentProfile = HIGH_RESOLUTION; - private final int currentProfile = HIGH_RESOLUTION; - - private BandwidthManager() { + public BandwidthManager() { // FIXME register a listener on NetworkManager to get notified of network state // FIXME register a listener on Preference to get notified of change in video enable value // FIXME initially get those values } - public static synchronized BandwidthManager getInstance() { - if (sInstance == null) sInstance = new BandwidthManager(); - return sInstance; - } + public void destroy() {} public void updateWithProfileSettings(CallParams callParams) { if (callParams != null) { // in call diff --git a/app/src/main/java/org/linphone/call/CallActivity.java b/app/src/main/java/org/linphone/call/CallActivity.java index 588f56730..862befcb0 100644 --- a/app/src/main/java/org/linphone/call/CallActivity.java +++ b/app/src/main/java/org/linphone/call/CallActivity.java @@ -61,9 +61,11 @@ import java.util.HashMap; import java.util.List; import java.util.Timer; import java.util.TimerTask; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; +import org.linphone.activities.DialerActivity; +import org.linphone.activities.LinphoneGenericActivity; +import org.linphone.chat.ChatActivity; import org.linphone.compatibility.Compatibility; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; @@ -87,7 +89,6 @@ import org.linphone.fragments.StatusFragment; import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration; import org.linphone.receivers.BluetoothManager; import org.linphone.settings.LinphonePreferences; -import org.linphone.utils.LinphoneGenericActivity; import org.linphone.utils.LinphoneUtils; import org.linphone.views.ContactAvatar; import org.linphone.views.Numpad; @@ -101,27 +102,28 @@ public class CallActivity extends LinphoneGenericActivity private static final int PERMISSIONS_ENABLED_MIC = 204; private static final int PERMISSIONS_EXTERNAL_STORAGE = 205; - private static CallActivity sInstance; private static long sTimeRemind = 0; private Handler mControlsHandler = new Handler(); private Runnable mControls; private ImageView mSwitchCamera; private TextView mMissedChats; private RelativeLayout mActiveCallHeader, mSideMenuContent, mAvatarLayout; - private ImageView mPause, - mHangUp, - mDialer, - mVideo, - mMicro, - mSpeaker, - mOptions, - mAddCall, - mTransfer, - mConference, - mConferenceStatus, - mRecordCall, - mRecording; - private ImageView mAudioRoute, mRouteSpeaker, mRouteEarpiece, mRouteBluetooth, mMenu, mChat; + private ImageView mPause; + private ImageView mDialer; + private ImageView mVideo; + private ImageView mMicro; + private ImageView mSpeaker; + private ImageView mOptions; + private ImageView mAddCall; + private ImageView mTransfer; + private ImageView mConference; + private ImageView mConferenceStatus; + private ImageView mRecordCall; + private ImageView mRecording; + private ImageView mAudioRoute; + private ImageView mRouteSpeaker; + private ImageView mRouteEarpiece; + private ImageView mRouteBluetooth; private LinearLayout mNoCurrentCall, mCallInfo, mCallPaused; private ProgressBar mVideoProgress; private StatusFragment mStatus; @@ -152,23 +154,15 @@ public class CallActivity extends LinphoneGenericActivity private TimerTask mTask; private HashMap mEncoderTexts; private HashMap mDecoderTexts; - private CallListenerStub mCallListener; private Call mCallDisplayedInStats; private boolean mOldIsSpeakerEnabled = false; - public static CallActivity instance() { - return sInstance; - } - - public static boolean isInstanciated() { - return sInstance != null; - } + private CallActivityInterface mCallInterface; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - sInstance = this; getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); Compatibility.setShowWhenLocked(this, true); @@ -192,14 +186,14 @@ public class CallActivity extends LinphoneGenericActivity mListener = new CoreListenerStub() { @Override - public void onMessageReceived(Core lc, ChatRoom cr, ChatMessage message) { + public void onMessageReceived(Core core, ChatRoom cr, ChatMessage message) { displayMissedChats(); } @Override public void onCallStateChanged( - Core lc, final Call call, Call.State state, String message) { - if (LinphoneManager.getLc().getCallsNb() == 0) { + Core core, final Call call, Call.State state, String message) { + if (core.getCallsNb() == 0) { finish(); return; } @@ -210,7 +204,7 @@ public class CallActivity extends LinphoneGenericActivity } else if (state == State.Paused || state == State.PausedByRemote || state == State.Pausing) { - if (LinphoneManager.getLc().getCurrentCall() != null) { + if (core.getCurrentCall() != null) { mVideo.setEnabled(false); } if (isVideoEnabled(call)) { @@ -223,7 +217,7 @@ public class CallActivity extends LinphoneGenericActivity showVideoView(); } } - if (LinphoneManager.getLc().getCurrentCall() != null) { + if (core.getCurrentCall() != null) { mVideo.setEnabled(true); } } else if (state == State.StreamsRunning) { @@ -250,19 +244,19 @@ public class CallActivity extends LinphoneGenericActivity if (remoteVideo && !localVideo && !autoAcceptCameraPolicy - && !LinphoneManager.getLc().isInConference()) { + && !core.isInConference()) { showAcceptCallUpdateDialog(); createTimerForDialog(SECONDS_BEFORE_DENYING_CALL_UPDATE); } } refreshIncallUi(); - mTransfer.setEnabled(LinphoneManager.getLc().getCurrentCall() != null); + mTransfer.setEnabled(core.getCurrentCall() != null); } @Override public void onCallEncryptionChanged( - Core lc, + Core core, final Call call, boolean encrypted, String authenticationToken) { @@ -281,8 +275,9 @@ public class CallActivity extends LinphoneGenericActivity if (findViewById(R.id.fragmentContainer) != null) { initUI(); - if (LinphoneManager.getLc().getCallsNb() > 0) { - Call call = LinphoneManager.getLc().getCalls()[0]; + Core core = LinphoneManager.getCore(); + if (core.getCallsNb() > 0) { + Call call = core.getCalls()[0]; if (LinphoneUtils.isCallEstablished(call)) { enableAndRefreshInCallActions(); @@ -302,16 +297,16 @@ public class CallActivity extends LinphoneGenericActivity refreshInCallActions(); return; } else { - mIsSpeakerEnabled = LinphoneManager.getInstance().isSpeakerEnabled(); - mIsMicMuted = !LinphoneManager.getLc().micEnabled(); + mIsSpeakerEnabled = LinphoneManager.getAudioManager().isAudioRoutedToSpeaker(); + mIsMicMuted = !core.micEnabled(); } Fragment callFragment; - if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) { + if (isVideoEnabled(core.getCurrentCall())) { callFragment = new CallVideoFragment(); mVideoCallFragment = (CallVideoFragment) callFragment; displayVideoCall(false); - LinphoneManager.getInstance().routeAudioToSpeaker(); + LinphoneManager.getAudioManager().routeAudioToSpeaker(); mIsSpeakerEnabled = true; } else { callFragment = new CallAudioFragment(); @@ -328,6 +323,24 @@ public class CallActivity extends LinphoneGenericActivity .add(R.id.fragmentContainer, callFragment) .commitAllowingStateLoss(); } + + mCallInterface = + new CallActivityInterface() { + @Override + public void setSpeakerEnabled(boolean enable) { + CallActivity.this.setSpeakerEnabled(enable); + } + + @Override + public void refreshInCallActions() { + CallActivity.this.refreshInCallActions(); + } + + @Override + public void resetCallControlsHidingTimer() { + CallActivity.this.resetCallControlsHidingTimer(); + } + }; } private void createTimerForDialog(long time) { @@ -356,13 +369,13 @@ public class CallActivity extends LinphoneGenericActivity @Override protected void onSaveInstanceState(Bundle outState) { - outState.putBoolean("Speaker", LinphoneManager.getInstance().isSpeakerEnabled()); - outState.putBoolean("Mic", !LinphoneManager.getLc().micEnabled()); + super.onSaveInstanceState(outState); + outState.putBoolean("Speaker", LinphoneManager.getAudioManager().isAudioRoutedToSpeaker()); + outState.putBoolean("Mic", !LinphoneManager.getCore().micEnabled()); outState.putBoolean("VideoCallPaused", mIsVideoCallPaused); outState.putBoolean("AskingVideo", mIsVideoAsk); outState.putLong("sTimeRemind", sTimeRemind); if (mDialog != null) mDialog.dismiss(); - super.onSaveInstanceState(outState); } private boolean isTablet() { @@ -394,7 +407,7 @@ public class CallActivity extends LinphoneGenericActivity mOptions.setEnabled(false); // BottonBar - mHangUp = findViewById(R.id.hang_up); + ImageView mHangUp = findViewById(R.id.hang_up); mHangUp.setOnClickListener(this); mDialer = findViewById(R.id.dialer); @@ -403,7 +416,7 @@ public class CallActivity extends LinphoneGenericActivity mNumpad = findViewById(R.id.numpad); mNumpad.getBackground().setAlpha(240); - mChat = findViewById(R.id.chat); + ImageView mChat = findViewById(R.id.chat); mChat.setOnClickListener(this); mMissedChats = findViewById(R.id.missed_chats); @@ -561,7 +574,7 @@ public class CallActivity extends LinphoneGenericActivity private void createInCallStats() { mSideMenu = findViewById(R.id.side_menu); - mMenu = findViewById(R.id.call_quality); + ImageView mMenu = findViewById(R.id.call_quality); mSideMenuContent = findViewById(R.id.side_menu_content); @@ -577,9 +590,9 @@ public class CallActivity extends LinphoneGenericActivity } }); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - initCallStatsRefresher(lc.getCurrentCall(), findViewById(R.id.incall_stats)); + Core core = LinphoneManager.getCore(); + if (core != null) { + initCallStatsRefresher(core.getCurrentCall(), findViewById(R.id.incall_stats)); } } @@ -590,16 +603,16 @@ public class CallActivity extends LinphoneGenericActivity displayMissedChats(); } - public void setSpeakerEnabled(boolean enabled) { + private void setSpeakerEnabled(boolean enabled) { mIsSpeakerEnabled = enabled; } - public void refreshInCallActions() { + private void refreshInCallActions() { if (!LinphonePreferences.instance().isVideoEnabled() || mIsConferenceRunning) { mVideo.setEnabled(false); } else { if (mVideo.isEnabled()) { - if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) { + if (isVideoEnabled(LinphoneManager.getCore().getCurrentCall())) { mVideo.setSelected(true); mVideoProgress.setVisibility(View.INVISIBLE); } else { @@ -647,32 +660,29 @@ public class CallActivity extends LinphoneGenericActivity private void enableAndRefreshInCallActions() { int confsize = 0; - if (LinphoneManager.getLc().isInConference()) { - confsize = - LinphoneManager.getLc().getConferenceSize() - - (LinphoneManager.getLc().getConference() != null ? 1 : 0); + Core core = LinphoneManager.getCore(); + if (core.isInConference()) { + confsize = core.getConferenceSize() - (core.getConference() != null ? 1 : 0); } // Enabled mTransfer button - mTransfer.setEnabled(mIsTransferAllowed && !LinphoneManager.getLc().soundResourcesLocked()); + mTransfer.setEnabled(mIsTransferAllowed && !core.soundResourcesLocked()); // Enable mConference button mConference.setEnabled( - LinphoneManager.getLc().getCallsNb() > 1 - && LinphoneManager.getLc().getCallsNb() > confsize - && !LinphoneManager.getLc().soundResourcesLocked()); + core.getCallsNb() > 1 + && core.getCallsNb() > confsize + && !core.soundResourcesLocked()); - mAddCall.setEnabled( - LinphoneManager.getLc().getCallsNb() < LinphoneManager.getLc().getMaxCalls() - && !LinphoneManager.getLc().soundResourcesLocked()); + mAddCall.setEnabled(core.getCallsNb() < core.getMaxCalls() && !core.soundResourcesLocked()); mOptions.setEnabled( !getResources().getBoolean(R.bool.disable_options_in_call) && (mAddCall.isEnabled() || mTransfer.isEnabled())); - Call currentCall = LinphoneManager.getLc().getCurrentCall(); + Call currentCall = core.getCurrentCall(); mRecordCall.setEnabled( - !LinphoneManager.getLc().soundResourcesLocked() + !core.soundResourcesLocked() && currentCall != null && currentCall.getCurrentParams().getRecordFile() != null); mRecordCall.setSelected(mIsRecording); @@ -711,7 +721,7 @@ public class CallActivity extends LinphoneGenericActivity + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); if (camera == PackageManager.PERMISSION_GRANTED) { - disableVideo(isVideoEnabled(LinphoneManager.getLc().getCurrentCall())); + disableVideo(isVideoEnabled(LinphoneManager.getCore().getCurrentCall())); } else { checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_ENABLED_CAMERA); } @@ -755,7 +765,7 @@ public class CallActivity extends LinphoneGenericActivity } else if (id == R.id.recording) { toggleCallRecording(false); } else if (id == R.id.pause) { - pauseOrResumeCall(LinphoneManager.getLc().getCurrentCall()); + pauseOrResumeCall(LinphoneManager.getCore().getCurrentCall()); } else if (id == R.id.hang_up) { hangUp(); } else if (id == R.id.dialer) { @@ -784,14 +794,14 @@ public class CallActivity extends LinphoneGenericActivity } hideOrDisplayAudioRoutes(); } else if (id == R.id.route_earpiece) { - LinphoneManager.getInstance().routeAudioToReceiver(); + LinphoneManager.getAudioManager().routeAudioToEarPiece(); mIsSpeakerEnabled = false; mRouteBluetooth.setSelected(false); mRouteSpeaker.setSelected(false); mRouteEarpiece.setSelected(true); hideOrDisplayAudioRoutes(); } else if (id == R.id.route_speaker) { - LinphoneManager.getInstance().routeAudioToSpeaker(); + LinphoneManager.getAudioManager().routeAudioToSpeaker(); mIsSpeakerEnabled = true; mRouteBluetooth.setSelected(false); mRouteSpeaker.setSelected(true); @@ -806,7 +816,7 @@ public class CallActivity extends LinphoneGenericActivity } private void toggleCallRecording(boolean enable) { - Call call = LinphoneManager.getLc().getCurrentCall(); + Call call = LinphoneManager.getCore().getCurrentCall(); if (call == null) return; @@ -832,19 +842,20 @@ public class CallActivity extends LinphoneGenericActivity } private void disableVideo(final boolean videoDisabled) { - final Call call = LinphoneManager.getLc().getCurrentCall(); + Core core = LinphoneManager.getCore(); + final Call call = core.getCurrentCall(); if (call == null) { return; } if (videoDisabled) { - CallParams params = LinphoneManager.getLc().createCallParams(call); + CallParams params = core.createCallParams(call); params.enableVideo(false); - LinphoneManager.getLc().updateCall(call, params); + core.updateCall(call, params); } else { mVideoProgress.setVisibility(View.VISIBLE); if (call.getRemoteParams() != null && !call.getRemoteParams().lowBandwidthEnabled()) { - LinphoneManager.getInstance().addVideo(); + LinphoneManager.getCallManager().addVideo(); } else { displayCustomToast(getString(R.string.error_low_bandwidth), Toast.LENGTH_LONG); } @@ -866,7 +877,7 @@ public class CallActivity extends LinphoneGenericActivity } private void switchVideo(final boolean displayVideo) { - final Call call = LinphoneManager.getLc().getCurrentCall(); + final Call call = LinphoneManager.getCore().getCurrentCall(); if (call == null) { return; } @@ -878,7 +889,7 @@ public class CallActivity extends LinphoneGenericActivity showAudioView(); } else { if (!call.getRemoteParams().lowBandwidthEnabled()) { - LinphoneManager.getInstance().addVideo(); + LinphoneManager.getCallManager().addVideo(); if (mVideoCallFragment == null || !mVideoCallFragment.isVisible()) showVideoView(); } else { displayCustomToast(getString(R.string.error_low_bandwidth), Toast.LENGTH_LONG); @@ -887,7 +898,7 @@ public class CallActivity extends LinphoneGenericActivity } private void showAudioView() { - if (LinphoneManager.getLc().getCurrentCall() != null) { + if (LinphoneManager.getCore().getCurrentCall() != null) { if (!mIsSpeakerEnabled) { LinphoneManager.getInstance().enableProximitySensing(true); } @@ -901,7 +912,7 @@ public class CallActivity extends LinphoneGenericActivity private void showVideoView() { if (!BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) { Log.w("Bluetooth not available, using mSpeaker"); - LinphoneManager.getInstance().routeAudioToSpeaker(); + LinphoneManager.getAudioManager().routeAudioToSpeaker(); mIsSpeakerEnabled = true; } refreshInCallActions(); @@ -963,40 +974,40 @@ public class CallActivity extends LinphoneGenericActivity } private void toggleMicro() { - Core lc = LinphoneManager.getLc(); + Core core = LinphoneManager.getCore(); mIsMicMuted = !mIsMicMuted; - lc.enableMic(!mIsMicMuted); + core.enableMic(!mIsMicMuted); mMicro.setSelected(mIsMicMuted); } private void toggleSpeaker() { mIsSpeakerEnabled = !mIsSpeakerEnabled; - if (LinphoneManager.getLc().getCurrentCall() != null) { - if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) + Core core = LinphoneManager.getCore(); + if (core.getCurrentCall() != null) { + if (isVideoEnabled(core.getCurrentCall())) LinphoneManager.getInstance().enableProximitySensing(false); else LinphoneManager.getInstance().enableProximitySensing(!mIsSpeakerEnabled); } mSpeaker.setSelected(mIsSpeakerEnabled); if (mIsSpeakerEnabled) { - LinphoneManager.getInstance().routeAudioToSpeaker(); - LinphoneManager.getInstance().enableSpeaker(mIsSpeakerEnabled); + LinphoneManager.getAudioManager().routeAudioToSpeaker(); } else { Log.d("Toggle mSpeaker off, routing back to earpiece"); - LinphoneManager.getInstance().routeAudioToReceiver(); + LinphoneManager.getAudioManager().routeAudioToEarPiece(); } } private void pauseOrResumeCall(Call call) { - Core lc = LinphoneManager.getLc(); - if (call != null && LinphoneManager.getLc().getCurrentCall() == call) { - lc.pauseCall(call); - if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) { + Core core = LinphoneManager.getCore(); + if (call != null && core.getCurrentCall() == call) { + core.pauseCall(call); + if (isVideoEnabled(core.getCurrentCall())) { mIsVideoCallPaused = true; } mPause.setSelected(true); } else if (call != null) { if (call.getState() == State.Paused) { - lc.resumeCall(call); + core.resumeCall(call); if (mIsVideoCallPaused) { mIsVideoCallPaused = false; } @@ -1006,19 +1017,19 @@ public class CallActivity extends LinphoneGenericActivity } private void hangUp() { - Core lc = LinphoneManager.getLc(); - Call currentCall = lc.getCurrentCall(); + Core core = LinphoneManager.getCore(); + Call currentCall = core.getCurrentCall(); if (mIsRecording) { toggleCallRecording(false); } if (currentCall != null) { - lc.terminateCall(currentCall); - } else if (lc.isInConference()) { - lc.terminateConference(); + core.terminateCall(currentCall); + } else if (core.isInConference()) { + core.terminateConference(); } else { - lc.terminateAllCalls(); + core.terminateAllCalls(); } } @@ -1047,17 +1058,18 @@ public class CallActivity extends LinphoneGenericActivity if (mControlsLayout.getVisibility() != View.VISIBLE) { displayVideoCall(true); } - resetControlsHidingCallBack(); + resetCallControlsHidingTimer(); } } - public void resetControlsHidingCallBack() { + private void resetCallControlsHidingTimer() { if (mControlsHandler != null && mControls != null) { mControlsHandler.removeCallbacks(mControls); } mControls = null; - if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall()) && mControlsHandler != null) { + if (isVideoEnabled(LinphoneManager.getCore().getCurrentCall()) + && mControlsHandler != null) { mControlsHandler.postDelayed( mControls = new Runnable() { @@ -1138,28 +1150,27 @@ public class CallActivity extends LinphoneGenericActivity mConference.setVisibility(View.VISIBLE); mRecordCall.setVisibility(View.VISIBLE); mOptions.setSelected(true); - mTransfer.setEnabled(LinphoneManager.getLc().getCurrentCall() != null); + mTransfer.setEnabled(LinphoneManager.getCore().getCurrentCall() != null); } } private void goBackToDialer() { Intent intent = new Intent(); - intent.setClass(this, LinphoneActivity.class); - intent.putExtra("AddCall", true); + intent.setClass(this, DialerActivity.class); + intent.putExtra("Transfer", false); startActivity(intent); } private void goBackToDialerAndDisplayTransferButton() { Intent intent = new Intent(); - intent.setClass(this, LinphoneActivity.class); + intent.setClass(this, DialerActivity.class); intent.putExtra("Transfer", true); startActivity(intent); } private void goToChatList() { Intent intent = new Intent(); - intent.setClass(this, LinphoneActivity.class); - intent.putExtra("GoToChat", true); + intent.setClass(this, ChatActivity.class); startActivity(intent); } @@ -1168,19 +1179,20 @@ public class CallActivity extends LinphoneGenericActivity mCountDownTimer.cancel(); } - Call call = LinphoneManager.getLc().getCurrentCall(); + Core core = LinphoneManager.getCore(); + Call call = core.getCurrentCall(); if (call == null) { return; } - CallParams params = LinphoneManager.getLc().createCallParams(call); + CallParams params = core.createCallParams(call); if (accept) { params.enableVideo(true); - LinphoneManager.getLc().enableVideoCapture(true); - LinphoneManager.getLc().enableVideoDisplay(true); + core.enableVideoCapture(true); + core.enableVideoDisplay(true); } - LinphoneManager.getLc().acceptCallUpdate(call, params); + core.acceptCallUpdate(call, params); } private void hideStatusBar() { @@ -1273,27 +1285,26 @@ public class CallActivity extends LinphoneGenericActivity @Override protected void onResume() { - - sInstance = this; super.onResume(); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.addListener(mListener); + LinphoneManager.getCallManager().setCallInterface(mCallInterface); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.addListener(mListener); } - mIsSpeakerEnabled = LinphoneManager.getInstance().isSpeakerEnabled(); + mIsSpeakerEnabled = LinphoneManager.getAudioManager().isAudioRoutedToSpeaker(); refreshIncallUi(); handleViewIntent(); - if (mStatus != null && lc != null) { - Call currentCall = lc.getCurrentCall(); + if (mStatus != null && core != null) { + Call currentCall = core.getCurrentCall(); if (currentCall != null && !currentCall.getAuthenticationTokenVerified()) { mStatus.showZRTPDialog(currentCall); } } - if (!isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) { + if (!isVideoEnabled(LinphoneManager.getCore().getCurrentCall())) { if (!mIsSpeakerEnabled) { LinphoneManager.getInstance().enableProximitySensing(true); removeCallbacks(); @@ -1304,7 +1315,7 @@ public class CallActivity extends LinphoneGenericActivity private void handleViewIntent() { Intent intent = getIntent(); if (intent != null && "android.intent.action.VIEW".equals(intent.getAction())) { - Call call = LinphoneManager.getLc().getCurrentCall(); + Call call = LinphoneManager.getCore().getCurrentCall(); if (call != null && isVideoEnabled(call)) { Player player = call.getPlayer(); String path = intent.getData().getPath(); @@ -1330,10 +1341,11 @@ public class CallActivity extends LinphoneGenericActivity @Override protected void onPause() { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.removeListener(mListener); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.removeListener(mListener); } + LinphoneManager.getCallManager().setCallInterface(null); super.onPause(); @@ -1360,9 +1372,8 @@ public class CallActivity extends LinphoneGenericActivity if (mTimer != null) { mTimer.cancel(); } - sInstance = null; + super.onDestroy(); - System.gc(); } private void unbindDrawables(View view) { @@ -1382,7 +1393,7 @@ public class CallActivity extends LinphoneGenericActivity @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (LinphoneUtils.onKeyVolumeAdjust(keyCode)) return true; + if (LinphoneManager.getAudioManager().onKeyVolumeAdjust(keyCode)) return true; if (LinphoneUtils.onKeyBackGoHome(this, keyCode, event)) return true; return super.onKeyDown(keyCode, event); } @@ -1475,9 +1486,6 @@ public class CallActivity extends LinphoneGenericActivity || call.getState() == State.PausedByRemote || call.getState() == State.Pausing) { onCallStateChanged.setSelected(false); - } else if (call.getState() == State.OutgoingInit - || call.getState() == State.OutgoingProgress - || call.getState() == State.OutgoingRinging) { } } @@ -1503,20 +1511,21 @@ public class CallActivity extends LinphoneGenericActivity } private void refreshCallList() { - mIsConferenceRunning = LinphoneManager.getLc().isInConference(); + Core core = LinphoneManager.getCore(); + mIsConferenceRunning = core.isInConference(); List pausedCalls = LinphoneUtils.getCallsInState( - LinphoneManager.getLc(), Collections.singletonList(State.PausedByRemote)); + core, Collections.singletonList(State.PausedByRemote)); // MultiCalls - if (LinphoneManager.getLc().getCallsNb() > 1) { + if (core.getCallsNb() > 1) { mCallsList.setVisibility(View.VISIBLE); } // Active call - if (LinphoneManager.getLc().getCurrentCall() != null) { + if (core.getCurrentCall() != null) { displayNoCurrentCall(false); - if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall()) + if (isVideoEnabled(core.getCurrentCall()) && !mIsConferenceRunning && pausedCalls.size() == 0) { displayVideoCall(false); @@ -1526,7 +1535,7 @@ public class CallActivity extends LinphoneGenericActivity } else { showAudioView(); displayNoCurrentCall(true); - if (LinphoneManager.getLc().getCallsNb() == 1) { + if (core.getCallsNb() == 1) { mCallsList.setVisibility(View.VISIBLE); } } @@ -1542,19 +1551,18 @@ public class CallActivity extends LinphoneGenericActivity mCallsList.removeAllViews(); int index = 0; - if (LinphoneManager.getLc().getCallsNb() == 0) { + if (core.getCallsNb() == 0) { goBackToDialer(); return; } boolean isConfPaused = false; - for (Call call : LinphoneManager.getLc().getCalls()) { + for (Call call : core.getCalls()) { if (call.getConference() != null && !mIsConferenceRunning) { isConfPaused = true; index++; } else { - if (call != LinphoneManager.getLc().getCurrentCall() - && call.getConference() == null) { + if (call != core.getCurrentCall() && call.getConference() == null) { displayPausedCalls(call, index); index++; } else { @@ -1581,31 +1589,31 @@ public class CallActivity extends LinphoneGenericActivity // Conference private void exitConference(final Call call) { - Core lc = LinphoneManager.getLc(); + Core core = LinphoneManager.getCore(); - if (lc.isInConference()) { - lc.removeFromConference(call); - if (lc.getConferenceSize() <= 1) { - lc.leaveConference(); + if (core.isInConference()) { + core.removeFromConference(call); + if (core.getConferenceSize() <= 1) { + core.leaveConference(); } } refreshIncallUi(); } private void enterConference() { - LinphoneManager.getLc().addAllToConference(); + LinphoneManager.getCore().addAllToConference(); } private void pauseOrResumeConference() { - Core lc = LinphoneManager.getLc(); + Core core = LinphoneManager.getCore(); mConferenceStatus = findViewById(R.id.conference_pause); if (mConferenceStatus != null) { - if (lc.isInConference()) { + if (core.isInConference()) { mConferenceStatus.setSelected(true); - lc.leaveConference(); + core.leaveConference(); } else { mConferenceStatus.setSelected(false); - lc.enterConference(); + core.enterConference(); } } refreshCallList(); @@ -1659,7 +1667,7 @@ public class CallActivity extends LinphoneGenericActivity // Conference participant int index = 1; - for (Call call : LinphoneManager.getLc().getCalls()) { + for (Call call : LinphoneManager.getCore().getCalls()) { if (call.getConference() != null) { displayConferenceParticipant(index, call); index++; @@ -1672,7 +1680,11 @@ public class CallActivity extends LinphoneGenericActivity } private void displayMissedChats() { - int count = LinphoneManager.getInstance().getUnreadMessageCount(); + int count = 0; + Core core = LinphoneManager.getCore(); + if (core != null) { + count = core.getUnreadChatMessageCountFromActiveLocals(); + } if (count > 0) { mMissedChats.setText(String.valueOf(count)); @@ -1683,7 +1695,6 @@ public class CallActivity extends LinphoneGenericActivity } } - @SuppressWarnings("deprecation") private void formatText(TextView tv, String name, String value) { tv.setText(Html.fromHtml("" + name + " " + value)); } @@ -1692,7 +1703,7 @@ public class CallActivity extends LinphoneGenericActivity String ret = mEncoderTexts.get(mime); if (ret == null) { org.linphone.mediastream.Factory msfactory = - LinphoneManager.getLc().getMediastreamerFactory(); + LinphoneManager.getCore().getMediastreamerFactory(); ret = msfactory.getEncoderText(mime); mEncoderTexts.put(mime, ret); } @@ -1703,7 +1714,7 @@ public class CallActivity extends LinphoneGenericActivity String ret = mDecoderTexts.get(mime); if (ret == null) { org.linphone.mediastream.Factory msfactory = - LinphoneManager.getLc().getMediastreamerFactory(); + LinphoneManager.getCore().getMediastreamerFactory(); ret = msfactory.getDecoderText(mime); mDecoderTexts.put(mime, ret); } @@ -1751,16 +1762,16 @@ public class CallActivity extends LinphoneGenericActivity formatText( dl, getString(R.string.call_stats_download), - String.valueOf((int) stats.getDownloadBandwidth()) + " kbits/s"); + (int) stats.getDownloadBandwidth() + " kbits/s"); formatText( ul, getString(R.string.call_stats_upload), - String.valueOf((int) stats.getUploadBandwidth()) + " kbits/s"); + (int) stats.getUploadBandwidth() + " kbits/s"); if (isVideo) { formatText( edl, getString(R.string.call_stats_estimated_download), - String.valueOf(stats.getEstimatedDownloadBandwidth()) + " kbits/s"); + stats.getEstimatedDownloadBandwidth() + " kbits/s"); } formatText(ice, getString(R.string.call_stats_ice), stats.getIceState().toString()); formatText( @@ -1854,10 +1865,10 @@ public class CallActivity extends LinphoneGenericActivity final View videoLayout = view.findViewById(R.id.callStatsVideo); final View audioLayout = view.findViewById(R.id.callStatsAudio); - mCallListener = + CallListenerStub mCallListener = new CallListenerStub() { - public void onStateChanged(Call call, Call.State cstate, String message) { - if (cstate == Call.State.End || cstate == Call.State.Error) { + public void onStateChanged(Call call, State cstate, String message) { + if (cstate == State.End || cstate == State.Error) { if (mTimer != null) { Log.i( "Call is terminated, stopping mCountDownTimer in charge of stats refreshing."); @@ -1901,11 +1912,9 @@ public class CallActivity extends LinphoneGenericActivity new Runnable() { @Override public void run() { - if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() - == null) return; - synchronized (LinphoneManager.getLc()) { - if (LinphoneActivity.isInstanciated() - && call.getState() != Call.State.Released) { + if (LinphoneManager.getCore() == null) return; + synchronized (LinphoneManager.getCore()) { + if (call.getState() != Call.State.Released) { CallParams params = call.getCurrentParams(); if (params != null) { CallStats audioStats = @@ -1984,6 +1993,14 @@ public class CallActivity extends LinphoneGenericActivity mTimer.scheduleAtFixedRate(mTask, 0, 1000); } + public interface CallActivityInterface { + void setSpeakerEnabled(boolean enable); + + void refreshInCallActions(); + + void resetCallControlsHidingTimer(); + } + //// Earset Connectivity Broadcast innerClass public class HeadsetReceiver extends BroadcastReceiver { @Override @@ -1993,13 +2010,13 @@ public class CallActivity extends LinphoneGenericActivity switch (intent.getIntExtra("state", 0)) { case 0: if (mOldIsSpeakerEnabled) { - LinphoneManager.getInstance().routeAudioToSpeaker(); + LinphoneManager.getAudioManager().routeAudioToSpeaker(); mIsSpeakerEnabled = true; mSpeaker.setEnabled(true); } break; case 1: - LinphoneManager.getInstance().routeAudioToReceiver(); + LinphoneManager.getAudioManager().routeAudioToEarPiece(); mOldIsSpeakerEnabled = mIsSpeakerEnabled; mIsSpeakerEnabled = false; mSpeaker.setEnabled(false); diff --git a/app/src/main/java/org/linphone/call/CallIncomingActivity.java b/app/src/main/java/org/linphone/call/CallIncomingActivity.java index 068aa110e..5d0ba540b 100644 --- a/app/src/main/java/org/linphone/call/CallIncomingActivity.java +++ b/app/src/main/java/org/linphone/call/CallIncomingActivity.java @@ -33,9 +33,10 @@ import android.widget.TextView; import android.widget.Toast; import androidx.core.app.ActivityCompat; import java.util.ArrayList; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; +import org.linphone.LinphoneService; import org.linphone.R; +import org.linphone.activities.LinphoneGenericActivity; import org.linphone.compatibility.Compatibility; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; @@ -46,7 +47,6 @@ import org.linphone.core.Core; import org.linphone.core.CoreListenerStub; import org.linphone.core.tools.Log; import org.linphone.settings.LinphonePreferences; -import org.linphone.utils.LinphoneGenericActivity; import org.linphone.utils.LinphoneUtils; import org.linphone.views.CallIncomingAnswerButton; import org.linphone.views.CallIncomingButtonListener; @@ -54,26 +54,12 @@ import org.linphone.views.CallIncomingDeclineButton; import org.linphone.views.ContactAvatar; public class CallIncomingActivity extends LinphoneGenericActivity { - private static CallIncomingActivity sInstance; - private TextView mName, mNumber; - private ImageView mAcceptIcon; - private CallIncomingAnswerButton mAccept; - private CallIncomingDeclineButton mDecline; private Call mCall; private CoreListenerStub mListener; private boolean mAlreadyAcceptedOrDeniedCall; - private KeyguardManager mKeyguardManager; private TextureView mVideoDisplay; - public static CallIncomingActivity instance() { - return sInstance; - } - - public static boolean isInstanciated() { - return sInstance != null; - } - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -87,9 +73,9 @@ public class CallIncomingActivity extends LinphoneGenericActivity { mNumber = findViewById(R.id.contact_number); mVideoDisplay = findViewById(R.id.videoSurface); - mAccept = findViewById(R.id.answer_button); - mDecline = findViewById(R.id.decline_button); - mAcceptIcon = findViewById(R.id.acceptIcon); + CallIncomingAnswerButton mAccept = findViewById(R.id.answer_button); + CallIncomingDeclineButton mDecline = findViewById(R.id.decline_button); + ImageView mAcceptIcon = findViewById(R.id.acceptIcon); lookupCurrentCall(); if (LinphonePreferences.instance() != null @@ -100,7 +86,8 @@ public class CallIncomingActivity extends LinphoneGenericActivity { mAcceptIcon.setImageResource(R.drawable.call_video_start); } - mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); + KeyguardManager mKeyguardManager = + (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); boolean doNotUseSliders = getResources() .getBoolean( @@ -133,35 +120,23 @@ public class CallIncomingActivity extends LinphoneGenericActivity { new CoreListenerStub() { @Override public void onCallStateChanged( - Core lc, Call call, State state, String message) { + Core core, Call call, State state, String message) { if (call == mCall && State.End == state) { finish(); } else if (state == State.Connected) { startActivity( new Intent(CallIncomingActivity.this, CallActivity.class)); - } else if (state == State.StreamsRunning) { - Log.e( - "CallIncommingActivity - onCreate - State.StreamsRunning - speaker = " - + LinphoneManager.getInstance().isSpeakerEnabled()); - // The following should not be needed except some devices need it (e.g. - // Galaxy S). - LinphoneManager.getInstance() - .enableSpeaker( - LinphoneManager.getInstance().isSpeakerEnabled()); } } }; - - sInstance = this; } @Override protected void onResume() { super.onResume(); - sInstance = this; - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.addListener(mListener); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.addListener(mListener); } mAlreadyAcceptedOrDeniedCall = false; @@ -204,32 +179,26 @@ public class CallIncomingActivity extends LinphoneGenericActivity { @Override protected void onPause() { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.removeListener(mListener); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.removeListener(mListener); } super.onPause(); } - @Override - protected void onDestroy() { - super.onDestroy(); - sInstance = null; - } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (LinphoneManager.isInstanciated() + if (LinphoneService.isReady() && (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME)) { - LinphoneManager.getLc().terminateCall(mCall); + LinphoneManager.getCore().terminateCall(mCall); finish(); } return super.onKeyDown(keyCode, event); } private void lookupCurrentCall() { - if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) { - for (Call call : LinphoneManager.getLc().getCalls()) { + if (LinphoneManager.getCore() != null) { + for (Call call : LinphoneManager.getCore().getCalls()) { if (State.IncomingReceived == call.getState() || State.IncomingEarlyMedia == call.getState()) { mCall = call; @@ -245,7 +214,7 @@ public class CallIncomingActivity extends LinphoneGenericActivity { } mAlreadyAcceptedOrDeniedCall = true; - LinphoneManager.getLc().terminateCall(mCall); + LinphoneManager.getCore().terminateCall(mCall); finish(); } @@ -255,15 +224,9 @@ public class CallIncomingActivity extends LinphoneGenericActivity { } mAlreadyAcceptedOrDeniedCall = true; - if (!LinphoneManager.getInstance().acceptCall(mCall)) { + if (!LinphoneManager.getCallManager().acceptCall(mCall)) { // the above method takes care of Samsung Galaxy S Toast.makeText(this, R.string.couldnt_accept_call, Toast.LENGTH_LONG).show(); - } else { - if (!LinphoneActivity.isInstanciated()) { - return; - } - LinphoneManager.getInstance().routeAudioToReceiver(); - LinphoneActivity.instance().startIncallActivity(); } } @@ -284,10 +247,21 @@ public class CallIncomingActivity extends LinphoneGenericActivity { "[Permission] Camera permission is " + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); + int readPhoneState = + getPackageManager() + .checkPermission(Manifest.permission.READ_PHONE_STATE, getPackageName()); + Log.i( + "[Permission] Read phone state permission is " + + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); + if (recordAudio != PackageManager.PERMISSION_GRANTED) { Log.i("[Permission] Asking for record audio"); permissionsList.add(Manifest.permission.RECORD_AUDIO); } + if (readPhoneState != PackageManager.PERMISSION_GRANTED) { + Log.i("[Permission] Asking for read phone state"); + permissionsList.add(Manifest.permission.READ_PHONE_STATE); + } if (LinphonePreferences.instance().shouldInitiateVideoCall() || LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) { if (camera != PackageManager.PERMISSION_GRANTED) { diff --git a/app/src/main/java/org/linphone/call/CallManager.java b/app/src/main/java/org/linphone/call/CallManager.java index 4c8fcad88..e5a9a9fc2 100644 --- a/app/src/main/java/org/linphone/call/CallManager.java +++ b/app/src/main/java/org/linphone/call/CallManager.java @@ -2,7 +2,7 @@ package org.linphone.call; /* CallManager.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -19,31 +19,42 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; +import android.widget.Toast; import org.linphone.LinphoneManager; import org.linphone.LinphoneService; +import org.linphone.R; +import org.linphone.contacts.ContactsManager; +import org.linphone.contacts.LinphoneContact; import org.linphone.core.Address; import org.linphone.core.Call; import org.linphone.core.CallParams; import org.linphone.core.Core; import org.linphone.core.MediaEncryption; +import org.linphone.core.ProxyConfig; import org.linphone.core.tools.Log; +import org.linphone.mediastream.Version; +import org.linphone.settings.LinphonePreferences; import org.linphone.utils.FileUtils; import org.linphone.utils.LinphoneUtils; +import org.linphone.views.AddressType; /** Handle call updating, reinvites. */ public class CallManager { + private Context mContext; + private boolean mHandsetON = false; + private CallActivity.CallActivityInterface mCallInterface; + private BandwidthManager mBandwidthManager; - private static CallManager sInstance; - - public static synchronized CallManager getInstance() { - if (sInstance == null) sInstance = new CallManager(); - return sInstance; + public CallManager(Context context) { + mContext = context; + mBandwidthManager = new BandwidthManager(); } - private CallManager() {} - - private BandwidthManager getBandwidthManager() { - return BandwidthManager.getInstance(); + public void destroy() { + mBandwidthManager.destroy(); } public void inviteAddress(Address lAddress, boolean forceZRTP) { @@ -54,16 +65,12 @@ public class CallManager { inviteAddress(lAddress, false, isLowBandwidthConnection, forceZRTP); } - public void inviteAddress(Address lAddress) { - inviteAddress(lAddress, false); - } - - public void inviteAddress( + private void inviteAddress( Address lAddress, boolean videoEnabled, boolean lowBandwidth, boolean forceZRTP) { - Core lc = LinphoneManager.getLc(); + Core core = LinphoneManager.getCore(); - CallParams params = lc.createCallParams(null); - getBandwidthManager().updateWithProfileSettings(params); + CallParams params = core.createCallParams(null); + mBandwidthManager.updateWithProfileSettings(params); if (videoEnabled && params.videoEnabled()) { params.enableVideo(true); @@ -73,7 +80,7 @@ public class CallManager { if (lowBandwidth) { params.enableLowBandwidth(true); - Log.d("Low bandwidth enabled in call params"); + Log.d("[Call Manager] Low bandwidth enabled in call params"); } if (forceZRTP) { @@ -81,11 +88,10 @@ public class CallManager { } String recordFile = - FileUtils.getCallRecordingFilename( - LinphoneManager.getInstance().getContext(), lAddress); + FileUtils.getCallRecordingFilename(LinphoneService.instance(), lAddress); params.setRecordFile(recordFile); - lc.inviteAddressWithParams(lAddress, params); + core.inviteAddressWithParams(lAddress, params); } public void inviteAddress(Address lAddress, boolean videoEnabled, boolean lowBandwidth) { @@ -99,18 +105,18 @@ public class CallManager { * @return if updateCall called */ public boolean reinviteWithVideo() { - Core lc = LinphoneManager.getLc(); - Call lCall = lc.getCurrentCall(); - if (lCall == null) { - Log.e("Trying to reinviteWithVideo while not in call: doing nothing"); + Core core = LinphoneManager.getCore(); + Call call = core.getCurrentCall(); + if (call == null) { + Log.e("[Call Manager] Trying to reinviteWithVideo while not in call: doing nothing"); return false; } - CallParams params = lc.createCallParams(lCall); + CallParams params = core.createCallParams(call); if (params.videoEnabled()) return false; // Check if video possible regarding bandwidth limitations - getBandwidthManager().updateWithProfileSettings(params); + mBandwidthManager.updateWithProfileSettings(params); // Abort if not enough bandwidth... if (!params.videoEnabled()) { @@ -118,7 +124,7 @@ public class CallManager { } // Not yet in video call: try to re-invite with video - lc.updateCall(lCall, params); + core.updateCall(call, params); return true; } @@ -128,14 +134,174 @@ public class CallManager { * is recreated and setParameters is called. */ public void updateCall() { - Core lc = LinphoneManager.getLc(); - Call lCall = lc.getCurrentCall(); - if (lCall == null) { - Log.e("Trying to updateCall while not in call: doing nothing"); + Core core = LinphoneManager.getCore(); + Call call = core.getCurrentCall(); + if (call == null) { + Log.e("[Call Manager] Trying to updateCall while not in call: doing nothing"); return; } - CallParams params = lc.createCallParams(lCall); - getBandwidthManager().updateWithProfileSettings(params); - lc.updateCall(lCall, null); + CallParams params = core.createCallParams(call); + mBandwidthManager.updateWithProfileSettings(params); + core.updateCall(call, null); + } + + public void newOutgoingCall(AddressType address) { + String to = address.getText().toString(); + newOutgoingCall(to, address.getDisplayedName()); + } + + public void newOutgoingCall(String to, String displayName) { + // if (mCore.inCall()) { + // listenerDispatcher.tryingNewOutgoingCallButAlreadyInCall(); + // return; + // } + if (to == null) return; + + // If to is only a username, try to find the contact to get an alias if existing + if (!to.startsWith("sip:") || !to.contains("@")) { + LinphoneContact contact = ContactsManager.getInstance().findContactFromPhoneNumber(to); + if (contact != null) { + String alias = contact.getContactFromPresenceModelForUriOrTel(to); + if (alias != null) { + to = alias; + } + } + } + + LinphonePreferences preferences = LinphonePreferences.instance(); + Core core = LinphoneManager.getCore(); + Address address; + address = core.interpretUrl(to); // InterpretUrl does normalizePhoneNumber + if (address == null) { + Log.e("[Call Manager] Couldn't convert to String to Address : " + to); + return; + } + + ProxyConfig lpc = core.getDefaultProxyConfig(); + if (mContext.getResources().getBoolean(R.bool.forbid_self_call) + && lpc != null + && address.weakEqual(lpc.getIdentityAddress())) { + return; + } + address.setDisplayName(displayName); + + boolean isLowBandwidthConnection = + !LinphoneUtils.isHighBandwidthConnection( + LinphoneService.instance().getApplicationContext()); + + if (core.isNetworkReachable()) { + if (Version.isVideoCapable()) { + boolean prefVideoEnable = preferences.isVideoEnabled(); + boolean prefInitiateWithVideo = preferences.shouldInitiateVideoCall(); + inviteAddress( + address, + prefVideoEnable && prefInitiateWithVideo, + isLowBandwidthConnection); + } else { + inviteAddress(address, false, isLowBandwidthConnection); + } + } else { + Toast.makeText( + mContext, + mContext.getString(R.string.error_network_unreachable), + Toast.LENGTH_LONG) + .show(); + Log.e( + "[Call Manager] Error: " + + mContext.getString(R.string.error_network_unreachable)); + } + } + + private void enableCamera(Call call, boolean enable) { + if (call != null) { + call.enableCamera(enable); + if (mContext.getResources().getBoolean(R.bool.enable_call_notification)) + LinphoneService.instance() + .getNotificationManager() + .displayCallNotification(LinphoneManager.getCore().getCurrentCall()); + } + } + + public void playDtmf(ContentResolver r, char dtmf) { + try { + if (Settings.System.getInt(r, Settings.System.DTMF_TONE_WHEN_DIALING) == 0) { + // audible touch disabled: don't play on speaker, only send in outgoing stream + return; + } + } catch (Settings.SettingNotFoundException e) { + Log.e("[Call Manager] playDtmf exception: " + e); + } + + LinphoneManager.getCore().playDtmf(dtmf, -1); + } + + private void terminateCall() { + Core core = LinphoneManager.getCore(); + if (core.inCall()) { + core.terminateCall(core.getCurrentCall()); + } + } + + /** @return false if already in video call. */ + public boolean addVideo() { + Call call = LinphoneManager.getCore().getCurrentCall(); + enableCamera(call, true); + return reinviteWithVideo(); + } + + public boolean acceptCall(Call call) { + if (call == null) return false; + + Core core = LinphoneManager.getCore(); + CallParams params = core.createCallParams(call); + + boolean isLowBandwidthConnection = + !LinphoneUtils.isHighBandwidthConnection( + LinphoneService.instance().getApplicationContext()); + + if (params != null) { + params.enableLowBandwidth(isLowBandwidthConnection); + params.setRecordFile( + FileUtils.getCallRecordingFilename(mContext, call.getRemoteAddress())); + } else { + Log.e("[Call Manager] Could not create call params for call"); + return false; + } + + core.acceptCallWithParams(call, params); + return true; + } + + public void setCallInterface(CallActivity.CallActivityInterface callInterface) { + mCallInterface = callInterface; + } + + public void resetCallControlsHidingTimer() { + if (mCallInterface != null) { + mCallInterface.resetCallControlsHidingTimer(); + } + } + + public void refreshInCallActions() { + if (mCallInterface != null) { + mCallInterface.refreshInCallActions(); + } + } + + public void setHandsetMode(Boolean on) { + if (mHandsetON == on) return; + Core core = LinphoneManager.getCore(); + + if (core.isIncomingInvitePending() && on) { + mHandsetON = true; + acceptCall(core.getCurrentCall()); + } else if (on && mCallInterface != null) { + mHandsetON = true; + mCallInterface.setSpeakerEnabled(true); + mCallInterface.refreshInCallActions(); + } else if (!on) { + mHandsetON = false; + terminateCall(); + } } } diff --git a/app/src/main/java/org/linphone/call/CallOutgoingActivity.java b/app/src/main/java/org/linphone/call/CallOutgoingActivity.java index 55fa13bcc..42a1eae85 100644 --- a/app/src/main/java/org/linphone/call/CallOutgoingActivity.java +++ b/app/src/main/java/org/linphone/call/CallOutgoingActivity.java @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import android.Manifest; +import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.view.Gravity; @@ -34,9 +35,10 @@ import android.widget.TextView; import android.widget.Toast; import androidx.core.app.ActivityCompat; import java.util.ArrayList; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; +import org.linphone.LinphoneService; import org.linphone.R; +import org.linphone.activities.LinphoneGenericActivity; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; import org.linphone.core.Address; @@ -47,13 +49,13 @@ import org.linphone.core.CoreListenerStub; import org.linphone.core.Reason; import org.linphone.core.tools.Log; import org.linphone.settings.LinphonePreferences; -import org.linphone.utils.LinphoneGenericActivity; import org.linphone.utils.LinphoneUtils; import org.linphone.views.ContactAvatar; public class CallOutgoingActivity extends LinphoneGenericActivity implements OnClickListener { private TextView mName, mNumber; - private ImageView mMicro, mSpeaker, mHangUp; + private ImageView mMicro; + private ImageView mSpeaker; private Call mCall; private CoreListenerStub mListener; private boolean mIsMicMuted, mIsSpeakerEnabled; @@ -76,21 +78,15 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC mSpeaker = findViewById(R.id.speaker); mSpeaker.setOnClickListener(this); - mHangUp = findViewById(R.id.outgoing_hang_up); - mHangUp.setOnClickListener(this); + ImageView hangUp = findViewById(R.id.outgoing_hang_up); + hangUp.setOnClickListener(this); mListener = new CoreListenerStub() { @Override public void onCallStateChanged( - Core lc, Call call, Call.State state, String message) { - if (call == mCall && State.Connected == state) { - if (!LinphoneActivity.isInstanciated()) { - return; - } - LinphoneActivity.instance().startIncallActivity(); - return; - } else if (state == State.Error) { + Core core, Call call, Call.State state, String message) { + if (state == State.Error) { // Convert Core message for internalization if (call.getErrorInfo().getReason() == Reason.Declined) { displayCustomToast( @@ -125,9 +121,12 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC Toast.LENGTH_SHORT); decline(); } + } else if (state == State.Connected) { + startActivity( + new Intent(CallOutgoingActivity.this, CallActivity.class)); } - if (LinphoneManager.getLc().getCallsNb() == 0) { + if (LinphoneManager.getCore().getCallsNb() == 0) { finish(); } } @@ -137,16 +136,16 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC @Override protected void onResume() { super.onResume(); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.addListener(mListener); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.addListener(mListener); } mCall = null; // Only one call ringing at a time is allowed - if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) { - for (Call call : LinphoneManager.getLc().getCalls()) { + if (LinphoneManager.getCore() != null) { + for (Call call : LinphoneManager.getCore().getCalls()) { State cstate = call.getState(); if (State.OutgoingInit == cstate || State.OutgoingProgress == cstate @@ -155,13 +154,6 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC mCall = call; break; } - if (State.StreamsRunning == cstate) { - if (!LinphoneActivity.isInstanciated()) { - return; - } - LinphoneActivity.instance().startIncallActivity(); - return; - } } } if (mCall == null) { @@ -191,9 +183,9 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC @Override protected void onPause() { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.removeListener(mListener); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.removeListener(mListener); } super.onPause(); } @@ -205,12 +197,16 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC if (id == R.id.micro) { mIsMicMuted = !mIsMicMuted; mMicro.setSelected(mIsMicMuted); - LinphoneManager.getLc().enableMic(!mIsMicMuted); + LinphoneManager.getCore().enableMic(!mIsMicMuted); } if (id == R.id.speaker) { mIsSpeakerEnabled = !mIsSpeakerEnabled; mSpeaker.setSelected(mIsSpeakerEnabled); - LinphoneManager.getInstance().enableSpeaker(mIsSpeakerEnabled); + if (mIsSpeakerEnabled) { + LinphoneManager.getAudioManager().routeAudioToSpeaker(); + } else { + LinphoneManager.getAudioManager().routeAudioToEarPiece(); + } } if (id == R.id.outgoing_hang_up) { decline(); @@ -219,9 +215,9 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (LinphoneManager.isInstanciated() + if (LinphoneService.isReady() && (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME)) { - LinphoneManager.getLc().terminateCall(mCall); + LinphoneManager.getCore().terminateCall(mCall); finish(); } return super.onKeyDown(keyCode, event); @@ -242,7 +238,7 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC } private void decline() { - LinphoneManager.getLc().terminateCall(mCall); + LinphoneManager.getCore().terminateCall(mCall); finish(); } @@ -263,10 +259,21 @@ public class CallOutgoingActivity extends LinphoneGenericActivity implements OnC "[Permission] Camera permission is " + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); + int readPhoneState = + getPackageManager() + .checkPermission(Manifest.permission.READ_PHONE_STATE, getPackageName()); + Log.i( + "[Permission] Read phone state permission is " + + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied")); + if (recordAudio != PackageManager.PERMISSION_GRANTED) { Log.i("[Permission] Asking for record audio"); permissionsList.add(Manifest.permission.RECORD_AUDIO); } + if (readPhoneState != PackageManager.PERMISSION_GRANTED) { + Log.i("[Permission] Asking for read phone state"); + permissionsList.add(Manifest.permission.READ_PHONE_STATE); + } if (LinphonePreferences.instance().shouldInitiateVideoCall() || LinphonePreferences.instance().shouldAutomaticallyAcceptVideoRequests()) { if (camera != PackageManager.PERMISSION_GRANTED) { diff --git a/app/src/main/java/org/linphone/call/CallVideoFragment.java b/app/src/main/java/org/linphone/call/CallVideoFragment.java index 563c4b683..4f70de55b 100644 --- a/app/src/main/java/org/linphone/call/CallVideoFragment.java +++ b/app/src/main/java/org/linphone/call/CallVideoFragment.java @@ -55,13 +55,12 @@ public class CallVideoFragment extends Fragment private CallActivity mInCallActivity; private int mPreviewX, mPreviewY; - @SuppressWarnings("deprecation") - // Warning useless because value is ignored and automatically set by new APIs. @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view; - if (LinphoneManager.getLc().hasCrappyOpengl()) { + Core core = LinphoneManager.getCore(); + if (core.hasCrappyOpengl()) { view = inflater.inflate(R.layout.video_no_opengl, container, false); } else { view = inflater.inflate(R.layout.video, container, false); @@ -70,8 +69,8 @@ public class CallVideoFragment extends Fragment mVideoView = view.findViewById(R.id.videoSurface); mCaptureView = view.findViewById(R.id.videoCaptureSurface); - LinphoneManager.getLc().setNativeVideoWindowId(mVideoView); - LinphoneManager.getLc().setNativePreviewWindowId(mCaptureView); + core.setNativeVideoWindowId(mVideoView); + core.setNativePreviewWindowId(mCaptureView); mVideoView.setOnTouchListener( new OnTouchListener() { @@ -131,11 +130,11 @@ public class CallVideoFragment extends Fragment } private void resizePreview() { - Core lc = LinphoneManager.getLc(); - if (lc.getCallsNb() > 0) { - Call call = lc.getCurrentCall(); + Core core = LinphoneManager.getCore(); + if (core.getCallsNb() > 0) { + Call call = core.getCurrentCall(); if (call == null) { - call = lc.getCalls()[0]; + call = core.getCalls()[0]; } if (call == null) return; @@ -151,7 +150,7 @@ public class CallVideoFragment extends Fragment if (videoSize.getWidth() == 0 || videoSize.getHeight() == 0) { Log.w( "[Video Fragment] Couldn't get sent video definition, using default video definition"); - videoSize = lc.getPreferredVideoDefinition(); + videoSize = core.getPreferredVideoDefinition(); } int width = videoSize.getWidth(); int height = videoSize.getHeight(); @@ -177,8 +176,9 @@ public class CallVideoFragment extends Fragment public void switchCamera() { try { - String currentDevice = LinphoneManager.getLc().getVideoDevice(); - String[] devices = LinphoneManager.getLc().getVideoDevicesList(); + Core core = LinphoneManager.getCore(); + String currentDevice = core.getVideoDevice(); + String[] devices = core.getVideoDevicesList(); int index = 0; for (String d : devices) { if (d.equals(currentDevice)) { @@ -191,9 +191,9 @@ public class CallVideoFragment extends Fragment if (index == 1) newDevice = devices[0]; else if (devices.length > 1) newDevice = devices[1]; else newDevice = devices[index]; - LinphoneManager.getLc().setVideoDevice(newDevice); + core.setVideoDevice(newDevice); - CallManager.getInstance().updateCall(); + LinphoneManager.getCallManager().updateCall(); } catch (ArithmeticException ae) { Log.e("[Video Fragment] Cannot swtich camera : no camera"); } @@ -216,11 +216,11 @@ public class CallVideoFragment extends Fragment @Override public void onPause() { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (LinphonePreferences.instance().isOverlayEnabled() - && lc != null - && lc.getCurrentCall() != null) { - Call call = lc.getCurrentCall(); + && core != null + && core.getCurrentCall() != null) { + Call call = core.getCurrentCall(); if (call.getState() == Call.State.StreamsRunning) { // Prevent overlay creation if video call is paused by remote LinphoneService.instance().createOverlay(); @@ -244,7 +244,7 @@ public class CallVideoFragment extends Fragment 0.1f, Math.min(mZoomFactor, Math.max(portraitZoomFactor, landscapeZoomFactor))); - Call currentCall = LinphoneManager.getLc().getCurrentCall(); + Call currentCall = LinphoneManager.getCore().getCurrentCall(); if (currentCall != null) { currentCall.zoom(mZoomFactor, mZoomCenterX, mZoomCenterY); return true; @@ -254,7 +254,8 @@ public class CallVideoFragment extends Fragment @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (LinphoneUtils.isCallEstablished(LinphoneManager.getLc().getCurrentCall())) { + Core core = LinphoneManager.getCore(); + if (LinphoneUtils.isCallEstablished(core.getCurrentCall())) { if (mZoomFactor > 1) { // Video is zoomed, slide is used to change center of zoom if (distanceX > 0 && mZoomCenterX < 1) { @@ -273,9 +274,7 @@ public class CallVideoFragment extends Fragment if (mZoomCenterY > 1) mZoomCenterY = 1; if (mZoomCenterY < 0) mZoomCenterY = 0; - LinphoneManager.getLc() - .getCurrentCall() - .zoom(mZoomFactor, mZoomCenterX, mZoomCenterY); + core.getCurrentCall().zoom(mZoomFactor, mZoomCenterX, mZoomCenterY); return true; } } @@ -285,7 +284,8 @@ public class CallVideoFragment extends Fragment @Override public boolean onDoubleTap(MotionEvent e) { - if (LinphoneUtils.isCallEstablished(LinphoneManager.getLc().getCurrentCall())) { + Core core = LinphoneManager.getCore(); + if (LinphoneUtils.isCallEstablished(core.getCurrentCall())) { if (mZoomFactor == 1.f) { // Zoom to make the video fill the screen vertically float portraitZoomFactor = @@ -301,7 +301,7 @@ public class CallVideoFragment extends Fragment resetZoom(); } - LinphoneManager.getLc().getCurrentCall().zoom(mZoomFactor, mZoomCenterX, mZoomCenterY); + core.getCurrentCall().zoom(mZoomFactor, mZoomCenterX, mZoomCenterY); return true; } diff --git a/app/src/main/java/org/linphone/chat/ChatActivity.java b/app/src/main/java/org/linphone/chat/ChatActivity.java new file mode 100644 index 000000000..e3624a963 --- /dev/null +++ b/app/src/main/java/org/linphone/chat/ChatActivity.java @@ -0,0 +1,293 @@ +package org.linphone.chat; + +/* +ChatActivity.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.app.Fragment; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.widget.Toast; +import java.util.ArrayList; +import org.linphone.R; +import org.linphone.activities.MainActivity; +import org.linphone.contacts.ContactAddress; +import org.linphone.core.Address; +import org.linphone.core.Factory; +import org.linphone.core.tools.Log; +import org.linphone.utils.FileUtils; + +public class ChatActivity extends MainActivity { + private String mSharedText, mSharedFiles; + + @Override + protected void onCreate(Bundle savedInstanceState) { + getIntent().putExtra("Activity", "Chat"); + super.onCreate(savedInstanceState); + } + + @Override + protected void onStart() { + super.onStart(); + + Fragment currentFragment = getFragmentManager().findFragmentById(R.id.fragmentContainer); + if (currentFragment == null) { + if (getIntent() != null && getIntent().getExtras() != null) { + Bundle extras = getIntent().getExtras(); + if (isTablet() || !extras.containsKey("RemoteSipUri")) { + showChatRooms(); + } + + handleRemoteSipUriInIntentExtras(extras); + // Remove the SIP Uri from the intent so a click on chat button will go back to list + getIntent().removeExtra("RemoteSipUri"); + } else { + showChatRooms(); + if (isTablet()) { + showEmptyChildFragment(); + } + } + } + + handleIntentExtras(getIntent()); + } + + @Override + protected void onResume() { + super.onResume(); + mChatSelected.setVisibility(View.VISIBLE); + } + + @Override + protected void onPause() { + super.onPause(); + getIntent().setAction(""); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString("SharedText", mSharedText); + outState.putString("SharedFiles", mSharedFiles); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + mSharedText = savedInstanceState.getString("SharedText", null); + mSharedFiles = savedInstanceState.getString("SharedFiles", null); + } + + @Override + public void goBack() { + // 1 is for the empty fragment on tablets + if (!isTablet() || getFragmentManager().getBackStackEntryCount() > 1) { + if (popBackStack()) { + return; + } + } + super.goBack(); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + // Clean fragments stack upon return + while (getFragmentManager().getBackStackEntryCount() > 0) { + getFragmentManager().popBackStackImmediate(); + } + + handleIntentExtras(intent); + } + + private void handleIntentExtras(Intent intent) { + if (intent == null) return; + + String sharedText = null; + String sharedFiles = null; + + String action = intent.getAction(); + String type = intent.getType(); + if (Intent.ACTION_SEND.equals(action) && type != null) { + if (("text/plain").equals(type) && intent.getStringExtra(Intent.EXTRA_TEXT) != null) { + sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); + Log.i("[Chat Activity] ACTION_SEND with text/plain data: " + sharedText); + } else { + Uri fileUri = intent.getParcelableExtra(Intent.EXTRA_STREAM); + sharedFiles = FileUtils.getFilePath(this, fileUri); + Log.i("[Chat Activity] ACTION_SEND with file: " + sharedFiles); + } + } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) { + if (type.startsWith("image/")) { + ArrayList imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); + StringBuilder filePaths = new StringBuilder(); + for (Uri uri : imageUris) { + filePaths.append(FileUtils.getFilePath(this, uri)); + filePaths.append(":"); + } + sharedFiles = filePaths.toString(); + Log.i("[Chat Activity] ACTION_SEND_MULTIPLE with files: " + sharedFiles); + } + } else { + if (intent.getExtras() != null) { + Bundle extras = intent.getExtras(); + handleRemoteSipUriInIntentExtras(extras); + } else { + // If there is no extras, make sure the chat rooms list fragment is displayed + Fragment currentFragment = + getFragmentManager().findFragmentById(R.id.fragmentContainer); + if (currentFragment == null || !(currentFragment instanceof ChatRoomsFragment)) { + showChatRooms(); + } + } + } + + if (sharedText != null || sharedFiles != null) { + mSharedText = sharedText; + mSharedFiles = sharedFiles; + Toast.makeText(this, R.string.toast_choose_chat_room_for_sharing, Toast.LENGTH_LONG) + .show(); + Log.i("[Chat Activity] Sharing arguments found: " + mSharedText + " / " + mSharedFiles); + } + } + + private void handleRemoteSipUriInIntentExtras(Bundle extras) { + if (extras == null) return; + + if (extras.containsKey("RemoteSipUri")) { + String remoteSipUri = extras.getString("RemoteSipUri", null); + String localSipUri = extras.getString("LocalSipUri", null); + + Address localAddress = null; + Address remoteAddress = null; + if (localSipUri != null) { + localAddress = Factory.instance().createAddress(localSipUri); + } + if (remoteSipUri != null) { + remoteAddress = Factory.instance().createAddress(remoteSipUri); + } + // Don't make it a child on smartphones to have a working back button + showChatRoom(localAddress, remoteAddress, isTablet()); + } + } + + private void showChatRooms() { + ChatRoomsFragment fragment = new ChatRoomsFragment(); + changeFragment(fragment, "Chat rooms", false); + } + + private void showChatRoom(Address localAddress, Address peerAddress, boolean isChild) { + Bundle extras = new Bundle(); + if (localAddress != null) { + extras.putSerializable("LocalSipUri", localAddress.asStringUriOnly()); + } + if (peerAddress != null) { + extras.putSerializable("RemoteSipUri", peerAddress.asStringUriOnly()); + } + if (mSharedText != null) { + extras.putString("SharedText", mSharedText); + mSharedText = null; + } + if (mSharedFiles != null) { + extras.putString("SharedFiles", mSharedFiles); + mSharedFiles = null; + } + + ChatMessagesFragment fragment = new ChatMessagesFragment(); + fragment.setArguments(extras); + changeFragment(fragment, "Chat room", isChild); + } + + public void showChatRoom(Address localAddress, Address peerAddress) { + showChatRoom(localAddress, peerAddress, true); + } + + public void showImdn(Address localAddress, Address peerAddress, String messageId) { + Bundle extras = new Bundle(); + if (localAddress != null) { + extras.putSerializable("LocalSipUri", localAddress.asStringUriOnly()); + } + if (peerAddress != null) { + extras.putSerializable("RemoteSipUri", peerAddress.asStringUriOnly()); + } + extras.putString("MessageId", messageId); + + ImdnFragment fragment = new ImdnFragment(); + fragment.setArguments(extras); + changeFragment(fragment, "Chat message IMDN", true); + } + + public void showDevices(Address localAddress, Address peerAddress) { + showDevices(localAddress, peerAddress, true); + } + + private void showDevices(Address localAddress, Address peerAddress, boolean isChild) { + Bundle extras = new Bundle(); + if (localAddress != null) { + extras.putSerializable("LocalSipUri", localAddress.asStringUriOnly()); + } + if (peerAddress != null) { + extras.putSerializable("RemoteSipUri", peerAddress.asStringUriOnly()); + } + + DevicesFragment fragment = new DevicesFragment(); + fragment.setArguments(extras); + changeFragment(fragment, "Chat room devices", isChild); + } + + public void showChatRoomCreation( + Address peerAddress, + ArrayList participants, + String subject, + boolean encrypted, + boolean isGroupChatRoom) { + Bundle extras = new Bundle(); + if (peerAddress != null) { + extras.putSerializable("RemoteSipUri", peerAddress.asStringUriOnly()); + } + extras.putSerializable("Participants", participants); + extras.putString("Subject", subject); + extras.putBoolean("Encrypted", encrypted); + extras.putBoolean("IsGroupChatRoom", isGroupChatRoom); + + ChatRoomCreationFragment fragment = new ChatRoomCreationFragment(); + fragment.setArguments(extras); + changeFragment(fragment, "Chat room creation", true); + } + + public void showChatRoomGroupInfo( + Address peerAddress, + ArrayList participants, + String subject, + boolean encrypted) { + Bundle extras = new Bundle(); + if (peerAddress != null) { + extras.putSerializable("RemoteSipUri", peerAddress.asStringUriOnly()); + } + extras.putSerializable("Participants", participants); + extras.putString("Subject", subject); + extras.putBoolean("Encrypted", encrypted); + + GroupInfoFragment fragment = new GroupInfoFragment(); + fragment.setArguments(extras); + changeFragment(fragment, "Chat room group info", true); + } +} diff --git a/app/src/main/java/org/linphone/chat/ChatMessageOldViewHolder.java b/app/src/main/java/org/linphone/chat/ChatMessageOldViewHolder.java deleted file mode 100644 index 452d1a01e..000000000 --- a/app/src/main/java/org/linphone/chat/ChatMessageOldViewHolder.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.linphone.chat; - -/* -ChatMessageViewHolder.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -import android.view.View; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.RelativeLayout; -import android.widget.TextView; -import androidx.recyclerview.widget.RecyclerView; -import org.linphone.R; - -public class ChatMessageOldViewHolder extends RecyclerView.ViewHolder - implements View.OnClickListener { - public final LinearLayout eventLayout; - public final TextView eventMessage; - - public final RelativeLayout bubbleLayout; - public final LinearLayout separatorLayout; - public final LinearLayout background; - public final RelativeLayout avatarLayout; - public final TextView contactName; - - public final ImageView messageStatus; - public final ProgressBar messageSendingInProgress; - public final LinearLayout imdmLayout; - public final ImageView imdmIcon; - public final TextView imdmLabel; - - public final TextView messageText; - public final ImageView messageImage; - - public final RelativeLayout fileTransferLayout; - public final ProgressBar fileTransferProgressBar; - public final Button fileTransferAction; - - public final TextView fileName; - public final Button openFileButton; - - public final CheckBox delete; - - private ChatMessageViewHolderClickListener mListener; - - public ChatMessageOldViewHolder(View view, ChatMessageViewHolderClickListener listener) { - this(view); - mListener = listener; - view.setOnClickListener(this); - } - - public ChatMessageOldViewHolder(View view) { - super(view); - eventLayout = view.findViewById(R.id.event); - // eventTime = view.findViewById(R.id.event_date); - eventMessage = view.findViewById(R.id.event_text); - - bubbleLayout = view.findViewById(R.id.bubble); - background = view.findViewById(R.id.background); - avatarLayout = view.findViewById(R.id.avatar_layout); - contactName = view.findViewById(R.id.contact_header); - - messageStatus = view.findViewById(R.id.status); - messageSendingInProgress = view.findViewById(R.id.inprogress); - imdmLayout = view.findViewById(R.id.imdmLayout); - imdmIcon = view.findViewById(R.id.imdmIcon); - imdmLabel = view.findViewById(R.id.imdmText); - - messageText = view.findViewById(R.id.message); - messageImage = view.findViewById(R.id.image); - separatorLayout = view.findViewById(R.id.separator); - - fileTransferLayout = view.findViewById(R.id.file_transfer_layout); - fileTransferProgressBar = view.findViewById(R.id.progress_bar); - fileTransferAction = view.findViewById(R.id.file_transfer_action); - - fileName = view.findViewById(R.id.file_name); - openFileButton = view.findViewById(R.id.open_file); - - delete = view.findViewById(R.id.delete_message); - } - - @Override - public void onClick(View v) { - if (mListener != null) { - mListener.onItemClicked(getAdapterPosition()); - } - } -} diff --git a/app/src/main/java/org/linphone/chat/ChatMessageViewHolder.java b/app/src/main/java/org/linphone/chat/ChatMessageViewHolder.java index d3177f56c..6bda27e9e 100644 --- a/app/src/main/java/org/linphone/chat/ChatMessageViewHolder.java +++ b/app/src/main/java/org/linphone/chat/ChatMessageViewHolder.java @@ -2,7 +2,7 @@ package org.linphone.chat; /* ChatMessageViewHolder.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -45,7 +45,6 @@ import com.google.android.flexbox.FlexboxLayout; import java.io.File; import java.util.ArrayList; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.R; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; @@ -71,13 +70,14 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi public final LinearLayout background; public final RelativeLayout avatarLayout; - public final ProgressBar downloadInProgress, sendInProgress; + private final ProgressBar downloadInProgress; + public final ProgressBar sendInProgress; public final TextView timeText; - public final ImageView outgoingImdn; - public final TextView messageText; + private final ImageView outgoingImdn; + private final TextView messageText; - public final FlexboxLayout multiFileContents; - public final RelativeLayout singleFileContent; + private final FlexboxLayout multiFileContents; + private final RelativeLayout singleFileContent; public final CheckBox delete; @@ -92,7 +92,7 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi view.setOnClickListener(this); } - public ChatMessageViewHolder(View view) { + private ChatMessageViewHolder(View view) { super(view); eventLayout = view.findViewById(R.id.event); eventMessage = view.findViewById(R.id.event_text); @@ -174,8 +174,7 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi background.setBackgroundResource(R.drawable.chat_bubble_incoming_full); // Can't anchor incoming messages, setting this to align max width with LIME icon - bubbleLayout.setPadding( - 0, 0, (int) ImageUtils.dpToPixels(LinphoneActivity.instance(), 18), 0); + bubbleLayout.setPadding(0, 0, (int) ImageUtils.dpToPixels(mContext, 18), 0); if (status == ChatMessage.State.FileTransferInProgress) { downloadInProgress.setVisibility(View.VISIBLE); @@ -325,7 +324,8 @@ public class ChatMessageViewHolder extends RecyclerView.ViewHolder implements Vi } else { Log.w( "WRITE_EXTERNAL_STORAGE permission not granted, won't be able to store the downloaded file"); - LinphoneActivity.instance().checkAndRequestExternalStoragePermission(); + ((ChatActivity) mContext) + .requestPermissionIfNotGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE); } } } diff --git a/app/src/main/java/org/linphone/chat/ChatMessageViewHolderClickListener.java b/app/src/main/java/org/linphone/chat/ChatMessageViewHolderClickListener.java index e5b49ebb2..a6ab1dd8c 100644 --- a/app/src/main/java/org/linphone/chat/ChatMessageViewHolderClickListener.java +++ b/app/src/main/java/org/linphone/chat/ChatMessageViewHolderClickListener.java @@ -2,7 +2,7 @@ package org.linphone.chat; /* ChatMessageViewHolderClickListener.java -Copyright (C) 2018 Belledonne Communications, Grenoble, France +Copyright (C) 2018 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 diff --git a/app/src/main/java/org/linphone/chat/ChatMessagesAdapter.java b/app/src/main/java/org/linphone/chat/ChatMessagesAdapter.java index 95eb0b0df..b06388107 100644 --- a/app/src/main/java/org/linphone/chat/ChatMessagesAdapter.java +++ b/app/src/main/java/org/linphone/chat/ChatMessagesAdapter.java @@ -2,7 +2,7 @@ package org.linphone.chat; /* ChatMessagesAdapter.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 diff --git a/app/src/main/java/org/linphone/chat/ChatMessagesFragment.java b/app/src/main/java/org/linphone/chat/ChatMessagesFragment.java index ea81d0150..183ee503c 100644 --- a/app/src/main/java/org/linphone/chat/ChatMessagesFragment.java +++ b/app/src/main/java/org/linphone/chat/ChatMessagesFragment.java @@ -2,7 +2,7 @@ package org.linphone.chat; /* ChatMessagesFragment.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -20,8 +20,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import static android.content.Context.INPUT_METHOD_SERVICE; -import static org.linphone.fragments.FragmentsAvailable.CHAT; +import android.Manifest; import android.app.Activity; import android.app.Dialog; import android.app.Fragment; @@ -61,11 +61,10 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.LinphoneService; import org.linphone.R; -import org.linphone.call.CallManager; +import org.linphone.call.CallActivity; import org.linphone.contacts.ContactAddress; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.ContactsUpdatedListener; @@ -103,7 +102,9 @@ public class ChatMessagesFragment extends Fragment private static final String COMMIT_CONTENT_FLAGS_KEY = "COMMIT_CONTENT_FLAGS"; private final Handler mHandler = new Handler(Looper.getMainLooper()); - private ImageView mBackButton, mCallButton, mBackToCallButton, mGroupInfosButton; + private ImageView mCallButton; + private ImageView mBackToCallButton; + private ImageView mGroupInfosButton; private ImageView mAttachImageButton, mSendMessageButton; private TextView mRoomLabel, mParticipantsLabel, mSipUriLabel, mRemoteComposing; private RichEditText mMessageTextToSend; @@ -114,20 +115,15 @@ public class ChatMessagesFragment extends Fragment private Context mContext; private ViewTreeObserver.OnGlobalLayoutListener mKeyboardListener; private Uri mImageToUploadUri; - private ChatMessagesAdapter mEventsAdapter; - private ChatMessagesOldAdapter mOldEventsAdapter; - private String mLocalSipUri, mRemoteSipUri; + private String mRemoteSipUri; private Address mLocalSipAddress, mRemoteSipAddress, mRemoteParticipantAddress; private ChatRoom mChatRoom; private ArrayList mParticipants; - private LinearLayoutManager layoutManager; private int mContextMenuMessagePosition; - private ChatScrollListener mChatScrollListener; private LinearLayout mTopBar; private ImageView mChatRoomSecurityLevel; private InputContentInfoCompat mCurrentInputContentInfo; - private int mCurrentFlags; @Override public View onCreateView( @@ -138,12 +134,12 @@ public class ChatMessagesFragment extends Fragment if (getArguments() != null) { if (getArguments().getString("LocalSipUri") != null) { - mLocalSipUri = getArguments().getString("LocalSipUri"); - mLocalSipAddress = LinphoneManager.getLc().createAddress(mLocalSipUri); + String mLocalSipUri = getArguments().getString("LocalSipUri"); + mLocalSipAddress = Factory.instance().createAddress(mLocalSipUri); } if (getArguments().getString("RemoteSipUri") != null) { mRemoteSipUri = getArguments().getString("RemoteSipUri"); - mRemoteSipAddress = LinphoneManager.getLc().createAddress(mRemoteSipUri); + mRemoteSipAddress = Factory.instance().createAddress(mRemoteSipUri); } } @@ -173,36 +169,34 @@ public class ChatMessagesFragment extends Fragment if (oneParticipantOneDevice) { ParticipantDevice device = mChatRoom.getParticipants()[0].getDevices()[0]; - CallManager.getInstance().inviteAddress(device.getAddress(), true); + LinphoneManager.getCallManager() + .inviteAddress(device.getAddress(), true); } else { - LinphoneActivity.instance() - .goToContactDevicesInfos(mLocalSipUri, mRemoteSipUri); + ((ChatActivity) getActivity()) + .showDevices(mLocalSipAddress, mRemoteSipAddress); } } } }); - mBackButton = view.findViewById(R.id.back); - if (getResources().getBoolean(R.bool.isTablet)) { - mBackButton.setVisibility(View.INVISIBLE); - } else { - mBackButton.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View view) { - LinphoneActivity.instance().goToChatList(); - } - }); - } + ImageView backButton = view.findViewById(R.id.back); + backButton.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View view) { + ((ChatActivity) getActivity()).goBack(); + } + }); + backButton.setVisibility( + getResources().getBoolean(R.bool.isTablet) ? View.INVISIBLE : View.VISIBLE); mCallButton = view.findViewById(R.id.start_call); mCallButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { - LinphoneActivity.instance() - .setAddresGoToDialerAndCall( - mRemoteParticipantAddress.asString(), null); + LinphoneManager.getCallManager() + .newOutgoingCall(mRemoteParticipantAddress.asString(), null); } }); @@ -211,8 +205,7 @@ public class ChatMessagesFragment extends Fragment new View.OnClickListener() { @Override public void onClick(View view) { - LinphoneActivity.instance() - .resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); + startActivity(new Intent(getActivity(), CallActivity.class)); } }); @@ -233,20 +226,18 @@ public class ChatMessagesFragment extends Fragment c.setFullName(displayName); } ContactAddress ca = - new ContactAddress( - c, a.asString(), "", c.isFriend(), p.isAdmin()); + new ContactAddress(c, a.asString(), "", p.isAdmin()); participants.add(ca); } - LinphoneActivity.instance() - .goToChatGroupInfos( - mRemoteSipAddress.asString(), + + boolean encrypted = + mChatRoom.hasCapability(ChatRoomCapabilities.Encrypted.toInt()); + ((ChatActivity) getActivity()) + .showChatRoomGroupInfo( + mRemoteSipAddress, participants, mChatRoom.getSubject(), - mChatRoom.getMe() != null && mChatRoom.getMe().isAdmin(), - false, - null, - mChatRoom.hasCapability( - ChatRoomCapabilities.Encrypted.toInt())); + encrypted); } }); @@ -261,7 +252,10 @@ public class ChatMessagesFragment extends Fragment new View.OnClickListener() { @Override public void onClick(View view) { - LinphoneActivity.instance().checkAndRequestPermissionsToSendImage(); + String[] permissions = { + Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE + }; + ((ChatActivity) getActivity()).requestPermissionsIfNotGranted(permissions); pickFile(); } }); @@ -308,21 +302,21 @@ public class ChatMessagesFragment extends Fragment mChatEventsList = view.findViewById(R.id.chat_message_list); mSelectionHelper = new SelectableHelper(view, this); - layoutManager = + LinearLayoutManager layoutManager = new LinphoneLinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, true); mChatEventsList.setLayoutManager(layoutManager); - mChatScrollListener = + ChatScrollListener chatScrollListener = new ChatScrollListener(layoutManager) { @Override public void onLoadMore(int totalItemsCount) { loadMoreData(totalItemsCount); } }; - mChatEventsList.addOnScrollListener(mChatScrollListener); + mChatEventsList.addOnScrollListener(chatScrollListener); if (getArguments() != null) { - String fileSharedUri = getArguments().getString("fileSharedUri"); + String fileSharedUri = getArguments().getString("SharedFiles"); if (fileSharedUri != null) { Log.i("[ChatMessages] Found shared file(s): " + fileSharedUri); if (fileSharedUri.contains(":")) { @@ -335,8 +329,8 @@ public class ChatMessagesFragment extends Fragment } } - if (getArguments().getString("messageDraft") != null) { - String sharedText = getArguments().getString("messageDraft"); + if (getArguments().containsKey("SharedText")) { + String sharedText = getArguments().getString("SharedText"); mMessageTextToSend.setText(sharedText); Log.i("[ChatMessages] Found shared text: " + sharedText); } @@ -353,9 +347,6 @@ public class ChatMessagesFragment extends Fragment public void onResume() { super.onResume(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(CHAT); - } ContactsManager.getInstance().addContactsListener(this); addVirtualKeyboardVisiblityListener(); @@ -375,32 +366,18 @@ public class ChatMessagesFragment extends Fragment initChatRoom(); displayChatRoomHeader(); displayChatRoomHistory(); - LinphoneManager.getInstance().setCurrentChatRoomAddress(mRemoteSipAddress); - if (LinphoneManager.getInstance().hasLastCallSasBeenRejected()) { - LinphoneManager.getInstance().lastCallSasRejected(false); - LinphoneUtils.showTrustDeniedDialog(getActivity()); - } - } - - public void changeDisplayedChat(String localSipUri, String remoteSipUri) { - mLocalSipUri = localSipUri; - mLocalSipAddress = LinphoneManager.getLc().createAddress(mLocalSipUri); - mRemoteSipUri = remoteSipUri; - mRemoteSipAddress = LinphoneManager.getLc().createAddress(mRemoteSipUri); - - initChatRoom(); - displayChatRoomHeader(); - displayChatRoomHistory(); - - LinphoneManager.getInstance().setCurrentChatRoomAddress(mRemoteSipAddress); + LinphoneService.instance() + .getNotificationManager() + .setCurrentlyDisplayedChatRoom( + mRemoteSipAddress != null ? mRemoteSipAddress.asStringUriOnly() : null); } @Override public void onPause() { ContactsManager.getInstance().removeContactsListener(this); removeVirtualKeyboardVisiblityListener(); - LinphoneManager.getInstance().setCurrentChatRoomAddress(null); + LinphoneService.instance().getNotificationManager().setCurrentlyDisplayedChatRoom(null); if (mChatRoom != null) mChatRoom.removeListener(this); if (mChatEventsList.getAdapter() != null) ((ChatMessagesGenericAdapter) mChatEventsList.getAdapter()).clear(); @@ -466,16 +443,6 @@ public class ChatMessagesFragment extends Fragment public void onDeleteSelection(Object[] objectsToDelete) { for (Object obj : objectsToDelete) { EventLog eventLog = (EventLog) obj; - if (eventLog.getType() == EventLog.Type.ConferenceChatMessage) { - ChatMessage message = eventLog.getChatMessage(); - if (message.getAppdata() != null && !message.isOutgoing()) { - File file = new File(message.getAppdata()); - if (file.exists()) { - // Delete downloaded file from incoming message that will be deleted - file.delete(); - } - } - } eventLog.deleteFromDatabase(); } if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { @@ -492,13 +459,8 @@ public class ChatMessagesFragment extends Fragment ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); - if (mContext.getResources().getBoolean(R.bool.use_new_chat_bubbles_layout)) { - ChatMessageViewHolder holder = (ChatMessageViewHolder) v.getTag(); - mContextMenuMessagePosition = holder.getAdapterPosition(); - } else { - ChatMessageOldViewHolder holder = (ChatMessageOldViewHolder) v.getTag(); - mContextMenuMessagePosition = holder.getAdapterPosition(); - } + ChatMessageViewHolder holder = (ChatMessageViewHolder) v.getTag(); + mContextMenuMessagePosition = holder.getAdapterPosition(); EventLog event = (EventLog) @@ -559,8 +521,7 @@ public class ChatMessagesFragment extends Fragment return true; } if (item.getItemId() == R.id.imdn_infos) { - LinphoneActivity.instance() - .goToChatMessageImdnInfos(mLocalSipUri, mRemoteSipUri, messageId); + ((ChatActivity) getActivity()).showImdn(mLocalSipAddress, mRemoteSipAddress, messageId); return true; } if (item.getItemId() == R.id.copy_text) { @@ -582,13 +543,8 @@ public class ChatMessagesFragment extends Fragment if (item.getItemId() == R.id.add_to_contacts) { Address address = message.getFromAddress(); if (address == null) return true; - String uri = address.getUsername() + "@" + address.getDomain(); // Get a clean address - if (address.getDisplayName() != null) { - LinphoneActivity.instance() - .displayContactsForEdition(uri, address.getDisplayName()); - } else { - LinphoneActivity.instance().displayContactsForEdition(uri); - } + address.clean(); + ((ChatActivity) getActivity()).showContactsListForCreationOrEdition(address); return true; } return super.onContextItemSelected(item); @@ -682,16 +638,16 @@ public class ChatMessagesFragment extends Fragment } private void showKeyboardVisibleMode() { - LinphoneActivity.instance().hideTabBar(true); - LinphoneActivity.instance().hideStatusBar(); + ((ChatActivity) getActivity()).hideTabBar(); + ((ChatActivity) getActivity()).hideStatusBar(); mTopBar.setVisibility(View.GONE); } private void hideKeyboardVisibleMode() { - LinphoneActivity.instance() - .hideTabBar( - getResources().getBoolean(R.bool.hide_bottom_bar_on_second_level_views)); - LinphoneActivity.instance().showStatusBar(); + if (getResources().getBoolean(R.bool.hide_bottom_bar_on_second_level_views)) { + ((ChatActivity) getActivity()).showTabBar(); + } + ((ChatActivity) getActivity()).showStatusBar(); mTopBar.setVisibility(View.VISIBLE); } @@ -740,7 +696,7 @@ public class ChatMessagesFragment extends Fragment mChatRoom.removeListener(this); } - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (mRemoteSipAddress == null || mRemoteSipUri == null || mRemoteSipUri.length() == 0 @@ -756,8 +712,8 @@ public class ChatMessagesFragment extends Fragment } mChatRoom.addListener(this); mChatRoom.markAsRead(); - LinphoneManager.getInstance().updateUnreadCountForChatRoom(mChatRoom, 0); - LinphoneActivity.instance().refreshMissedChatCountDisplay(); + + ((ChatActivity) getActivity()).displayMissedChats(); mRemoteParticipantAddress = mRemoteSipAddress; if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt()) @@ -771,7 +727,7 @@ public class ChatMessagesFragment extends Fragment } private void displayChatRoomHeader() { - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core == null || mChatRoom == null) return; if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { @@ -846,6 +802,7 @@ public class ChatMessagesFragment extends Fragment private void displayChatRoomHistory() { if (mChatRoom == null) return; + ChatMessagesAdapter mEventsAdapter; if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { mEventsAdapter = new ChatMessagesAdapter( @@ -855,14 +812,6 @@ public class ChatMessagesFragment extends Fragment mChatRoom.getHistoryMessageEvents(MESSAGES_PER_PAGE), mParticipants, this); - mOldEventsAdapter = - new ChatMessagesOldAdapter( - this, - mSelectionHelper, - R.layout.chat_bubble_old, - mChatRoom.getHistoryMessageEvents(MESSAGES_PER_PAGE), - mParticipants, - this); } else { mEventsAdapter = new ChatMessagesAdapter( @@ -872,28 +821,16 @@ public class ChatMessagesFragment extends Fragment mChatRoom.getHistoryEvents(MESSAGES_PER_PAGE), mParticipants, this); - mOldEventsAdapter = - new ChatMessagesOldAdapter( - this, - mSelectionHelper, - R.layout.chat_bubble_old, - mChatRoom.getHistoryEvents(MESSAGES_PER_PAGE), - mParticipants, - this); - } - if (mContext.getResources().getBoolean(R.bool.use_new_chat_bubbles_layout)) { - mSelectionHelper.setAdapter(mEventsAdapter); - mChatEventsList.setAdapter(mEventsAdapter); - } else { - mSelectionHelper.setAdapter(mOldEventsAdapter); - mChatEventsList.setAdapter(mOldEventsAdapter); } + mSelectionHelper.setAdapter(mEventsAdapter); + mChatEventsList.setAdapter(mEventsAdapter); scrollToBottom(); } private void showSecurityDialog(boolean oneParticipantOneDevice) { final Dialog dialog = - LinphoneActivity.instance().displayDialog(getString(R.string.lime_security_popup)); + ((ChatActivity) getActivity()) + .displayDialog(getString(R.string.lime_security_popup)); Button delete = dialog.findViewById(R.id.dialog_delete_button); delete.setVisibility(View.GONE); Button ok = dialog.findViewById(R.id.dialog_ok_button); @@ -926,10 +863,11 @@ public class ChatMessagesFragment extends Fragment if (oneParticipantOneDevice) { ParticipantDevice device = mChatRoom.getParticipants()[0].getDevices()[0]; - CallManager.getInstance().inviteAddress(device.getAddress(), true); + LinphoneManager.getCallManager() + .inviteAddress(device.getAddress(), true); } else { - LinphoneActivity.instance() - .goToContactDevicesInfos(mLocalSipUri, mRemoteSipUri); + ((ChatActivity) getActivity()) + .showDevices(mLocalSipAddress, mRemoteSipAddress); } dialog.dismiss(); @@ -960,31 +898,8 @@ public class ChatMessagesFragment extends Fragment } } - /** File transfer related */ - @Override - public void onSaveInstanceState(Bundle outState) { - if (mFilesUploadLayout != null) { - String files[] = new String[mFilesUploadLayout.getChildCount()]; - for (int i = 0; i < mFilesUploadLayout.getChildCount(); i++) { - View child = mFilesUploadLayout.getChildAt(i); - String path = (String) child.getTag(); - files[i] = path; - } - outState.putStringArray("Files", files); - } - - if (mCurrentInputContentInfo != null) { - outState.putParcelable( - INPUT_CONTENT_INFO_KEY, (Parcelable) mCurrentInputContentInfo.unwrap()); - outState.putInt(COMMIT_CONTENT_FLAGS_KEY, mCurrentFlags); - } - mCurrentInputContentInfo = null; - mCurrentFlags = 0; - super.onSaveInstanceState(outState); - } - private void onRestoreInstanceState(Bundle savedInstanceState) { - String files[] = savedInstanceState.getStringArray("Files"); + String[] files = savedInstanceState.getStringArray("Files"); if (files != null && files.length > 0) { for (String file : files) { if (FileUtils.isExtensionImage(file)) { @@ -1011,9 +926,7 @@ public class ChatMessagesFragment extends Fragment new File( FileUtils.getStorageDirectory(mContext), getString(R.string.temp_photo_name_with_date) - .replace( - "%s", - String.valueOf(System.currentTimeMillis()) + ".jpeg")); + .replace("%s", System.currentTimeMillis() + ".jpeg")); mImageToUploadUri = Uri.fromFile(file); captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageToUploadUri); cameraIntents.add(captureIntent); @@ -1202,37 +1115,9 @@ public class ChatMessagesFragment extends Fragment final Address from = msg.getFromAddress(); final LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(from); - if (LinphoneActivity.instance().isOnBackground()) { - if (!getResources().getBoolean(R.bool.disable_chat_message_notification)) { - if (contact != null) { - LinphoneService.instance() - .getNotificationManager() - .displayMessageNotification( - from.asStringUriOnly(), - contact.getFullName(), - contact.getThumbnailUri(), - getString(R.string.message_cant_be_decrypted_notif), - cr.getLocalAddress(), - msg.getTime(), - null, - null); - } else { - LinphoneService.instance() - .getNotificationManager() - .displayMessageNotification( - from.asStringUriOnly(), - from.getUsername(), - null, - getString(R.string.message_cant_be_decrypted_notif), - cr.getLocalAddress(), - msg.getTime(), - null, - null); - } - } - } else if (LinphoneManager.getLc().limeEnabled() == LimeState.Mandatory) { + if (LinphoneManager.getCore().limeEnabled() == LimeState.Mandatory) { final Dialog dialog = - LinphoneActivity.instance() + ((ChatActivity) getActivity()) .displayDialog( getString(R.string.message_cant_be_decrypted) .replace( @@ -1248,7 +1133,7 @@ public class ChatMessagesFragment extends Fragment new View.OnClickListener() { @Override public void onClick(View view) { - LinphoneManager.getInstance() + LinphoneManager.getCallManager() .newOutgoingCall( from.asStringUriOnly(), (contact != null) @@ -1272,8 +1157,7 @@ public class ChatMessagesFragment extends Fragment @Override public void onChatMessageReceived(ChatRoom cr, EventLog event) { cr.markAsRead(); - LinphoneManager.getInstance().updateUnreadCountForChatRoom(mChatRoom, 0); - LinphoneActivity.instance().refreshMissedChatCountDisplay(); + ((ChatActivity) getActivity()).displayMissedChats(); ChatMessage msg = event.getChatMessage(); if (msg.getErrorInfo() != null @@ -1290,7 +1174,8 @@ public class ChatMessagesFragment extends Fragment String externalBodyUrl = msg.getExternalBodyUrl(); Content fileTransferContent = msg.getFileTransferInformation(); if (externalBodyUrl != null || fileTransferContent != null) { - LinphoneActivity.instance().checkAndRequestExternalStoragePermission(); + ((ChatActivity) getActivity()) + .requestPermissionIfNotGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE); } ((ChatMessagesGenericAdapter) mChatEventsList.getAdapter()).addToHistory(event); @@ -1433,6 +1318,8 @@ public class ChatMessagesFragment extends Fragment @Override public void onContactsUpdated() { getContactsForParticipants(); + displayChatRoomHeader(); + mChatEventsList.getAdapter().notifyDataSetChanged(); } @Override @@ -1481,7 +1368,6 @@ public class ChatMessagesFragment extends Fragment } mCurrentInputContentInfo = inputContentInfo; - mCurrentFlags = flags; return true; } diff --git a/app/src/main/java/org/linphone/chat/ChatMessagesGenericAdapter.java b/app/src/main/java/org/linphone/chat/ChatMessagesGenericAdapter.java index b9e90ffd6..3a4e4cd37 100644 --- a/app/src/main/java/org/linphone/chat/ChatMessagesGenericAdapter.java +++ b/app/src/main/java/org/linphone/chat/ChatMessagesGenericAdapter.java @@ -2,7 +2,7 @@ package org.linphone.chat; /* ChatMessagesGenericAdapter.java -Copyright (C) 2018 Belledonne Communications, Grenoble, France +Copyright (C) 2018 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 diff --git a/app/src/main/java/org/linphone/chat/ChatMessagesOldAdapter.java b/app/src/main/java/org/linphone/chat/ChatMessagesOldAdapter.java deleted file mode 100644 index c45eff20a..000000000 --- a/app/src/main/java/org/linphone/chat/ChatMessagesOldAdapter.java +++ /dev/null @@ -1,662 +0,0 @@ -package org.linphone.chat; - -/* -ChatMessagesAdapter.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; - -import android.Manifest; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.text.Spanned; -import android.text.method.LinkMovementMethod; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.webkit.MimeTypeMap; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import androidx.annotation.NonNull; -import androidx.core.content.FileProvider; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.linphone.LinphoneActivity; -import org.linphone.LinphoneManager; -import org.linphone.R; -import org.linphone.compatibility.Compatibility; -import org.linphone.contacts.ContactsManager; -import org.linphone.contacts.LinphoneContact; -import org.linphone.core.Address; -import org.linphone.core.ChatMessage; -import org.linphone.core.ChatMessageListenerStub; -import org.linphone.core.Content; -import org.linphone.core.EventLog; -import org.linphone.core.LimeState; -import org.linphone.core.tools.Log; -import org.linphone.utils.FileUtils; -import org.linphone.utils.LinphoneUtils; -import org.linphone.utils.SelectableAdapter; -import org.linphone.utils.SelectableHelper; -import org.linphone.views.AsyncBitmap; -import org.linphone.views.BitmapWorkerTask; -import org.linphone.views.ContactAvatar; - -public class ChatMessagesOldAdapter extends SelectableAdapter - implements ChatMessagesGenericAdapter { - - private static final int MARGIN_BETWEEN_MESSAGES = 10; - private static final int SIDE_MARGIN = 100; - private final Context mContext; - private List mHistory; - private List mParticipants; - private final int mItemResource; - private Bitmap mDefaultBitmap; - private final ChatMessagesFragment mFragment; - private final ChatMessageListenerStub mListener; - - private final ChatMessageViewHolderClickListener mClickListener; - - public ChatMessagesOldAdapter( - ChatMessagesFragment fragment, - SelectableHelper helper, - int itemResource, - EventLog[] history, - ArrayList participants, - ChatMessageViewHolderClickListener clickListener) { - super(helper); - mFragment = fragment; - mContext = mFragment.getActivity(); - mItemResource = itemResource; - mHistory = new ArrayList<>(Arrays.asList(history)); - Collections.reverse(mHistory); - mParticipants = participants; - mClickListener = clickListener; - mListener = - new ChatMessageListenerStub() { - @Override - public void onFileTransferProgressIndication( - ChatMessage message, Content content, int offset, int total) { - ChatMessageOldViewHolder holder = - (ChatMessageOldViewHolder) message.getUserData(); - if (holder == null) return; - - if (offset == total) { - holder.fileTransferProgressBar.setVisibility(View.GONE); - holder.fileTransferAction.setVisibility(View.GONE); - holder.fileTransferLayout.setVisibility(View.GONE); - - displayAttachedFile(message, holder); - } else { - holder.fileTransferProgressBar.setVisibility(View.VISIBLE); - holder.fileTransferProgressBar.setProgress(offset * 100 / total); - } - } - - @Override - public void onMsgStateChanged(ChatMessage message, ChatMessage.State state) { - if (state == ChatMessage.State.FileTransferDone) { - if (!message.isOutgoing()) { - message.setAppdata(message.getFileTransferFilepath()); - } - message.setFileTransferFilepath( - null); // Not needed anymore, will help differenciate between - // InProgress states for file transfer / message sending - } - for (int i = 0; i < mHistory.size(); i++) { - EventLog log = mHistory.get(i); - if (log.getType() == EventLog.Type.ConferenceChatMessage - && log.getChatMessage() == message) { - notifyItemChanged(i); - break; - } - } - } - }; - } - - @Override - public ChatMessageOldViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(mItemResource, parent, false); - ChatMessageOldViewHolder VH = new ChatMessageOldViewHolder(v, mClickListener); - - // Allows onLongClick ContextMenu on bubbles - mFragment.registerForContextMenu(v); - v.setTag(VH); - return VH; - } - - @Override - public void onBindViewHolder(@NonNull final ChatMessageOldViewHolder holder, int position) { - final EventLog event = mHistory.get(position); - holder.eventLayout.setVisibility(View.GONE); - holder.bubbleLayout.setVisibility(View.GONE); - holder.delete.setVisibility(isEditionEnabled() ? View.VISIBLE : View.GONE); - holder.messageText.setVisibility(View.GONE); - holder.messageImage.setVisibility(View.GONE); - holder.fileTransferLayout.setVisibility(View.GONE); - holder.fileTransferProgressBar.setProgress(0); - holder.fileTransferAction.setEnabled(true); - holder.fileName.setVisibility(View.GONE); - holder.openFileButton.setVisibility(View.GONE); - holder.messageStatus.setVisibility(View.INVISIBLE); - holder.messageSendingInProgress.setVisibility(View.GONE); - holder.imdmLayout.setVisibility(View.INVISIBLE); - - if (isEditionEnabled()) { - holder.delete.setOnCheckedChangeListener(null); - holder.delete.setChecked(isSelected(position)); - holder.delete.setTag(position); - } - - if (event.getType() == EventLog.Type.ConferenceChatMessage) { - holder.bubbleLayout.setVisibility(View.VISIBLE); - final ChatMessage message = event.getChatMessage(); - - if (position > 0 - && mContext.getResources() - .getBoolean(R.bool.lower_space_between_chat_bubbles_if_same_person)) { - EventLog previousEvent = (EventLog) getItem(position - 1); - if (previousEvent.getType() == EventLog.Type.ConferenceChatMessage) { - ChatMessage previousMessage = previousEvent.getChatMessage(); - if (previousMessage.getFromAddress().weakEqual(message.getFromAddress())) { - holder.separatorLayout.setVisibility(View.GONE); - } - } else { - // No separator if previous event is not a message - holder.separatorLayout.setVisibility(View.GONE); - } - } - - message.setUserData(holder); - message.addListener(mListener); - - RelativeLayout.LayoutParams layoutParams = - new RelativeLayout.LayoutParams( - RelativeLayout.LayoutParams.WRAP_CONTENT, - RelativeLayout.LayoutParams.WRAP_CONTENT); - - ChatMessage.State status = message.getState(); - Address remoteSender = message.getFromAddress(); - String displayName; - - LinphoneContact contact = null; - if (message.isOutgoing()) { - if (status == ChatMessage.State.InProgress) { - holder.messageSendingInProgress.setVisibility(View.VISIBLE); - } - - if (!message.isSecured() - && LinphoneManager.getLc().limeEnabled() == LimeState.Mandatory - && status != ChatMessage.State.InProgress) { - holder.messageStatus.setVisibility(View.VISIBLE); - holder.messageStatus.setImageResource(R.drawable.chat_unsecure); - } - - if (status == ChatMessage.State.DeliveredToUser) { - holder.imdmLayout.setVisibility(View.VISIBLE); - holder.imdmIcon.setImageResource(R.drawable.imdn_received); - holder.imdmLabel.setText(R.string.delivered); - holder.imdmLabel.setTextColor( - mContext.getResources().getColor(R.color.grey_color)); - } else if (status == ChatMessage.State.Displayed) { - holder.imdmLayout.setVisibility(View.VISIBLE); - holder.imdmIcon.setImageResource(R.drawable.imdn_read); - holder.imdmLabel.setText(R.string.displayed); - holder.imdmLabel.setTextColor( - mContext.getResources().getColor(R.color.imdn_read_color)); - } else if (status == ChatMessage.State.NotDelivered) { - holder.imdmLayout.setVisibility(View.VISIBLE); - holder.imdmIcon.setImageResource(R.drawable.imdn_error); - holder.imdmLabel.setText(R.string.error); - holder.imdmLabel.setTextColor( - mContext.getResources().getColor(R.color.red_color)); - } else if (status == ChatMessage.State.FileTransferError) { - holder.imdmLayout.setVisibility(View.VISIBLE); - holder.imdmIcon.setImageResource(R.drawable.imdn_error); - holder.imdmLabel.setText(R.string.file_transfer_error); - holder.imdmLabel.setTextColor( - mContext.getResources().getColor(R.color.red_color)); - } - - // layoutParams allow bubbles alignment during selection mode - if (isEditionEnabled()) { - layoutParams.addRule(RelativeLayout.LEFT_OF, holder.delete.getId()); - layoutParams.setMargins( - SIDE_MARGIN, - MARGIN_BETWEEN_MESSAGES / 2, - 0, - MARGIN_BETWEEN_MESSAGES / 2); - } else { - layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); - layoutParams.setMargins( - SIDE_MARGIN, - MARGIN_BETWEEN_MESSAGES / 2, - 0, - MARGIN_BETWEEN_MESSAGES / 2); - } - - holder.background.setBackgroundResource(R.drawable.resizable_chat_bubble_outgoing); - Compatibility.setTextAppearance(holder.contactName, mContext, R.style.font3); - Compatibility.setTextAppearance( - holder.fileTransferAction, mContext, R.style.font15); - holder.fileTransferAction.setBackgroundResource( - R.drawable.resizable_confirm_delete_button); - } else { - for (LinphoneContact c : mParticipants) { - if (c != null && c.hasAddress(remoteSender.asStringUriOnly())) { - contact = c; - break; - } - } - - if (isEditionEnabled()) { - layoutParams.addRule(RelativeLayout.LEFT_OF, holder.delete.getId()); - layoutParams.setMargins( - SIDE_MARGIN, - MARGIN_BETWEEN_MESSAGES / 2, - 0, - MARGIN_BETWEEN_MESSAGES / 2); - } else { - layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); - layoutParams.setMargins( - 0, - MARGIN_BETWEEN_MESSAGES / 2, - SIDE_MARGIN, - MARGIN_BETWEEN_MESSAGES / 2); - } - - holder.background.setBackgroundResource(R.drawable.resizable_chat_bubble_incoming); - Compatibility.setTextAppearance( - holder.contactName, mContext, R.style.contact_organization_font); - Compatibility.setTextAppearance( - holder.fileTransferAction, mContext, R.style.button_font); - holder.fileTransferAction.setBackgroundResource( - R.drawable.resizable_assistant_button); - } - - if (contact == null) { - contact = ContactsManager.getInstance().findContactFromAddress(remoteSender); - } - if (contact != null) { - if (contact.getFullName() != null) { - displayName = contact.getFullName(); - } else { - displayName = LinphoneUtils.getAddressDisplayName(remoteSender); - } - ContactAvatar.displayAvatar(contact, holder.avatarLayout); - } else { - displayName = LinphoneUtils.getAddressDisplayName(remoteSender); - ContactAvatar.displayAvatar(displayName, holder.avatarLayout); - } - holder.contactName.setText( - LinphoneUtils.timestampToHumanDate( - mContext, message.getTime(), R.string.messages_date_format) - + " - " - + displayName); - - if (message.hasTextContent()) { - String msg = message.getTextContent(); - Spanned text = LinphoneUtils.getTextWithHttpLinks(msg); - holder.messageText.setText(text); - holder.messageText.setMovementMethod(LinkMovementMethod.getInstance()); - holder.messageText.setVisibility(View.VISIBLE); - } - - String externalBodyUrl = message.getExternalBodyUrl(); - Content fileTransferContent = message.getFileTransferInformation(); - - boolean hasFile = message.getAppdata() != null; - boolean hasFileTransfer = externalBodyUrl != null; - for (Content c : message.getContents()) { - if (c.isFile()) { - hasFile = true; - } else if (c.isFileTransfer()) { - hasFileTransfer = true; - } - } - if (hasFile) { // Something to display - displayAttachedFile(message, holder); - } - - if (hasFileTransfer) { // Incoming file transfer not yet downloaded - holder.fileName.setVisibility(View.VISIBLE); - holder.fileName.setText(fileTransferContent.getName()); - - holder.fileTransferLayout.setVisibility(View.VISIBLE); - holder.fileTransferProgressBar.setVisibility(View.GONE); - if (message.isFileTransferInProgress()) { // Incoming file transfer in progress - holder.fileTransferAction.setVisibility(View.GONE); - } else { - holder.fileTransferAction.setText(mContext.getString(R.string.accept)); - holder.fileTransferAction.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mContext.getPackageManager() - .checkPermission( - Manifest.permission - .WRITE_EXTERNAL_STORAGE, - mContext.getPackageName()) - == PackageManager.PERMISSION_GRANTED) { - v.setEnabled(false); - String filename = - message.getFileTransferInformation().getName(); - File file = - new File( - FileUtils.getStorageDirectory(mContext), - filename); - int prefix = 1; - while (file.exists()) { - file = - new File( - FileUtils.getStorageDirectory(mContext), - prefix + "_" + filename); - Log.w( - "File with that name already exists, renamed to " - + prefix - + "_" - + filename); - prefix += 1; - } - message.setFileTransferFilepath(file.getPath()); - message.downloadFile(); - - } else { - Log.w( - "WRITE_EXTERNAL_STORAGE permission not granted, won't be able to store the downloaded file"); - LinphoneActivity.instance() - .checkAndRequestExternalStoragePermission(); - } - } - }); - } - } else if (message.isFileTransferInProgress()) { // Outgoing file transfer in progress - holder.messageSendingInProgress.setVisibility(View.GONE); - holder.fileTransferLayout.setVisibility(View.VISIBLE); - holder.fileTransferAction.setText(mContext.getString(R.string.cancel)); - holder.fileTransferAction.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - message.cancelFileTransfer(); - notifyItemChanged(holder.getAdapterPosition()); - } - }); - } - - holder.bubbleLayout.setLayoutParams(layoutParams); - } else { // Event is not chat message - holder.eventLayout.setVisibility(View.VISIBLE); - holder.eventMessage.setTextColor( - mContext.getResources().getColor(R.color.light_grey_color)); - holder.eventLayout.setBackgroundResource(R.drawable.event_decoration_gray); - holder.eventLayout.setBackgroundResource(R.drawable.event_decoration_gray); - - Address address = event.getParticipantAddress(); - if (address == null && event.getType() == EventLog.Type.ConferenceSecurityEvent) { - address = event.getSecurityEventFaultyDeviceAddress(); - } - String displayName = ""; - if (address != null) { - LinphoneContact contact = - ContactsManager.getInstance().findContactFromAddress(address); - if (contact != null) { - displayName = contact.getFullName(); - } else { - displayName = LinphoneUtils.getAddressDisplayName(address); - } - } - - switch (event.getType()) { - case ConferenceCreated: - holder.eventMessage.setText(mContext.getString(R.string.conference_created)); - break; - case ConferenceTerminated: - holder.eventMessage.setText(mContext.getString(R.string.conference_destroyed)); - break; - case ConferenceParticipantAdded: - holder.eventMessage.setText( - mContext.getString(R.string.participant_added) - .replace("%s", displayName)); - break; - case ConferenceParticipantRemoved: - holder.eventMessage.setText( - mContext.getString(R.string.participant_removed) - .replace("%s", displayName)); - break; - case ConferenceSubjectChanged: - holder.eventMessage.setText( - mContext.getString(R.string.subject_changed) - .replace("%s", event.getSubject())); - break; - case ConferenceParticipantSetAdmin: - holder.eventMessage.setText( - mContext.getString(R.string.admin_set).replace("%s", displayName)); - break; - case ConferenceParticipantUnsetAdmin: - holder.eventMessage.setText( - mContext.getString(R.string.admin_unset).replace("%s", displayName)); - break; - case ConferenceParticipantDeviceAdded: - holder.eventMessage.setText( - mContext.getString(R.string.device_added).replace("%s", displayName)); - break; - case ConferenceParticipantDeviceRemoved: - holder.eventMessage.setText( - mContext.getString(R.string.device_removed).replace("%s", displayName)); - break; - case ConferenceSecurityEvent: - holder.eventMessage.setTextColor( - mContext.getResources().getColor(R.color.red_color)); - holder.eventLayout.setBackgroundResource(R.drawable.event_decoration_red); - holder.eventLayout.setBackgroundResource(R.drawable.event_decoration_red); - - switch (event.getSecurityEventType()) { - case EncryptionIdentityKeyChanged: - holder.eventMessage.setText( - mContext.getString(R.string.lime_identity_key_changed) - .replace("%s", displayName)); - break; - case ManInTheMiddleDetected: - holder.eventMessage.setText( - mContext.getString(R.string.man_in_the_middle_detected) - .replace("%s", displayName)); - break; - case SecurityLevelDowngraded: - holder.eventMessage.setText( - mContext.getString(R.string.security_level_downgraded) - .replace("%s", displayName)); - break; - case ParticipantMaxDeviceCountExceeded: - holder.eventMessage.setText( - mContext.getString(R.string.participant_max_count_exceeded) - .replace("%s", displayName)); - break; - case None: - default: - break; - } - break; - case None: - default: - holder.eventMessage.setText( - mContext.getString(R.string.unexpected_event) - .replace("%s", displayName) - .replace("%i", String.valueOf(event.getType().toInt()))); - break; - } - } - } - - @Override - public int getItemCount() { - return mHistory.size(); - } - - public void addToHistory(EventLog log) { - mHistory.add(0, log); - notifyItemInserted(0); - } - - public void addAllToHistory(ArrayList logs) { - int currentSize = mHistory.size() - 1; - Collections.reverse(logs); - mHistory.addAll(logs); - notifyItemRangeInserted(currentSize + 1, logs.size()); - } - - public void setContacts(ArrayList participants) { - mParticipants = participants; - } - - public void refresh(EventLog[] history) { - mHistory = new ArrayList<>(Arrays.asList(history)); - Collections.reverse(mHistory); - notifyDataSetChanged(); - } - - public void clear() { - for (EventLog event : mHistory) { - if (event.getType() == EventLog.Type.ConferenceChatMessage) { - ChatMessage message = event.getChatMessage(); - message.removeListener(mListener); - } - } - mHistory.clear(); - } - - public Object getItem(int i) { - return mHistory.get(i); - } - - public void removeItem(int i) { - mHistory.remove(i); - notifyItemRemoved(i); - } - - private void loadBitmap(String path, ImageView imageView) { - if (cancelPotentialWork(path, imageView)) { - mDefaultBitmap = - BitmapFactory.decodeResource(mContext.getResources(), R.drawable.chat_file); - BitmapWorkerTask task = new BitmapWorkerTask(mContext, imageView, mDefaultBitmap); - final AsyncBitmap asyncBitmap = - new AsyncBitmap(mContext.getResources(), mDefaultBitmap, task); - imageView.setImageDrawable(asyncBitmap); - task.execute(path); - } - } - - private void openFile(String path) { - Intent intent = new Intent(Intent.ACTION_VIEW); - File file; - Uri contentUri; - if (path.startsWith("file://")) { - path = path.substring("file://".length()); - file = new File(path); - contentUri = - FileProvider.getUriForFile( - mContext, - mContext.getResources().getString(R.string.file_provider), - file); - } else if (path.startsWith("content://")) { - contentUri = Uri.parse(path); - } else { - file = new File(path); - try { - contentUri = - FileProvider.getUriForFile( - mContext, - mContext.getResources().getString(R.string.file_provider), - file); - } catch (Exception e) { - contentUri = Uri.parse(path); - } - } - String type = null; - String extension = MimeTypeMap.getFileExtensionFromUrl(contentUri.toString()); - if (extension != null) { - type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - } - if (type != null) { - intent.setDataAndType(contentUri, type); - } else { - intent.setDataAndType(contentUri, "*/*"); - } - intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION); - mContext.startActivity(intent); - } - - private void displayAttachedFile(ChatMessage message, ChatMessageOldViewHolder holder) { - holder.fileName.setVisibility(View.VISIBLE); - - String appData = message.getAppdata(); - if (appData == null) { - for (Content c : message.getContents()) { - if (c.isFile()) { - appData = c.getFilePath(); - } - } - } - - if (appData != null) { - FileUtils.scanFile(message); - holder.fileName.setText(FileUtils.getNameFromFilePath(appData)); - if (FileUtils.isExtensionImage(appData)) { - holder.messageImage.setVisibility(View.VISIBLE); - loadBitmap(appData, holder.messageImage); - holder.messageImage.setTag(appData); - } else { - holder.openFileButton.setVisibility(View.VISIBLE); - holder.openFileButton.setTag(appData); - holder.openFileButton.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - openFile((String) v.getTag()); - } - }); - } - } - } - - private boolean cancelPotentialWork(String path, ImageView imageView) { - final BitmapWorkerTask bitmapWorkerTask = BitmapWorkerTask.getBitmapWorkerTask(imageView); - - if (bitmapWorkerTask != null) { - final String bitmapData = bitmapWorkerTask.path; - // If bitmapData is not yet set or it differs from the new data - if (bitmapData == null || !bitmapData.equals(path)) { - // Cancel previous task - bitmapWorkerTask.cancel(true); - } else { - // The same work is already in progress - return false; - } - } - // No task associated with the ImageView, or an existing task was cancelled - return true; - } -} diff --git a/app/src/main/java/org/linphone/chat/ChatRoomCreationFragment.java b/app/src/main/java/org/linphone/chat/ChatRoomCreationFragment.java index 1f75c9927..28d8f0087 100644 --- a/app/src/main/java/org/linphone/chat/ChatRoomCreationFragment.java +++ b/app/src/main/java/org/linphone/chat/ChatRoomCreationFragment.java @@ -1,6 +1,8 @@ +package org.linphone.chat; + /* ChatRoomCreationFragment.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.linphone.chat; - import static android.content.Context.INPUT_METHOD_SERVICE; import android.app.Fragment; @@ -41,7 +41,6 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.contacts.ContactAddress; @@ -56,11 +55,11 @@ import org.linphone.core.ChatRoomBackend; import org.linphone.core.ChatRoomListenerStub; import org.linphone.core.ChatRoomParams; import org.linphone.core.Core; +import org.linphone.core.Factory; import org.linphone.core.FriendCapability; import org.linphone.core.ProxyConfig; import org.linphone.core.SearchResult; import org.linphone.core.tools.Log; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.settings.LinphonePreferences; import org.linphone.views.ContactSelectView; @@ -71,19 +70,19 @@ public class ChatRoomCreationFragment extends Fragment private RecyclerView mContactsList; private LinearLayout mContactsSelectedLayout; private HorizontalScrollView mContactsSelectLayout; - private ImageView mAllContactsButton, mLinphoneContactsButton, mBackButton, mNextButton; + private ImageView mAllContactsButton; + private ImageView mLinphoneContactsButton; + private ImageView mNextButton; private boolean mOnlyDisplayLinphoneContacts; private View mAllContactsSelected, mLinphoneContactsSelected; private RelativeLayout mSearchLayout, mWaitLayout, mLinphoneContactsToggle, mAllContactsToggle; private SearchView mSearchField; - private ProgressBar mContactsFetchInProgress; private SearchContactsAdapter mSearchAdapter; private String mChatRoomSubject, mChatRoomAddress; private ChatRoom mChatRoom; private ChatRoomListenerStub mChatRoomCreationListener; - private Bundle mShareInfos; - private ImageView mSecurityToggleOff, mSecurityToggleOn; private Switch mSecurityToggle; + private ArrayList mParticipants; private boolean mCreateGroupChatRoom; private boolean mChatRoomEncrypted; @@ -92,22 +91,22 @@ public class ChatRoomCreationFragment extends Fragment LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreate(savedInstanceState); View view = inflater.inflate(R.layout.chat_create, container, false); + setRetainInstance(true); - ArrayList selectedContacts = new ArrayList<>(); + mParticipants = new ArrayList<>(); mChatRoomSubject = null; mChatRoomAddress = null; mCreateGroupChatRoom = false; if (getArguments() != null) { - if (getArguments().getSerializable("selectedContacts") != null) { - selectedContacts = - (ArrayList) - getArguments().getSerializable("selectedContacts"); + if (getArguments().getSerializable("Participants") != null) { + mParticipants = + (ArrayList) getArguments().getSerializable("Participants"); } - mChatRoomSubject = getArguments().getString("subject"); - mChatRoomAddress = getArguments().getString("groupChatRoomAddress"); - mCreateGroupChatRoom = getArguments().getBoolean("createGroupChatRoom", false); - mChatRoomEncrypted = getArguments().getBoolean("encrypted", false); + mChatRoomSubject = getArguments().getString("Subject"); + mChatRoomAddress = getArguments().getString("RemoteSipUri"); + mCreateGroupChatRoom = getArguments().getBoolean("IsGroupChatRoom", false); + mChatRoomEncrypted = getArguments().getBoolean("Encrypted", false); } mWaitLayout = view.findViewById(R.id.waitScreen); @@ -126,16 +125,44 @@ public class ChatRoomCreationFragment extends Fragment mAllContactsSelected = view.findViewById(R.id.all_contacts_select); mLinphoneContactsSelected = view.findViewById(R.id.linphone_contacts_select); - mBackButton = view.findViewById(R.id.back); - mBackButton.setOnClickListener(this); + ImageView backButton = view.findViewById(R.id.back); + backButton.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + ((ChatActivity) getActivity()).goBack(); + } + }); mNextButton = view.findViewById(R.id.next); - mNextButton.setOnClickListener(this); + mNextButton.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mChatRoomAddress == null && mChatRoomSubject == null) { + mContactsSelectedLayout.removeAllViews(); + } else { + // Pop the back stack twice so we don't have in stack Group -> Creation + // -> Group + getFragmentManager().popBackStack(); + getFragmentManager().popBackStack(); + } + ((ChatActivity) getActivity()) + .showChatRoomGroupInfo( + mChatRoomAddress == null + ? null + : Factory.instance() + .createAddress(mChatRoomAddress), + mSearchAdapter.getContactsSelectedList(), + mChatRoomSubject, + mSecurityToggle.isChecked()); + } + }); mNextButton.setEnabled(false); mSearchLayout = view.findViewById(R.id.layoutSearchField); - mContactsFetchInProgress = view.findViewById(R.id.contactsFetchInProgress); - mContactsFetchInProgress.setVisibility(View.GONE); + ProgressBar contactsFetchInProgress = view.findViewById(R.id.contactsFetchInProgress); + contactsFetchInProgress.setVisibility(View.GONE); mSearchAdapter = new SearchContactsAdapter(this, !mCreateGroupChatRoom, mChatRoomEncrypted); @@ -165,16 +192,16 @@ public class ChatRoomCreationFragment extends Fragment setSecurityEnabled(isChecked); } }); - mSecurityToggleOn = view.findViewById(R.id.security_toogle_on); - mSecurityToggleOff = view.findViewById(R.id.security_toogle_off); - mSecurityToggleOn.setOnClickListener( + ImageView securityToggleOn = view.findViewById(R.id.security_toogle_on); + ImageView securityToggleOff = view.findViewById(R.id.security_toogle_off); + securityToggleOn.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { setSecurityEnabled(true); } }); - mSecurityToggleOff.setOnClickListener( + securityToggleOff.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { @@ -184,12 +211,12 @@ public class ChatRoomCreationFragment extends Fragment mSecurityToggle.setChecked(mChatRoomEncrypted); mSearchAdapter.setSecurityEnabled(mChatRoomEncrypted); - ProxyConfig lpc = LinphoneManager.getLc().getDefaultProxyConfig(); + ProxyConfig lpc = LinphoneManager.getCore().getDefaultProxyConfig(); if ((mChatRoomSubject != null && mChatRoomAddress != null) || (lpc == null || lpc.getConferenceFactoryUri() == null)) { mSecurityToggle.setVisibility(View.GONE); - mSecurityToggleOn.setVisibility(View.GONE); - mSecurityToggleOff.setVisibility(View.GONE); + securityToggleOn.setVisibility(View.GONE); + securityToggleOff.setVisibility(View.GONE); } LinearLayoutManager layoutManager = @@ -209,32 +236,22 @@ public class ChatRoomCreationFragment extends Fragment mContactsList.setLayoutManager(layoutManager); - if (savedInstanceState != null - && savedInstanceState.getStringArrayList("selectedContacts") != null) { - mContactsSelectedLayout.removeAllViews(); - // We need to get all contacts not only sip - selectedContacts = - (ArrayList) - savedInstanceState.getSerializable("selectedContacts"); - } - - if (selectedContacts.size() != 0) { - mSearchAdapter.setContactsSelectedList(selectedContacts); - updateList(); - updateListSelected(); - } - mOnlyDisplayLinphoneContacts = ContactsManager.getInstance().isLinphoneContactsPrefered() || getResources().getBoolean(R.bool.hide_non_linphone_contacts); + if (savedInstanceState != null) { + if (mParticipants.isEmpty() + && savedInstanceState.getStringArrayList("Participants") != null) { + mContactsSelectedLayout.removeAllViews(); + // We need to get all contacts not only sip + mParticipants = + (ArrayList) + savedInstanceState.getSerializable("Participants"); + } mOnlyDisplayLinphoneContacts = savedInstanceState.getBoolean("onlySipContact", mOnlyDisplayLinphoneContacts); } - mSearchAdapter.setOnlySipContact(mOnlyDisplayLinphoneContacts); - updateList(); - - displayChatCreation(); mChatRoomCreationListener = new ChatRoomListenerStub() { @@ -242,14 +259,15 @@ public class ChatRoomCreationFragment extends Fragment public void onStateChanged(ChatRoom cr, ChatRoom.State newState) { if (newState == ChatRoom.State.Created) { mWaitLayout.setVisibility(View.GONE); - LinphoneActivity.instance() - .goToChat( - cr.getLocalAddress().asStringUriOnly(), - cr.getPeerAddress().asStringUriOnly(), - mShareInfos); + // Pop back stack so back button takes to the chat rooms list + getFragmentManager().popBackStack(); + ((ChatActivity) getActivity()) + .showChatRoom( + mChatRoom.getLocalAddress(), + mChatRoom.getPeerAddress()); } else if (newState == ChatRoom.State.CreationFailed) { mWaitLayout.setVisibility(View.GONE); - LinphoneActivity.instance().displayChatRoomError(); + ((ChatActivity) getActivity()).displayChatRoomError(); Log.e( "[Chat Room Creation] Group chat room for address " + cr.getPeerAddress() @@ -258,34 +276,15 @@ public class ChatRoomCreationFragment extends Fragment } }; - if (getArguments() != null) { - String fileSharedUri = getArguments().getString("fileSharedUri"); - String messageDraft = getArguments().getString("messageDraft"); - - if (fileSharedUri != null || messageDraft != null) { - Log.i("[ChatRoomCreation] Forwarding arguments to new chat room"); - mShareInfos = new Bundle(); - } - - if (fileSharedUri != null) { - LinphoneActivity.instance().checkAndRequestPermissionsToSendImage(); - mShareInfos.putString("fileSharedUri", fileSharedUri); - } - - if (messageDraft != null) mShareInfos.putString("messageDraft", messageDraft); - } - return view; } @Override public void onResume() { - ContactsManager.getInstance().addContactsListener(this); super.onResume(); + ContactsManager.getInstance().addContactsListener(this); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.CREATE_CHAT); - } + updateLayout(); InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE); @@ -304,6 +303,191 @@ public class ChatRoomCreationFragment extends Fragment super.onPause(); } + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (mSearchAdapter.getContactsSelectedList().size() > 0) { + outState.putSerializable("Participants", mSearchAdapter.getContactsSelectedList()); + } + outState.putBoolean("onlySipContact", mOnlyDisplayLinphoneContacts); + } + + @Override + public void onClick(View view) { + int id = view.getId(); + if (id == R.id.all_contacts) { + mOnlyDisplayLinphoneContacts = false; + mSearchAdapter.setOnlySipContact(false); + mAllContactsSelected.setVisibility(View.VISIBLE); + mAllContactsButton.setEnabled(false); + mLinphoneContactsButton.setEnabled(true); + mLinphoneContactsSelected.setVisibility(View.INVISIBLE); + updateList(); + resetAndResearch(); + } else if (id == R.id.linphone_contacts) { + mSearchAdapter.setOnlySipContact(true); + mLinphoneContactsSelected.setVisibility(View.VISIBLE); + mLinphoneContactsButton.setEnabled(false); + mOnlyDisplayLinphoneContacts = true; + mAllContactsButton.setEnabled(true); + mAllContactsSelected.setVisibility(View.INVISIBLE); + updateList(); + resetAndResearch(); + } else if (id == R.id.contactChatDelete) { + ContactAddress ca = (ContactAddress) view.getTag(); + addOrRemoveContactFromSelection(ca); + } + } + + @Override + public void onItemClicked(int position) { + SearchResult searchResult = mSearchAdapter.getContacts().get(position); + Core core = LinphoneManager.getCore(); + ProxyConfig lpc = core.getDefaultProxyConfig(); + boolean createEncryptedChatRoom = mSecurityToggle.isChecked(); + + if (createEncryptedChatRoom && !searchResult.hasCapability(FriendCapability.LimeX3Dh)) { + Log.w( + "[Chat Room Creation] Contact " + + searchResult.getFriend() + + " doesn't have LIME X3DH capability !"); + return; + } else if (mCreateGroupChatRoom + && !searchResult.hasCapability(FriendCapability.GroupChat)) { + Log.w( + "[Chat Room Creation] Contact " + + searchResult.getFriend() + + " doesn't have group chat capability !"); + return; + } + + if (lpc == null || lpc.getConferenceFactoryUri() == null || !mCreateGroupChatRoom) { + Address address = searchResult.getAddress(); + if (address == null) { + Log.w( + "[Chat Room Creation] Using search result without an address, trying with phone number..."); + address = core.interpretUrl(searchResult.getPhoneNumber()); + } + if (address == null) { + Log.e("[Chat Room Creation] Can't create a chat room without a valid address !"); + return; + } + if (lpc != null && lpc.getIdentityAddress().weakEqual(address)) { + Log.e("[Chat Room Creation] Can't create a 1-to-1 chat room with myself !"); + return; + } + + if (createEncryptedChatRoom && lpc != null && lpc.getConferenceFactoryUri() != null) { + mChatRoom = core.findOneToOneChatRoom(lpc.getIdentityAddress(), address, true); + if (mChatRoom != null) { + ((ChatActivity) getActivity()) + .showChatRoom(mChatRoom.getLocalAddress(), mChatRoom.getPeerAddress()); + } else { + ChatRoomParams params = core.createDefaultChatRoomParams(); + // This will set the backend to FlexisipChat automatically + params.enableEncryption(true); + params.enableGroup(false); + + Address[] participants = new Address[1]; + participants[0] = address; + + mChatRoom = + core.createChatRoom( + params, + getString(R.string.dummy_group_chat_subject), + participants); + if (mChatRoom != null) { + mChatRoom.addListener(mChatRoomCreationListener); + } else { + Log.w("[Chat Room Creation Fragment] createChatRoom returned null..."); + mWaitLayout.setVisibility(View.GONE); + } + } + } else { + if (lpc != null + && lpc.getConferenceFactoryUri() != null + && !LinphonePreferences.instance().useBasicChatRoomFor1To1()) { + mChatRoom = core.findOneToOneChatRoom(lpc.getIdentityAddress(), address, false); + if (mChatRoom == null) { + mWaitLayout.setVisibility(View.VISIBLE); + + ChatRoomParams params = core.createDefaultChatRoomParams(); + params.enableEncryption(false); + params.enableGroup(false); + // We don't want a basic chat room + params.setBackend(ChatRoomBackend.FlexisipChat); + + Address[] participants = new Address[1]; + participants[0] = address; + + mChatRoom = + core.createChatRoom( + params, + getString(R.string.dummy_group_chat_subject), + participants); + if (mChatRoom != null) { + mChatRoom.addListener(mChatRoomCreationListener); + } else { + Log.w("[Chat Room Creation Fragment] createChatRoom returned null..."); + mWaitLayout.setVisibility(View.GONE); + } + } else { + // Pop back stack so back button takes to the chat rooms list + getFragmentManager().popBackStack(); + ((ChatActivity) getActivity()) + .showChatRoom( + mChatRoom.getLocalAddress(), mChatRoom.getPeerAddress()); + } + } else { + ChatRoom chatRoom = core.getChatRoom(address); + if (chatRoom != null) { + // Pop back stack so back button takes to the chat rooms list + getFragmentManager().popBackStack(); + ((ChatActivity) getActivity()) + .showChatRoom( + chatRoom.getLocalAddress(), chatRoom.getPeerAddress()); + } + } + } + } else { + LinphoneContact c = + searchResult.getFriend() != null + ? (LinphoneContact) searchResult.getFriend().getUserData() + : null; + if (c == null) { + c = ContactsManager.getInstance().findContactFromAddress(searchResult.getAddress()); + if (c == null) { + c = + ContactsManager.getInstance() + .findContactFromPhoneNumber(searchResult.getPhoneNumber()); + } + } + addOrRemoveContactFromSelection( + new ContactAddress( + c, + searchResult.getAddress().asStringUriOnly(), + searchResult.getPhoneNumber())); + } + } + + @Override + public void onContactsUpdated() { + updateList(); + } + + private void updateLayout() { + if (mParticipants.size() != 0) { + mSearchAdapter.setContactsSelectedList(mParticipants); + updateList(); + updateListSelected(); + } + + mSearchAdapter.setOnlySipContact(mOnlyDisplayLinphoneContacts); + updateList(); + + displayChatCreation(); + } + private void setSecurityEnabled(boolean enabled) { mChatRoomEncrypted = enabled; mSecurityToggle.setChecked(mChatRoomEncrypted); @@ -409,8 +593,7 @@ public class ChatRoomCreationFragment extends Fragment private void addSelectedContactAddress(ContactAddress ca) { View viewContact = - LayoutInflater.from(LinphoneActivity.instance()) - .inflate(R.layout.contact_selected, null); + LayoutInflater.from(getActivity()).inflate(R.layout.contact_selected, null); if (ca.getContact() != null) { String name = (ca.getContact().getFullName() != null @@ -436,7 +619,7 @@ public class ChatRoomCreationFragment extends Fragment private void updateContactsClick(ContactAddress ca) { boolean isSelected = mSearchAdapter.toggleContactSelection(ca); if (isSelected) { - ContactSelectView csv = new ContactSelectView(LinphoneActivity.instance()); + ContactSelectView csv = new ContactSelectView(getActivity()); csv.setListener(this); csv.setContactName(ca); addSelectedContactAddress(ca); @@ -455,208 +638,4 @@ public class ChatRoomCreationFragment extends Fragment mSearchAdapter.notifyDataSetChanged(); updateListSelected(); } - - @Override - public void onSaveInstanceState(Bundle outState) { - if (mSearchAdapter.getContactsSelectedList().size() > 0) { - outState.putSerializable("selectedContacts", mSearchAdapter.getContactsSelectedList()); - } - outState.putBoolean("onlySipContact", mOnlyDisplayLinphoneContacts); - super.onSaveInstanceState(outState); - } - - @Override - public void onClick(View view) { - int id = view.getId(); - if (id == R.id.all_contacts) { - mOnlyDisplayLinphoneContacts = false; - mSearchAdapter.setOnlySipContact(mOnlyDisplayLinphoneContacts); - mAllContactsSelected.setVisibility(View.VISIBLE); - mAllContactsButton.setEnabled(false); - mLinphoneContactsButton.setEnabled(true); - mLinphoneContactsSelected.setVisibility(View.INVISIBLE); - updateList(); - resetAndResearch(); - } else if (id == R.id.linphone_contacts) { - mSearchAdapter.setOnlySipContact(true); - mLinphoneContactsSelected.setVisibility(View.VISIBLE); - mLinphoneContactsButton.setEnabled(false); - mOnlyDisplayLinphoneContacts = true; - mAllContactsButton.setEnabled(mOnlyDisplayLinphoneContacts); - mAllContactsSelected.setVisibility(View.INVISIBLE); - updateList(); - resetAndResearch(); - } else if (id == R.id.back) { - if (LinphoneActivity.instance().isTablet()) { - LinphoneActivity.instance().goToChatList(); - } else { - mContactsSelectedLayout.removeAllViews(); - LinphoneActivity.instance().popBackStack(); - } - } else if (id == R.id.next) { - if (mChatRoomAddress == null && mChatRoomSubject == null) { - mContactsSelectedLayout.removeAllViews(); - LinphoneActivity.instance() - .goToChatGroupInfos( - null, - mSearchAdapter.getContactsSelectedList(), - null, - true, - false, - mShareInfos, - mSecurityToggle.isChecked()); - } else { - LinphoneActivity.instance() - .goToChatGroupInfos( - mChatRoomAddress, - mSearchAdapter.getContactsSelectedList(), - mChatRoomSubject, - true, - true, - mShareInfos, - mSecurityToggle.isChecked()); - } - } else if (id == R.id.contactChatDelete) { - ContactAddress ca = (ContactAddress) view.getTag(); - addOrRemoveContactFromSelection(ca); - } - } - - @Override - public void onItemClicked(int position) { - SearchResult searchResult = mSearchAdapter.getContacts().get(position); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - ProxyConfig lpc = lc.getDefaultProxyConfig(); - boolean createEncryptedChatRoom = mSecurityToggle.isChecked(); - - if (createEncryptedChatRoom && !searchResult.hasCapability(FriendCapability.LimeX3Dh)) { - Log.w( - "[Chat Room Creation] Contact " - + searchResult.getFriend() - + " doesn't have LIME X3DH capability !"); - return; - } else if (mCreateGroupChatRoom - && !searchResult.hasCapability(FriendCapability.GroupChat)) { - Log.w( - "[Chat Room Creation] Contact " - + searchResult.getFriend() - + " doesn't have group chat capability !"); - return; - } - - if (lpc == null || lpc.getConferenceFactoryUri() == null || !mCreateGroupChatRoom) { - Address address = searchResult.getAddress(); - if (address == null) { - Log.w( - "[Chat Room Creation] Using search result without an address, trying with phone number..."); - address = lc.interpretUrl(searchResult.getPhoneNumber()); - } - if (address == null) { - Log.e("[Chat Room Creation] Can't create a chat room without a valid address !"); - return; - } - if (lpc != null && lpc.getIdentityAddress().weakEqual(address)) { - Log.e("[Chat Room Creation] Can't create a 1-to-1 chat room with myself !"); - return; - } - - if (createEncryptedChatRoom && lpc != null && lpc.getConferenceFactoryUri() != null) { - mChatRoom = lc.findOneToOneChatRoom(lpc.getIdentityAddress(), address, true); - if (mChatRoom != null) { - LinphoneActivity.instance() - .goToChat( - mChatRoom.getLocalAddress().asStringUriOnly(), - mChatRoom.getPeerAddress().asStringUriOnly(), - mShareInfos); - } else { - ChatRoomParams params = lc.createDefaultChatRoomParams(); - // This will set the backend to FlexisipChat automatically - params.enableEncryption(true); - params.enableGroup(false); - - Address participants[] = new Address[1]; - participants[0] = address; - - mChatRoom = - lc.createChatRoom( - params, - getString(R.string.dummy_group_chat_subject), - participants); - if (mChatRoom != null) { - mChatRoom.addListener(mChatRoomCreationListener); - } else { - Log.w("[Chat Room Creation Fragment] createChatRoom returned null..."); - mWaitLayout.setVisibility(View.GONE); - } - } - } else { - if (lpc != null - && lpc.getConferenceFactoryUri() != null - && !LinphonePreferences.instance().useBasicChatRoomFor1To1()) { - mChatRoom = lc.findOneToOneChatRoom(lpc.getIdentityAddress(), address, false); - if (mChatRoom == null) { - mWaitLayout.setVisibility(View.VISIBLE); - - ChatRoomParams params = lc.createDefaultChatRoomParams(); - params.enableEncryption(false); - params.enableGroup(false); - // We don't want a basic chat room - params.setBackend(ChatRoomBackend.FlexisipChat); - - Address participants[] = new Address[1]; - participants[0] = address; - - mChatRoom = - lc.createChatRoom( - params, - getString(R.string.dummy_group_chat_subject), - participants); - if (mChatRoom != null) { - mChatRoom.addListener(mChatRoomCreationListener); - } else { - Log.w("[Chat Room Creation Fragment] createChatRoom returned null..."); - mWaitLayout.setVisibility(View.GONE); - } - } else { - LinphoneActivity.instance() - .goToChat( - mChatRoom.getLocalAddress().asStringUriOnly(), - mChatRoom.getPeerAddress().asStringUriOnly(), - mShareInfos); - } - } else { - ChatRoom chatRoom = lc.getChatRoom(address); - LinphoneActivity.instance() - .goToChat( - chatRoom.getLocalAddress().asStringUriOnly(), - chatRoom.getPeerAddress().asStringUriOnly(), - mShareInfos); - } - } - } else { - LinphoneContact c = - searchResult.getFriend() != null - ? (LinphoneContact) searchResult.getFriend().getUserData() - : null; - if (c == null) { - c = ContactsManager.getInstance().findContactFromAddress(searchResult.getAddress()); - if (c == null) { - c = - ContactsManager.getInstance() - .findContactFromPhoneNumber(searchResult.getPhoneNumber()); - } - } - addOrRemoveContactFromSelection( - new ContactAddress( - c, - searchResult.getAddress().asStringUriOnly(), - searchResult.getPhoneNumber(), - searchResult.getFriend() != null)); - } - } - - @Override - public void onContactsUpdated() { - updateList(); - } } diff --git a/app/src/main/java/org/linphone/chat/ChatRoomViewHolder.java b/app/src/main/java/org/linphone/chat/ChatRoomViewHolder.java index 3c3df2f2e..f0f1801fe 100644 --- a/app/src/main/java/org/linphone/chat/ChatRoomViewHolder.java +++ b/app/src/main/java/org/linphone/chat/ChatRoomViewHolder.java @@ -1,6 +1,8 @@ +package org.linphone.chat; + /* ChatRoomViewHolder.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.linphone.chat; - import android.content.Context; import android.view.View; import android.widget.CheckBox; @@ -39,12 +39,12 @@ import org.linphone.views.ContactAvatar; public class ChatRoomViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { - public final TextView lastMessageView; - public final TextView date; - public final TextView displayName; + private final TextView lastMessageView; + private final TextView date; + private final TextView displayName; public final TextView unreadMessages; public final CheckBox delete; - public final RelativeLayout avatarLayout; + private final RelativeLayout avatarLayout; private final Context mContext; private final ClickListener mListener; @@ -77,7 +77,7 @@ public class ChatRoomViewHolder extends RecyclerView.ViewHolder messageContent.insert(0, c.getStringBuffer() + " "); } } - lastMessageView.setText(getSender(room) + messageContent); + lastMessageView.setText(getSender(lastMessage) + messageContent); date.setText( LinphoneUtils.timestampToHumanDate( mContext, @@ -106,23 +106,21 @@ public class ChatRoomViewHolder extends RecyclerView.ViewHolder return false; } - public String getSender(ChatRoom mRoom) { - if (mRoom.getLastMessageInHistory() != null) { + private String getSender(ChatMessage lastMessage) { + if (lastMessage != null) { LinphoneContact contact = ContactsManager.getInstance() - .findContactFromAddress( - mRoom.getLastMessageInHistory().getFromAddress()); + .findContactFromAddress(lastMessage.getFromAddress()); if (contact != null) { return (contact.getFullName() + mContext.getString(R.string.separator)); } - return (LinphoneUtils.getAddressDisplayName( - mRoom.getLastMessageInHistory().getFromAddress()) + return (LinphoneUtils.getAddressDisplayName(lastMessage.getFromAddress()) + mContext.getString(R.string.separator)); } return null; } - public String getContact(ChatRoom mRoom) { + private String getContact(ChatRoom mRoom) { Address contactAddress = mRoom.getPeerAddress(); if (mRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt()) && mRoom.getParticipants().length > 0) { @@ -140,7 +138,7 @@ public class ChatRoomViewHolder extends RecyclerView.ViewHolder return mRoom.getSubject(); } - public void getAvatar(ChatRoom mRoom) { + private void getAvatar(ChatRoom mRoom) { if (mRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { LinphoneContact contact = null; if (mRoom.hasCapability(ChatRoomCapabilities.Basic.toInt())) { diff --git a/app/src/main/java/org/linphone/chat/ChatRoomsAdapter.java b/app/src/main/java/org/linphone/chat/ChatRoomsAdapter.java index ed54cbfcc..c4b318ed5 100644 --- a/app/src/main/java/org/linphone/chat/ChatRoomsAdapter.java +++ b/app/src/main/java/org/linphone/chat/ChatRoomsAdapter.java @@ -1,6 +1,8 @@ +package org.linphone.chat; + /* ChatRoomsAdapter.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.linphone.chat; - import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -68,11 +68,12 @@ public class ChatRoomsAdapter extends SelectableAdapter { ? View.INVISIBLE : (room.getUnreadMessagesCount() > 0 ? View.VISIBLE : View.INVISIBLE)); holder.delete.setChecked(isSelected(position)); + room.setUserData(holder); holder.bindChatRoom(room); } public void refresh() { - ChatRoom[] rooms = LinphoneManager.getLc().getChatRooms(); + ChatRoom[] rooms = LinphoneManager.getCore().getChatRooms(); if (mContext.getResources().getBoolean(R.bool.hide_empty_one_to_one_chat_rooms)) { mRooms = LinphoneUtils.removeEmptyOneToOneChatRooms(rooms); } else { @@ -95,7 +96,7 @@ public class ChatRoomsAdapter extends SelectableAdapter { public void clear() { mRooms.clear(); - notifyDataSetChanged(); + // Do not notify data set changed, we don't want the list to empty when fragment is paused } /** Adapter's methods */ diff --git a/app/src/main/java/org/linphone/chat/ChatRoomsFragment.java b/app/src/main/java/org/linphone/chat/ChatRoomsFragment.java index d339ff346..3ffc8b7f4 100644 --- a/app/src/main/java/org/linphone/chat/ChatRoomsFragment.java +++ b/app/src/main/java/org/linphone/chat/ChatRoomsFragment.java @@ -1,6 +1,8 @@ +package org.linphone.chat; + /* ChatRoomsFragment.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -17,12 +19,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.linphone.chat; - -import static org.linphone.fragments.FragmentsAvailable.CHAT_LIST; - import android.app.Fragment; -import android.content.Context; +import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -30,16 +28,14 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; -import android.widget.Toast; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import java.io.File; import java.util.Arrays; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; +import org.linphone.call.CallActivity; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.ContactsUpdatedListener; import org.linphone.core.ChatMessage; @@ -47,10 +43,7 @@ import org.linphone.core.ChatRoom; import org.linphone.core.ChatRoomListenerStub; import org.linphone.core.Core; import org.linphone.core.CoreListenerStub; -import org.linphone.core.EventLog; import org.linphone.core.ProxyConfig; -import org.linphone.core.tools.Log; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.utils.LinphoneUtils; import org.linphone.utils.SelectableHelper; @@ -60,14 +53,13 @@ public class ChatRoomsFragment extends Fragment SelectableHelper.DeleteListener { private RecyclerView mChatRoomsList; - private ImageView mNewDiscussionButton, mNewGroupDiscussionButton, mBackToCallButton; + private ImageView mNewGroupDiscussionButton; + private ImageView mBackToCallButton; private ChatRoomsAdapter mChatRoomsAdapter; private CoreListenerStub mListener; private RelativeLayout mWaitLayout; private int mChatRoomDeletionPendingCount; private ChatRoomListenerStub mChatRoomListener; - private Context mContext; - private List mRooms; private SelectableHelper mSelectionHelper; private TextView mNoChatHistory; @@ -76,18 +68,18 @@ public class ChatRoomsFragment extends Fragment final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mContext = getActivity().getApplicationContext(); View view = inflater.inflate(R.layout.chatlist, container, false); mChatRoomsList = view.findViewById(R.id.chatList); mWaitLayout = view.findViewById(R.id.waitScreen); - mNewDiscussionButton = view.findViewById(R.id.new_discussion); + ImageView newDiscussionButton = view.findViewById(R.id.new_discussion); mNewGroupDiscussionButton = view.findViewById(R.id.new_group_discussion); mBackToCallButton = view.findViewById(R.id.back_in_call); mNoChatHistory = view.findViewById(R.id.noChatHistory); - ChatRoom[] rooms = LinphoneManager.getLc().getChatRooms(); - if (mContext.getResources().getBoolean(R.bool.hide_empty_one_to_one_chat_rooms)) { + ChatRoom[] rooms = LinphoneManager.getCore().getChatRooms(); + List mRooms; + if (getResources().getBoolean(R.bool.hide_empty_one_to_one_chat_rooms)) { mRooms = LinphoneUtils.removeEmptyOneToOneChatRooms(rooms); } else { mRooms = Arrays.asList(rooms); @@ -96,19 +88,18 @@ public class ChatRoomsFragment extends Fragment mSelectionHelper = new SelectableHelper(view, this); mChatRoomsAdapter = new ChatRoomsAdapter( - mContext, R.layout.chatlist_cell, mRooms, this, mSelectionHelper); + getActivity(), R.layout.chatlist_cell, mRooms, this, mSelectionHelper); mChatRoomsList.setAdapter(mChatRoomsAdapter); mSelectionHelper.setAdapter(mChatRoomsAdapter); mSelectionHelper.setDialogMessage(R.string.chat_room_delete_dialog); - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext); + LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); mChatRoomsList.setLayoutManager(layoutManager); DividerItemDecoration dividerItemDecoration = new DividerItemDecoration( - mChatRoomsList.getContext(), - ((LinearLayoutManager) layoutManager).getOrientation()); + mChatRoomsList.getContext(), layoutManager.getOrientation()); dividerItemDecoration.setDrawable( getActivity() .getApplicationContext() @@ -118,18 +109,12 @@ public class ChatRoomsFragment extends Fragment mWaitLayout.setVisibility(View.GONE); - mNewDiscussionButton.setOnClickListener( + newDiscussionButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { - Bundle extras = null; - if (getArguments() != null) { - Log.i("[ChatRooms] Forwarding arguments to new chat room"); - extras = (Bundle) getArguments().clone(); - getArguments().clear(); - } - LinphoneActivity.instance() - .goToChatCreator(null, null, null, false, extras, false, false); + ((ChatActivity) getActivity()) + .showChatRoomCreation(null, null, null, false, false); } }); @@ -137,14 +122,8 @@ public class ChatRoomsFragment extends Fragment new View.OnClickListener() { @Override public void onClick(View v) { - Bundle extras = null; - if (getArguments() != null) { - Log.i("[ChatRooms] Forwarding arguments to new group chat room"); - extras = (Bundle) getArguments().clone(); - getArguments().clear(); - } - LinphoneActivity.instance() - .goToChatCreator(null, null, null, false, extras, true, false); + ((ChatActivity) getActivity()) + .showChatRoomCreation(null, null, null, false, true); } }); @@ -152,22 +131,38 @@ public class ChatRoomsFragment extends Fragment new View.OnClickListener() { @Override public void onClick(View v) { - LinphoneActivity.instance() - .resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); + startActivity(new Intent(getActivity(), CallActivity.class)); } }); mListener = new CoreListenerStub() { @Override - public void onMessageReceived(Core lc, ChatRoom cr, ChatMessage message) { - refreshChatRoomsList(); + public void onMessageSent(Core core, ChatRoom room, ChatMessage message) { + refreshChatRoom(room); } @Override - public void onChatRoomStateChanged(Core lc, ChatRoom cr, ChatRoom.State state) { + public void onMessageReceived(Core core, ChatRoom cr, ChatMessage message) { + refreshChatRoom(cr); + } + + @Override + public void onMessageReceivedUnableDecrypt( + Core core, ChatRoom room, ChatMessage message) { + refreshChatRoom(room); + } + + @Override + public void onChatRoomRead(Core core, ChatRoom room) { + refreshChatRoom(room); + } + + @Override + public void onChatRoomStateChanged( + Core core, ChatRoom cr, ChatRoom.State state) { if (state == ChatRoom.State.Created) { - refreshChatRoomsList(); + refreshChatRoom(cr); } } }; @@ -193,19 +188,6 @@ public class ChatRoomsFragment extends Fragment } }; - if (getArguments() != null) { - String fileSharedUri = getArguments().getString("fileSharedUri"); - String messageSharedUri = getArguments().getString("messageDraft"); - if (fileSharedUri != null || messageSharedUri != null) { - Toast.makeText( - LinphoneActivity.instance(), - R.string.toast_choose_chat_room_for_sharing, - Toast.LENGTH_LONG) - .show(); - } - Log.i("[ChatRooms] Arguments found: " + messageSharedUri + " / " + fileSharedUri); - } - return view; } @@ -215,17 +197,11 @@ public class ChatRoomsFragment extends Fragment mChatRoomsAdapter.toggleSelection(position); } else { ChatRoom room = (ChatRoom) mChatRoomsAdapter.getItem(position); - Bundle extras = null; - if (getArguments() != null) { - Log.i("[ChatRooms] Forwarding arguments to existing chat room"); - extras = (Bundle) getArguments().clone(); - getArguments().clear(); + if (room != null) { + ((ChatActivity) getActivity()) + .showChatRoom(room.getLocalAddress(), room.getPeerAddress()); + refreshChatRoom(room); } - LinphoneActivity.instance() - .goToChat( - room.getLocalAddress().asStringUriOnly(), - room.getPeerAddress().asString(), - extras); } } @@ -238,64 +214,33 @@ public class ChatRoomsFragment extends Fragment return true; } - private void refreshChatRoomsList() { - mChatRoomsAdapter.refresh(); - mNoChatHistory.setVisibility( - mChatRoomsAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); - } - - public void displayFirstChat() { - ChatRoomsAdapter adapter = (ChatRoomsAdapter) mChatRoomsList.getAdapter(); - if (adapter != null && adapter.getItemCount() > 0) { - ChatRoom room = (ChatRoom) adapter.getItem(0); - LinphoneActivity.instance() - .goToChat( - room.getLocalAddress().asStringUriOnly(), - room.getPeerAddress().asStringUriOnly(), - null); - } else { - LinphoneActivity.instance().displayEmptyFragment(); - } - } - - public void invalidate() { - if (mChatRoomsAdapter != null) { - mChatRoomsAdapter.notifyDataSetChanged(); - } - } - @Override public void onResume() { super.onResume(); ContactsManager.getInstance().addContactsListener(this); - if (LinphoneManager.getLc().getCallsNb() > 0) { - mBackToCallButton.setVisibility(View.VISIBLE); - } else { - mBackToCallButton.setVisibility(View.INVISIBLE); - } + mBackToCallButton.setVisibility(View.INVISIBLE); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.addListener(mListener); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.CHAT_LIST); - } - - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.addListener(mListener); + if (core.getCallsNb() > 0) { + mBackToCallButton.setVisibility(View.VISIBLE); + } } refreshChatRoomsList(); - ProxyConfig lpc = lc.getDefaultProxyConfig(); + ProxyConfig lpc = core.getDefaultProxyConfig(); mNewGroupDiscussionButton.setVisibility( (lpc != null && lpc.getConferenceFactoryUri() != null) ? View.VISIBLE : View.GONE); } @Override public void onPause() { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.removeListener(mListener); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.removeListener(mListener); } ContactsManager.getInstance().removeContactsListener(this); mChatRoomsAdapter.clear(); @@ -304,42 +249,44 @@ public class ChatRoomsFragment extends Fragment @Override public void onDeleteSelection(Object[] objectsToDelete) { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); mChatRoomDeletionPendingCount = objectsToDelete.length; for (Object obj : objectsToDelete) { ChatRoom room = (ChatRoom) obj; - - for (EventLog eventLog : room.getHistoryEvents(0)) { - if (eventLog.getType() == EventLog.Type.ConferenceChatMessage) { - ChatMessage message = eventLog.getChatMessage(); - if (message.getAppdata() != null && !message.isOutgoing()) { - File file = new File(message.getAppdata()); - if (file.exists()) { - file.delete(); // Delete downloaded file from incoming message that - // will be deleted - } - } - } - } - room.addListener(mChatRoomListener); - lc.deleteChatRoom(room); + core.deleteChatRoom(room); } if (mChatRoomDeletionPendingCount > 0) { mWaitLayout.setVisibility(View.VISIBLE); } - LinphoneActivity.instance() - .displayMissedChats(LinphoneManager.getInstance().getUnreadMessageCount()); + ((ChatActivity) getActivity()).displayMissedChats(); } @Override public void onContactsUpdated() { - if (!LinphoneActivity.isInstanciated() - || LinphoneActivity.instance().getCurrentFragment() != CHAT_LIST) return; - ChatRoomsAdapter adapter = (ChatRoomsAdapter) mChatRoomsList.getAdapter(); if (adapter != null) { adapter.notifyDataSetChanged(); } } + + private void refreshChatRoom(ChatRoom cr) { + ChatRoomViewHolder holder = (ChatRoomViewHolder) cr.getUserData(); + if (holder != null) { + int position = holder.getAdapterPosition(); + if (position == 0) { + mChatRoomsAdapter.notifyItemChanged(0); + } else { + refreshChatRoomsList(); + } + } else { + refreshChatRoomsList(); + } + } + + private void refreshChatRoomsList() { + mChatRoomsAdapter.refresh(); + mNoChatHistory.setVisibility( + mChatRoomsAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); + } } diff --git a/app/src/main/java/org/linphone/chat/ChatScrollListener.java b/app/src/main/java/org/linphone/chat/ChatScrollListener.java index 7140ed228..c1af953c4 100644 --- a/app/src/main/java/org/linphone/chat/ChatScrollListener.java +++ b/app/src/main/java/org/linphone/chat/ChatScrollListener.java @@ -2,7 +2,7 @@ package org.linphone.chat; /* ChatScrollListener.java -Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France +Copyright (C) 2018 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 @@ -25,7 +25,7 @@ import androidx.recyclerview.widget.RecyclerView; abstract class ChatScrollListener extends RecyclerView.OnScrollListener { // The minimum amount of items to have below your current scroll position // before mLoading more. - private final int mVisibleThreshold = 5; + private static final int mVisibleThreshold = 5; // The total number of items in the dataset after the last load private int mPreviousTotalItemCount = 0; // True if we are still waiting for the last set of data to load. diff --git a/app/src/main/java/org/linphone/chat/DeviceChildViewHolder.java b/app/src/main/java/org/linphone/chat/DeviceChildViewHolder.java index 2498372be..92219d365 100644 --- a/app/src/main/java/org/linphone/chat/DeviceChildViewHolder.java +++ b/app/src/main/java/org/linphone/chat/DeviceChildViewHolder.java @@ -2,7 +2,7 @@ package org.linphone.chat; /* DeviceChildViewHolder.java -Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France +Copyright (C) 2018 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 diff --git a/app/src/main/java/org/linphone/chat/DeviceGroupViewHolder.java b/app/src/main/java/org/linphone/chat/DeviceGroupViewHolder.java index bc72f4004..805a68fc1 100644 --- a/app/src/main/java/org/linphone/chat/DeviceGroupViewHolder.java +++ b/app/src/main/java/org/linphone/chat/DeviceGroupViewHolder.java @@ -2,7 +2,7 @@ package org.linphone.chat; /* DeviceGroupViewHolder.java -Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France +Copyright (C) 2018 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 diff --git a/app/src/main/java/org/linphone/chat/DevicesAdapter.java b/app/src/main/java/org/linphone/chat/DevicesAdapter.java index fdd28d863..1a8da4005 100644 --- a/app/src/main/java/org/linphone/chat/DevicesAdapter.java +++ b/app/src/main/java/org/linphone/chat/DevicesAdapter.java @@ -2,7 +2,7 @@ package org.linphone.chat; /* DevicesAdapter.java -Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France +Copyright (C) 2018 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 diff --git a/app/src/main/java/org/linphone/chat/DevicesFragment.java b/app/src/main/java/org/linphone/chat/DevicesFragment.java index 6f99c875b..7eceb9118 100644 --- a/app/src/main/java/org/linphone/chat/DevicesFragment.java +++ b/app/src/main/java/org/linphone/chat/DevicesFragment.java @@ -1,6 +1,8 @@ +package org.linphone.chat; + /* DevicesFragment.java -Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France +Copyright (C) 2018 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 @@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.linphone.chat; - import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; @@ -29,28 +29,23 @@ import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.Nullable; import java.util.Arrays; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; -import org.linphone.call.CallManager; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; import org.linphone.core.Address; import org.linphone.core.ChatRoom; import org.linphone.core.ChatRoomCapabilities; import org.linphone.core.Core; +import org.linphone.core.Factory; import org.linphone.core.ParticipantDevice; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.utils.LinphoneUtils; public class DevicesFragment extends Fragment { - private LayoutInflater mInflater; - private ImageView mBackButton; private TextView mTitle; private ExpandableListView mExpandableList; private DevicesAdapter mAdapter; - private String mLocalSipUri, mRoomUri; private Address mLocalSipAddr, mRoomAddr; private ChatRoom mRoom; private boolean mOnlyDisplayChilds; @@ -62,14 +57,13 @@ public class DevicesFragment extends Fragment { super.onCreate(savedInstanceState); if (getArguments() != null) { - mLocalSipUri = getArguments().getString("LocalSipUri"); - mLocalSipAddr = LinphoneManager.getLc().createAddress(mLocalSipUri); - mRoomUri = getArguments().getString("RemoteSipUri"); - mRoomAddr = LinphoneManager.getLc().createAddress(mRoomUri); + String localSipUri = getArguments().getString("LocalSipUri"); + mLocalSipAddr = Factory.instance().createAddress(localSipUri); + String roomUri = getArguments().getString("RemoteSipUri"); + mRoomAddr = Factory.instance().createAddress(roomUri); } - mInflater = inflater; - View view = mInflater.inflate(R.layout.chat_devices, container, false); + View view = inflater.inflate(R.layout.chat_devices, container, false); mOnlyDisplayChilds = false; @@ -85,7 +79,7 @@ public class DevicesFragment extends Fragment { long l) { ParticipantDevice device = (ParticipantDevice) mAdapter.getChild(groupPosition, childPosition); - CallManager.getInstance().inviteAddress(device.getAddress(), true); + LinphoneManager.getCallManager().inviteAddress(device.getAddress(), true); return false; } }); @@ -101,13 +95,15 @@ public class DevicesFragment extends Fragment { // in this case groups are childs, so call on click ParticipantDevice device = (ParticipantDevice) mAdapter.getGroup(groupPosition); - CallManager.getInstance().inviteAddress(device.getAddress(), true); + LinphoneManager.getCallManager() + .inviteAddress(device.getAddress(), true); return true; } else { if (mAdapter.getChildrenCount(groupPosition) == 1) { ParticipantDevice device = (ParticipantDevice) mAdapter.getChild(groupPosition, 0); - CallManager.getInstance().inviteAddress(device.getAddress(), true); + LinphoneManager.getCallManager() + .inviteAddress(device.getAddress(), true); return true; } } @@ -120,16 +116,12 @@ public class DevicesFragment extends Fragment { mTitle = view.findViewById(R.id.title); initHeader(); - mBackButton = view.findViewById(R.id.back); - mBackButton.setOnClickListener( + ImageView backButton = view.findViewById(R.id.back); + backButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { - if (LinphoneActivity.instance().isTablet()) { - LinphoneActivity.instance().goToChat(mLocalSipUri, mRoomUri, null); - } else { - LinphoneActivity.instance().onBackPressed(); - } + ((ChatActivity) getActivity()).goBack(); } }); @@ -140,10 +132,6 @@ public class DevicesFragment extends Fragment { public void onResume() { super.onResume(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.CONTACT_DEVICES); - } - initValues(); if (LinphoneManager.getInstance().hasLastCallSasBeenRejected()) { @@ -153,7 +141,7 @@ public class DevicesFragment extends Fragment { } private void initChatRoom() { - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); mRoom = core.getChatRoom(mRoomAddr, mLocalSipAddr); } diff --git a/app/src/main/java/org/linphone/chat/GroupInfoAdapter.java b/app/src/main/java/org/linphone/chat/GroupInfoAdapter.java index e0d515a0a..12d7ac207 100644 --- a/app/src/main/java/org/linphone/chat/GroupInfoAdapter.java +++ b/app/src/main/java/org/linphone/chat/GroupInfoAdapter.java @@ -1,6 +1,8 @@ +package org.linphone.chat; + /* GroupInfoAdapter.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.linphone.chat; - import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -26,7 +26,7 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.List; -import org.linphone.LinphoneActivity; +import org.linphone.LinphoneService; import org.linphone.R; import org.linphone.contacts.ContactAddress; import org.linphone.contacts.LinphoneContact; @@ -73,7 +73,7 @@ class GroupInfoAdapter extends RecyclerView.Adapter { holder.sipUri.setText(ca.getAddressAsDisplayableString()); - if (!LinphoneActivity.instance().getResources().getBoolean(R.bool.show_sip_uri_in_chat)) { + if (!LinphoneService.instance().getResources().getBoolean(R.bool.show_sip_uri_in_chat)) { holder.sipUri.setVisibility(View.GONE); holder.name.setOnClickListener( new View.OnClickListener() { diff --git a/app/src/main/java/org/linphone/chat/GroupInfoFragment.java b/app/src/main/java/org/linphone/chat/GroupInfoFragment.java index 1e3f5f5ec..4db353133 100644 --- a/app/src/main/java/org/linphone/chat/GroupInfoFragment.java +++ b/app/src/main/java/org/linphone/chat/GroupInfoFragment.java @@ -1,6 +1,8 @@ +package org.linphone.chat; + /* -InfoGroupChatFragment.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +GroupInfoFragment.java +Copyright (C) 2017 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 @@ -17,13 +19,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.linphone.chat; - import static android.content.Context.INPUT_METHOD_SERVICE; import android.app.Dialog; import android.app.Fragment; -import android.content.Context; +import android.app.FragmentManager; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; @@ -40,34 +40,31 @@ import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.contacts.ContactAddress; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; import org.linphone.core.Address; -import org.linphone.core.ChatMessage; import org.linphone.core.ChatRoom; -import org.linphone.core.ChatRoomListener; +import org.linphone.core.ChatRoomCapabilities; import org.linphone.core.ChatRoomListenerStub; import org.linphone.core.ChatRoomParams; import org.linphone.core.Core; import org.linphone.core.EventLog; +import org.linphone.core.Factory; import org.linphone.core.Participant; import org.linphone.core.tools.Log; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.utils.LinphoneUtils; -public class GroupInfoFragment extends Fragment implements ChatRoomListener { - private ImageView mBackButton, mConfirmButton, mAddParticipantsButton; - private RelativeLayout mAddParticipantsLayout; +public class GroupInfoFragment extends Fragment { + private ImageView mConfirmButton; + private ImageView mAddParticipantsButton; private Address mGroupChatRoomAddress; private EditText mSubjectField; private RecyclerView mParticipantsList; - private LinearLayout mLeaveGroupButton; private RelativeLayout mWaitLayout; private GroupInfoAdapter mAdapter; private boolean mIsAlreadyCreatedGroup; @@ -77,10 +74,8 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { private ChatRoom mChatRoom, mTempChatRoom; private Dialog mAdminStateChangedDialog; private ChatRoomListenerStub mChatRoomCreationListener; - private Bundle mShareInfos; - private Context mContext; - private LinearLayoutManager layoutManager; private boolean mIsEncryptionEnabled; + private ChatRoomListenerStub mListener; @Override public View onCreateView( @@ -90,32 +85,34 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { if (getArguments() == null || getArguments().isEmpty()) { return null; } - mContext = getActivity().getApplicationContext(); - - mParticipants = - (ArrayList) getArguments().getSerializable("ContactAddress"); + mParticipants = (ArrayList) getArguments().getSerializable("Participants"); mGroupChatRoomAddress = null; mChatRoom = null; - String address = getArguments().getString("groupChatRoomAddress"); + String address = getArguments().getString("RemoteSipUri"); if (address != null && address.length() > 0) { - mGroupChatRoomAddress = LinphoneManager.getLc().createAddress(address); + mGroupChatRoomAddress = Factory.instance().createAddress(address); } + mIsAlreadyCreatedGroup = mGroupChatRoomAddress != null; if (mIsAlreadyCreatedGroup) { - mChatRoom = LinphoneManager.getLc().getChatRoom(mGroupChatRoomAddress); - } - if (mChatRoom == null) mIsAlreadyCreatedGroup = false; - - mIsEditionEnabled = getArguments().getBoolean("isEditionEnabled"); - mSubject = getArguments().getString("subject"); - - if (mChatRoom != null && mChatRoom.hasBeenLeft()) { - mIsEditionEnabled = false; + mChatRoom = LinphoneManager.getCore().getChatRoom(mGroupChatRoomAddress); } - mIsEncryptionEnabled = getArguments().getBoolean("encryptionEnabled", false); + if (mChatRoom == null) { + mIsAlreadyCreatedGroup = false; + mIsEditionEnabled = true; + mSubject = getArguments().getString("Subject", ""); + mIsEncryptionEnabled = getArguments().getBoolean("Encrypted", false); + } else { + mIsEditionEnabled = + mChatRoom.getMe() != null + && mChatRoom.getMe().isAdmin() + && !mChatRoom.hasBeenLeft(); + mSubject = mChatRoom.getSubject(); + mIsEncryptionEnabled = mChatRoom.hasCapability(ChatRoomCapabilities.Encrypted.toInt()); + } mParticipantsList = view.findViewById(R.id.chat_room_participants); mAdapter = new GroupInfoAdapter(mParticipants, !mIsEditionEnabled, !mIsAlreadyCreatedGroup); @@ -133,126 +130,55 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { }); mParticipantsList.setAdapter(mAdapter); mAdapter.setChatRoom(mChatRoom); - layoutManager = new LinearLayoutManager(mContext); + LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); mParticipantsList.setLayoutManager(layoutManager); // Divider between items DividerItemDecoration dividerItemDecoration = new DividerItemDecoration( mParticipantsList.getContext(), layoutManager.getOrientation()); - dividerItemDecoration.setDrawable(mContext.getResources().getDrawable(R.drawable.divider)); + dividerItemDecoration.setDrawable(getResources().getDrawable(R.drawable.divider)); mParticipantsList.addItemDecoration(dividerItemDecoration); - String fileSharedUri = getArguments().getString("fileSharedUri"); - String messageDraft = getArguments().getString("messageDraft"); - - if (fileSharedUri != null || messageDraft != null) { - Log.i("[GroupInfo] Forwarding arguments to group chat room"); - mShareInfos = new Bundle(); - } - - if (fileSharedUri != null) mShareInfos.putString("fileSharedUri", fileSharedUri); - - if (messageDraft != null) mShareInfos.putString("messageDraft", messageDraft); - - mBackButton = view.findViewById(R.id.back); - mBackButton.setOnClickListener( + ImageView backButton = view.findViewById(R.id.back); + backButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { - if (mIsAlreadyCreatedGroup) { - if (LinphoneActivity.instance().isTablet()) { - LinphoneActivity.instance() - .goToChat( - mChatRoom.getLocalAddress().asStringUriOnly(), - mGroupChatRoomAddress.asStringUriOnly(), - mShareInfos); - } else { - getFragmentManager().popBackStack(); - } - } else { - LinphoneActivity.instance() - .goToChatCreator( - null, - mParticipants, - null, - true, - mShareInfos, - true, - mIsEncryptionEnabled); - } + ((ChatActivity) getActivity()).goBack(); } }); mConfirmButton = view.findViewById(R.id.confirm); - - mLeaveGroupButton = view.findViewById(R.id.leaveGroupLayout); - mLeaveGroupButton.setOnClickListener( + mConfirmButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { - final Dialog dialog = - LinphoneActivity.instance() - .displayDialog(getString(R.string.chat_room_leave_dialog)); - Button delete = dialog.findViewById(R.id.dialog_delete_button); - delete.setText(getString(R.string.chat_room_leave_button)); - Button cancel = dialog.findViewById(R.id.dialog_cancel_button); - - delete.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View view) { - if (mChatRoom != null) { - mChatRoom.leave(); - LinphoneActivity.instance() - .goToChat( - mChatRoom - .getLocalAddress() - .asStringUriOnly(), - mGroupChatRoomAddress.asString(), - null); - } else { - Log.e( - "Can't leave, chatRoom for address " - + mGroupChatRoomAddress.asString() - + " is null..."); - } - dialog.dismiss(); - } - }); - - cancel.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View view) { - dialog.dismiss(); - } - }); - dialog.show(); + applyChanges(); } }); - mLeaveGroupButton.setVisibility( + mConfirmButton.setEnabled(!mSubject.isEmpty() && mParticipants.size() > 0); + + LinearLayout leaveGroupButton = view.findViewById(R.id.leaveGroupLayout); + leaveGroupButton.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View view) { + showLeaveGroupDialog(); + } + }); + leaveGroupButton.setVisibility( mIsAlreadyCreatedGroup && mChatRoom.hasBeenLeft() ? View.GONE : mIsAlreadyCreatedGroup ? View.VISIBLE : View.GONE); - mAddParticipantsLayout = view.findViewById(R.id.addParticipantsLayout); - mAddParticipantsLayout.setOnClickListener( + RelativeLayout addParticipantsLayout = view.findViewById(R.id.addParticipantsLayout); + addParticipantsLayout.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { if (mIsEditionEnabled && mIsAlreadyCreatedGroup) { - LinphoneActivity.instance() - .goToChatCreator( - mGroupChatRoomAddress != null - ? mGroupChatRoomAddress.asString() - : null, - mParticipants, - mSubject, - !mIsAlreadyCreatedGroup, - null, - true, - mIsEncryptionEnabled); + goBackToChatCreationFragment(); } } }); @@ -262,17 +188,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { @Override public void onClick(View view) { if (mIsEditionEnabled && mIsAlreadyCreatedGroup) { - LinphoneActivity.instance() - .goToChatCreator( - mGroupChatRoomAddress != null - ? mGroupChatRoomAddress.asString() - : null, - mParticipants, - mSubject, - !mIsAlreadyCreatedGroup, - null, - true, - mIsEncryptionEnabled); + goBackToChatCreationFragment(); } } }); @@ -302,118 +218,23 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { public void onStateChanged(ChatRoom cr, ChatRoom.State newState) { if (newState == ChatRoom.State.Created) { mWaitLayout.setVisibility(View.GONE); - // This will remove both the creation fragment and the group info - // fragment from the back stack + // Pop the back stack twice so we don't have in stack Creation -> Group + // Behind the chat room, so a back press will take us back to the rooms getFragmentManager().popBackStack(); getFragmentManager().popBackStack(); - LinphoneActivity.instance() - .goToChat( - cr.getLocalAddress().asStringUriOnly(), - cr.getPeerAddress().asStringUriOnly(), - mShareInfos); + ((ChatActivity) getActivity()) + .showChatRoom(cr.getLocalAddress(), cr.getPeerAddress()); } else if (newState == ChatRoom.State.CreationFailed) { mWaitLayout.setVisibility(View.GONE); - LinphoneActivity.instance().displayChatRoomError(); + ((ChatActivity) getActivity()).displayChatRoomError(); Log.e( - "Group chat room for address " + "[Group Info] Group chat room for address " + cr.getPeerAddress() + " has failed !"); } } }; - mConfirmButton.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View view) { - if (!mIsAlreadyCreatedGroup) { - mWaitLayout.setVisibility(View.VISIBLE); - Core core = LinphoneManager.getLc(); - - int i = 0; - Address[] participants = new Address[mParticipants.size()]; - for (ContactAddress ca : mParticipants) { - participants[i] = ca.getAddress(); - i++; - } - - ChatRoomParams params = core.createDefaultChatRoomParams(); - params.enableEncryption(mIsEncryptionEnabled); - params.enableGroup(true); - - mTempChatRoom = - core.createChatRoom( - params, - mSubjectField.getText().toString(), - participants); - if (mTempChatRoom != null) { - mTempChatRoom.addListener(mChatRoomCreationListener); - } else { - Log.w("[Group Info Fragment] createChatRoom returned null..."); - mWaitLayout.setVisibility(View.GONE); - } - } else { - // Subject - String newSubject = mSubjectField.getText().toString(); - if (!newSubject.equals(mSubject)) { - mChatRoom.setSubject(newSubject); - } - - // Participants removed - ArrayList toRemove = new ArrayList<>(); - for (Participant p : mChatRoom.getParticipants()) { - boolean found = false; - for (ContactAddress c : mParticipants) { - if (c.getAddress().weakEqual(p.getAddress())) { - found = true; - break; - } - } - if (!found) { - toRemove.add(p); - } - } - Participant[] participantsToRemove = new Participant[toRemove.size()]; - toRemove.toArray(participantsToRemove); - mChatRoom.removeParticipants(participantsToRemove); - - // Participants added - ArrayList
    toAdd = new ArrayList<>(); - for (ContactAddress c : mParticipants) { - boolean found = false; - for (Participant p : mChatRoom.getParticipants()) { - if (p.getAddress().weakEqual(c.getAddress())) { - // Admin rights - if (c.isAdmin() != p.isAdmin()) { - mChatRoom.setParticipantAdminStatus(p, c.isAdmin()); - } - found = true; - break; - } - } - if (!found) { - Address addr = c.getAddress(); - if (addr != null) { - toAdd.add(addr); - } else { - // TODO error - } - } - } - Address[] participantsToAdd = new Address[toAdd.size()]; - toAdd.toArray(participantsToAdd); - mChatRoom.addParticipants(participantsToAdd); - - LinphoneActivity.instance() - .goToChat( - mChatRoom.getLocalAddress().asStringUriOnly(), - mGroupChatRoomAddress.asString(), - null); - } - } - }); - mConfirmButton.setEnabled(mSubjectField.getText().length() > 0 && mParticipants.size() > 0); - if (!mIsEditionEnabled) { mSubjectField.setEnabled(false); mConfirmButton.setVisibility(View.INVISIBLE); @@ -423,8 +244,27 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { mWaitLayout = view.findViewById(R.id.waitScreen); mWaitLayout.setVisibility(View.GONE); + mListener = + new ChatRoomListenerStub() { + @Override + public void onParticipantAdminStatusChanged(ChatRoom cr, EventLog event_log) { + if (mChatRoom.getMe().isAdmin() != mIsEditionEnabled) { + // Either we weren't admin and we are now or the other way around + mIsEditionEnabled = mChatRoom.getMe().isAdmin(); + displayMeAdminStatusUpdated(); + refreshAdminRights(); + } + refreshParticipantsList(); + } + + @Override + public void onSubjectChanged(ChatRoom cr, EventLog event_log) { + mSubjectField.setText(event_log.getSubject()); + } + }; + if (mChatRoom != null) { - mChatRoom.addListener(this); + mChatRoom.addListener(mListener); } return view; @@ -434,10 +274,6 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { public void onResume() { super.onResume(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.INFO_GROUP_CHAT); - } - InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE); if (getActivity().getCurrentFocus() != null) { @@ -457,11 +293,34 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { @Override public void onDestroy() { if (mChatRoom != null) { - mChatRoom.removeListener(this); + mChatRoom.removeListener(mListener); } super.onDestroy(); } + private void goBackToChatCreationFragment() { + boolean previousFragmentInBackStackIsChatRoomCreation = false; + FragmentManager fragmentManager = getActivity().getFragmentManager(); + int count = fragmentManager.getBackStackEntryCount(); + if (count > 1) { + FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(count - 1); + if ("Chat room creation".equals(entry.getName())) { + previousFragmentInBackStackIsChatRoomCreation = true; + ((ChatActivity) getActivity()).goBack(); + } + } + + if (!previousFragmentInBackStackIsChatRoomCreation) { + ((ChatActivity) getActivity()) + .showChatRoomCreation( + mGroupChatRoomAddress, + mParticipants, + mSubject, + mIsEncryptionEnabled, + true); + } + } + private void refreshParticipantsList() { if (mChatRoom == null) return; mParticipants = new ArrayList<>(); @@ -473,7 +332,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { String displayName = LinphoneUtils.getAddressDisplayName(a); c.setFullName(displayName); } - ContactAddress ca = new ContactAddress(c, a.asString(), "", c.isFriend(), p.isAdmin()); + ContactAddress ca = new ContactAddress(c, a.asString(), "", p.isAdmin()); mParticipants.add(ca); } @@ -493,7 +352,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { if (mAdminStateChangedDialog != null) mAdminStateChangedDialog.dismiss(); mAdminStateChangedDialog = - LinphoneActivity.instance() + ((ChatActivity) getActivity()) .displayDialog( getString( mIsEditionEnabled @@ -513,78 +372,121 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { mAdminStateChangedDialog.show(); } - @Override - public void onParticipantAdminStatusChanged(ChatRoom cr, EventLog event_log) { - if (mChatRoom.getMe().isAdmin() != mIsEditionEnabled) { - // Either we weren't admin and we are now or the other way around - mIsEditionEnabled = mChatRoom.getMe().isAdmin(); - displayMeAdminStatusUpdated(); - refreshAdminRights(); + private void showLeaveGroupDialog() { + final Dialog dialog = + ((ChatActivity) getActivity()) + .displayDialog(getString(R.string.chat_room_leave_dialog)); + Button delete = dialog.findViewById(R.id.dialog_delete_button); + delete.setText(getString(R.string.chat_room_leave_button)); + Button cancel = dialog.findViewById(R.id.dialog_cancel_button); + + delete.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mChatRoom != null) { + mChatRoom.leave(); + ((ChatActivity) getActivity()) + .showChatRoom( + mChatRoom.getLocalAddress(), + mChatRoom.getPeerAddress()); + } else { + Log.e( + "[Group Info] Can't leave, chatRoom for address " + + mGroupChatRoomAddress.asString() + + " is null..."); + } + dialog.dismiss(); + } + }); + + cancel.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View view) { + dialog.dismiss(); + } + }); + dialog.show(); + } + + private void applyChanges() { + if (!mIsAlreadyCreatedGroup) { + mWaitLayout.setVisibility(View.VISIBLE); + Core core = LinphoneManager.getCore(); + + int i = 0; + Address[] participants = new Address[mParticipants.size()]; + for (ContactAddress ca : mParticipants) { + participants[i] = ca.getAddress(); + i++; + } + + ChatRoomParams params = core.createDefaultChatRoomParams(); + params.enableEncryption(mIsEncryptionEnabled); + params.enableGroup(true); + + mTempChatRoom = + core.createChatRoom(params, mSubjectField.getText().toString(), participants); + if (mTempChatRoom != null) { + mTempChatRoom.addListener(mChatRoomCreationListener); + } else { + Log.w("[Group Info] createChatRoom returned null..."); + mWaitLayout.setVisibility(View.GONE); + } + } else { + // Subject + String newSubject = mSubjectField.getText().toString(); + if (!newSubject.equals(mSubject)) { + mChatRoom.setSubject(newSubject); + } + + // Participants removed + ArrayList toRemove = new ArrayList<>(); + for (Participant p : mChatRoom.getParticipants()) { + boolean found = false; + for (ContactAddress c : mParticipants) { + if (c.getAddress().weakEqual(p.getAddress())) { + found = true; + break; + } + } + if (!found) { + toRemove.add(p); + } + } + Participant[] participantsToRemove = new Participant[toRemove.size()]; + toRemove.toArray(participantsToRemove); + mChatRoom.removeParticipants(participantsToRemove); + + // Participants added + ArrayList
    toAdd = new ArrayList<>(); + for (ContactAddress c : mParticipants) { + boolean found = false; + for (Participant p : mChatRoom.getParticipants()) { + if (p.getAddress().weakEqual(c.getAddress())) { + // Admin rights + if (c.isAdmin() != p.isAdmin()) { + mChatRoom.setParticipantAdminStatus(p, c.isAdmin()); + } + found = true; + break; + } + } + if (!found) { + Address addr = c.getAddress(); + if (addr != null) { + toAdd.add(addr); + } else { + // TODO error + } + } + } + Address[] participantsToAdd = new Address[toAdd.size()]; + toAdd.toArray(participantsToAdd); + mChatRoom.addParticipants(participantsToAdd); + // Pop back stack to go back to the Messages fragment + getFragmentManager().popBackStack(); } - refreshParticipantsList(); } - - @Override - public void onSubjectChanged(ChatRoom cr, EventLog event_log) { - mSubjectField.setText(event_log.getSubject()); - } - - @Override - public void onConferenceJoined(ChatRoom cr, EventLog event_log) {} - - @Override - public void onConferenceLeft(ChatRoom cr, EventLog event_log) {} - - @Override - public void onParticipantAdded(ChatRoom cr, EventLog event_log) { - refreshParticipantsList(); - } - - @Override - public void onParticipantRemoved(ChatRoom cr, EventLog event_log) { - refreshParticipantsList(); - } - - @Override - public void onChatMessageShouldBeStored(ChatRoom cr, ChatMessage msg) {} - - @Override - public void onIsComposingReceived(ChatRoom cr, Address remoteAddr, boolean isComposing) {} - - @Override - public void onChatMessageSent(ChatRoom cr, EventLog event_log) {} - - @Override - public void onConferenceAddressGeneration(ChatRoom cr) {} - - @Override - public void onChatMessageReceived(ChatRoom cr, EventLog event_log) {} - - @Override - public void onMessageReceived(ChatRoom cr, ChatMessage msg) {} - - @Override - public void onParticipantDeviceRemoved(ChatRoom cr, EventLog event_log) {} - - @Override - public void onParticipantDeviceAdded(ChatRoom cr, EventLog event_log) {} - - @Override - public void onSecurityEvent(ChatRoom cr, EventLog eventLog) { - refreshParticipantsList(); - } - - @Override - public void onUndecryptableMessageReceived(ChatRoom cr, ChatMessage msg) {} - - @Override - public void onStateChanged(ChatRoom cr, ChatRoom.State newState) {} - - @Override - public void onParticipantRegistrationSubscriptionRequested( - ChatRoom cr, Address participantAddr) {} - - @Override - public void onParticipantRegistrationUnsubscriptionRequested( - ChatRoom cr, Address participantAddr) {} } diff --git a/app/src/main/java/org/linphone/chat/GroupInfoViewHolder.java b/app/src/main/java/org/linphone/chat/GroupInfoViewHolder.java index 5f0e2017b..9a2988db2 100644 --- a/app/src/main/java/org/linphone/chat/GroupInfoViewHolder.java +++ b/app/src/main/java/org/linphone/chat/GroupInfoViewHolder.java @@ -2,7 +2,7 @@ package org.linphone.chat; /* GroupInfoViewHolder.java -Copyright (C) 2018 Belledonne Communications, Grenoble, France +Copyright (C) 2018 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 diff --git a/app/src/main/java/org/linphone/chat/ImdnFragment.java b/app/src/main/java/org/linphone/chat/ImdnFragment.java index deb26ceb1..2c6d83320 100644 --- a/app/src/main/java/org/linphone/chat/ImdnFragment.java +++ b/app/src/main/java/org/linphone/chat/ImdnFragment.java @@ -1,6 +1,8 @@ +package org.linphone.chat; + /* -ImdnOldFragment.java -Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France +ImdnFragment.java +Copyright (C) 2018 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 @@ -17,8 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.linphone.chat; - import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; @@ -28,7 +28,6 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.Nullable; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.contacts.ContactsManager; @@ -38,8 +37,8 @@ import org.linphone.core.ChatMessage; import org.linphone.core.ChatMessageListenerStub; import org.linphone.core.ChatRoom; import org.linphone.core.Core; +import org.linphone.core.Factory; import org.linphone.core.ParticipantImdnState; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.utils.LinphoneUtils; import org.linphone.views.ContactAvatar; @@ -53,13 +52,11 @@ public class ImdnFragment extends Fragment { mSentHeader, mUndelivered, mUndeliveredHeader; - private ImageView mBackButton; private ChatMessageViewHolder mBubble; private ViewGroup mContainer; - private String mLocalSipuri, mRoomUri, mMessageId; + private String mMessageId; private Address mLocalSipAddr, mRoomAddr; - private ChatRoom mRoom; private ChatMessage mMessage; private ChatMessageListenerStub mListener; @@ -70,29 +67,29 @@ public class ImdnFragment extends Fragment { super.onCreate(savedInstanceState); if (getArguments() != null) { - mLocalSipuri = getArguments().getString("LocalSipUri"); - mLocalSipAddr = LinphoneManager.getLc().createAddress(mLocalSipuri); - mRoomUri = getArguments().getString("RemoteSipUri"); - mRoomAddr = LinphoneManager.getLc().createAddress(mRoomUri); + String localSipuri = getArguments().getString("LocalSipUri"); + mLocalSipAddr = Factory.instance().createAddress(localSipuri); + String roomUri = getArguments().getString("RemoteSipUri"); + mRoomAddr = Factory.instance().createAddress(roomUri); mMessageId = getArguments().getString("MessageId"); } - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - mRoom = core.getChatRoom(mRoomAddr, mLocalSipAddr); + Core core = LinphoneManager.getCore(); + ChatRoom room = core.getChatRoom(mRoomAddr, mLocalSipAddr); mInflater = inflater; mContainer = container; View view = mInflater.inflate(R.layout.chat_imdn, container, false); - mBackButton = view.findViewById(R.id.back); - mBackButton.setOnClickListener( + ImageView backButton = view.findViewById(R.id.back); + backButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { - if (LinphoneActivity.instance().isTablet()) { - LinphoneActivity.instance().goToChat(mLocalSipuri, mRoomUri, null); + if (getResources().getBoolean(R.bool.isTablet)) { + ((ChatActivity) getActivity()).showChatRoom(mLocalSipAddr, mRoomAddr); } else { - LinphoneActivity.instance().onBackPressed(); + ((ChatActivity) getActivity()).popBackStack(); } } }); @@ -108,7 +105,7 @@ public class ImdnFragment extends Fragment { mBubble = new ChatMessageViewHolder(getActivity(), view.findViewById(R.id.bubble), null); - mMessage = mRoom.findMessage(mMessageId); + mMessage = room.findMessage(mMessageId); mListener = new ChatMessageListenerStub() { @Override @@ -125,10 +122,6 @@ public class ImdnFragment extends Fragment { public void onResume() { super.onResume(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.MESSAGE_IMDN); - } - refreshInfo(); if (mMessage != null) { mMessage.addListener(mListener); @@ -197,9 +190,7 @@ public class ImdnFragment extends Fragment { final TextView sipUri = v.findViewById(R.id.sipUri); sipUri.setText(address.asStringUriOnly()); - if (!LinphoneActivity.instance() - .getResources() - .getBoolean(R.bool.show_sip_uri_in_chat)) { + if (!getResources().getBoolean(R.bool.show_sip_uri_in_chat)) { sipUri.setVisibility(View.GONE); name.setOnClickListener( new View.OnClickListener() { @@ -249,9 +240,7 @@ public class ImdnFragment extends Fragment { final TextView sipUri = v.findViewById(R.id.sipUri); sipUri.setText(address.asStringUriOnly()); - if (!LinphoneActivity.instance() - .getResources() - .getBoolean(R.bool.show_sip_uri_in_chat)) { + if (!getResources().getBoolean(R.bool.show_sip_uri_in_chat)) { sipUri.setVisibility(View.GONE); name.setOnClickListener( new View.OnClickListener() { @@ -301,9 +290,7 @@ public class ImdnFragment extends Fragment { final TextView sipUri = v.findViewById(R.id.sipUri); sipUri.setText(address.asStringUriOnly()); - if (!LinphoneActivity.instance() - .getResources() - .getBoolean(R.bool.show_sip_uri_in_chat)) { + if (!getResources().getBoolean(R.bool.show_sip_uri_in_chat)) { sipUri.setVisibility(View.GONE); name.setOnClickListener( new View.OnClickListener() { @@ -347,9 +334,7 @@ public class ImdnFragment extends Fragment { final TextView sipUri = v.findViewById(R.id.sipUri); sipUri.setText(address.asStringUriOnly()); - if (!LinphoneActivity.instance() - .getResources() - .getBoolean(R.bool.show_sip_uri_in_chat)) { + if (!getResources().getBoolean(R.bool.show_sip_uri_in_chat)) { sipUri.setVisibility(View.GONE); name.setOnClickListener( new View.OnClickListener() { diff --git a/app/src/main/java/org/linphone/chat/ImdnOldFragment.java b/app/src/main/java/org/linphone/chat/ImdnOldFragment.java deleted file mode 100644 index ae38309d9..000000000 --- a/app/src/main/java/org/linphone/chat/ImdnOldFragment.java +++ /dev/null @@ -1,357 +0,0 @@ -package org.linphone.chat; - -/* -ImdnOldFragment.java -Copyright (C) 2010-2018 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -import android.app.Fragment; -import android.os.Bundle; -import android.text.Spanned; -import android.text.method.LinkMovementMethod; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.TextView; -import androidx.annotation.Nullable; -import org.linphone.LinphoneActivity; -import org.linphone.LinphoneManager; -import org.linphone.R; -import org.linphone.compatibility.Compatibility; -import org.linphone.contacts.ContactsManager; -import org.linphone.contacts.LinphoneContact; -import org.linphone.core.Address; -import org.linphone.core.ChatMessage; -import org.linphone.core.ChatMessageListenerStub; -import org.linphone.core.ChatRoom; -import org.linphone.core.Core; -import org.linphone.core.ParticipantImdnState; -import org.linphone.fragments.FragmentsAvailable; -import org.linphone.utils.FileUtils; -import org.linphone.utils.LinphoneUtils; -import org.linphone.views.ContactAvatar; - -public class ImdnOldFragment extends Fragment { - private LayoutInflater mInflater; - private LinearLayout mRead, - mReadHeader, - mDelivered, - mDeliveredHeader, - mSent, - mSentHeader, - mUndelivered, - mUndeliveredHeader; - private ImageView mBackButton; - private ChatMessageOldViewHolder mBubble; - private ViewGroup mContainer; - - private String mLocalSipUri, mRoomUri, mMessageId; - private Address mLocalAddr, mRoomAddr; - private ChatRoom mRoom; - private ChatMessage mMessage; - private ChatMessageListenerStub mListener; - - @Nullable - @Override - public View onCreateView( - LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (getArguments() != null) { - mLocalSipUri = getArguments().getString("LocalSipUri"); - mLocalAddr = LinphoneManager.getLc().createAddress(mLocalSipUri); - mRoomUri = getArguments().getString("RemoteSipUri"); - mRoomAddr = LinphoneManager.getLc().createAddress(mRoomUri); - mMessageId = getArguments().getString("MessageId"); - } - - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - mRoom = core.getChatRoom(mRoomAddr, mLocalAddr); - - mInflater = inflater; - mContainer = container; - View view = mInflater.inflate(R.layout.chat_imdn_old, container, false); - - mBackButton = view.findViewById(R.id.back); - mBackButton.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View view) { - if (LinphoneActivity.instance().isTablet()) { - LinphoneActivity.instance().goToChat(mLocalSipUri, mRoomUri, null); - } else { - LinphoneActivity.instance().onBackPressed(); - } - } - }); - - mRead = view.findViewById(R.id.read_layout); - mDelivered = view.findViewById(R.id.delivered_layout); - mSent = view.findViewById(R.id.sent_layout); - mUndelivered = view.findViewById(R.id.undelivered_layout); - mReadHeader = view.findViewById(R.id.read_layout_header); - mDeliveredHeader = view.findViewById(R.id.delivered_layout_header); - mSentHeader = view.findViewById(R.id.sent_layout_header); - mUndeliveredHeader = view.findViewById(R.id.undelivered_layout_header); - - mBubble = new ChatMessageOldViewHolder(view.findViewById(R.id.bubble)); - mBubble.eventLayout.setVisibility(View.GONE); - mBubble.bubbleLayout.setVisibility(View.VISIBLE); - mBubble.delete.setVisibility(View.GONE); - mBubble.messageText.setVisibility(View.GONE); - mBubble.messageImage.setVisibility(View.GONE); - mBubble.fileTransferLayout.setVisibility(View.GONE); - mBubble.fileName.setVisibility(View.GONE); - mBubble.openFileButton.setVisibility(View.GONE); - mBubble.messageStatus.setVisibility(View.INVISIBLE); - mBubble.messageSendingInProgress.setVisibility(View.GONE); - mBubble.imdmLayout.setVisibility(View.INVISIBLE); - - mMessage = mRoom.findMessage(mMessageId); - mListener = - new ChatMessageListenerStub() { - @Override - public void onParticipantImdnStateChanged( - ChatMessage msg, ParticipantImdnState state) { - refreshInfo(); - } - }; - if (mMessage == null) return null; - - RelativeLayout.LayoutParams layoutParams = - new RelativeLayout.LayoutParams( - RelativeLayout.LayoutParams.WRAP_CONTENT, - RelativeLayout.LayoutParams.WRAP_CONTENT); - layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); - layoutParams.setMargins(100, 10, 10, 10); - if (mMessage.isOutgoing()) { - mBubble.background.setBackgroundResource(R.drawable.resizable_chat_bubble_outgoing); - Compatibility.setTextAppearance(mBubble.contactName, getActivity(), R.style.font3); - Compatibility.setTextAppearance( - mBubble.fileTransferAction, getActivity(), R.style.font15); - mBubble.fileTransferAction.setBackgroundResource( - R.drawable.resizable_confirm_delete_button); - } else { - mBubble.background.setBackgroundResource(R.drawable.resizable_chat_bubble_incoming); - Compatibility.setTextAppearance( - mBubble.contactName, getActivity(), R.style.contact_organization_font); - Compatibility.setTextAppearance( - mBubble.fileTransferAction, getActivity(), R.style.button_font); - mBubble.fileTransferAction.setBackgroundResource(R.drawable.resizable_assistant_button); - } - - return view; - } - - @Override - public void onResume() { - super.onResume(); - - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.MESSAGE_IMDN); - } - if (mMessage != null) { - mMessage.addListener(mListener); - } - - refreshInfo(); - } - - @Override - public void onPause() { - if (mMessage != null) { - mMessage.removeListener(mListener); - } - - super.onPause(); - } - - private void refreshInfo() { - Address remoteSender = mMessage.getFromAddress(); - LinphoneContact contact = - ContactsManager.getInstance().findContactFromAddress(remoteSender); - String displayName; - - if (contact != null) { - if (contact.getFullName() != null) { - displayName = contact.getFullName(); - } else { - displayName = LinphoneUtils.getAddressDisplayName(remoteSender); - } - - ContactAvatar.displayAvatar(contact, mBubble.avatarLayout); - } else { - displayName = LinphoneUtils.getAddressDisplayName(remoteSender); - ContactAvatar.displayAvatar(displayName, mBubble.avatarLayout); - } - mBubble.contactName.setText( - LinphoneUtils.timestampToHumanDate( - getActivity(), mMessage.getTime(), R.string.messages_date_format) - + " - " - + displayName); - - if (mMessage.hasTextContent()) { - String msg = mMessage.getTextContent(); - Spanned text = LinphoneUtils.getTextWithHttpLinks(msg); - mBubble.messageText.setText(text); - mBubble.messageText.setMovementMethod(LinkMovementMethod.getInstance()); - mBubble.messageText.setVisibility(View.VISIBLE); - } - - String appData = mMessage.getAppdata(); - if (appData != null) { // Something to display - mBubble.fileName.setVisibility(View.VISIBLE); - mBubble.fileName.setText(FileUtils.getNameFromFilePath(appData)); - // We purposely chose not to display the image - } - - mRead.removeAllViews(); - mDelivered.removeAllViews(); - mSent.removeAllViews(); - mUndelivered.removeAllViews(); - - ParticipantImdnState[] participants = - mMessage.getParticipantsByImdnState(ChatMessage.State.Displayed); - mReadHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE); - boolean first = true; - for (ParticipantImdnState participant : participants) { - Address address = participant.getParticipant().getAddress(); - - LinphoneContact participantContact = - ContactsManager.getInstance().findContactFromAddress(address); - String participantDisplayName = - participantContact != null - ? participantContact.getFullName() - : LinphoneUtils.getAddressDisplayName(address); - - View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false); - v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE); - ((TextView) v.findViewById(R.id.time)) - .setText( - LinphoneUtils.timestampToHumanDate( - getActivity(), - participant.getStateChangeTime(), - R.string.messages_date_format)); - ((TextView) v.findViewById(R.id.name)).setText(participantDisplayName); - if (participantContact != null) { - ContactAvatar.displayAvatar(participantContact, v.findViewById(R.id.avatar_layout)); - } else { - ContactAvatar.displayAvatar( - participantDisplayName, v.findViewById(R.id.avatar_layout)); - } - - mRead.addView(v); - first = false; - } - - participants = mMessage.getParticipantsByImdnState(ChatMessage.State.DeliveredToUser); - mDeliveredHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE); - first = true; - for (ParticipantImdnState participant : participants) { - Address address = participant.getParticipant().getAddress(); - - LinphoneContact participantContact = - ContactsManager.getInstance().findContactFromAddress(address); - String participantDisplayName = - participantContact != null - ? participantContact.getFullName() - : LinphoneUtils.getAddressDisplayName(address); - - View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false); - v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE); - ((TextView) v.findViewById(R.id.time)) - .setText( - LinphoneUtils.timestampToHumanDate( - getActivity(), - participant.getStateChangeTime(), - R.string.messages_date_format)); - ((TextView) v.findViewById(R.id.name)).setText(participantDisplayName); - if (participantContact != null) { - ContactAvatar.displayAvatar(participantContact, v.findViewById(R.id.avatar_layout)); - } else { - ContactAvatar.displayAvatar( - participantDisplayName, v.findViewById(R.id.avatar_layout)); - } - - mDelivered.addView(v); - first = false; - } - - participants = mMessage.getParticipantsByImdnState(ChatMessage.State.Delivered); - mSentHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE); - first = true; - for (ParticipantImdnState participant : participants) { - Address address = participant.getParticipant().getAddress(); - - LinphoneContact participantContact = - ContactsManager.getInstance().findContactFromAddress(address); - String participantDisplayName = - participantContact != null - ? participantContact.getFullName() - : LinphoneUtils.getAddressDisplayName(address); - - View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false); - v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE); - ((TextView) v.findViewById(R.id.time)) - .setText( - LinphoneUtils.timestampToHumanDate( - getActivity(), - participant.getStateChangeTime(), - R.string.messages_date_format)); - ((TextView) v.findViewById(R.id.name)).setText(participantDisplayName); - if (participantContact != null) { - ContactAvatar.displayAvatar(participantContact, v.findViewById(R.id.avatar_layout)); - } else { - ContactAvatar.displayAvatar( - participantDisplayName, v.findViewById(R.id.avatar_layout)); - } - - mSent.addView(v); - first = false; - } - - participants = mMessage.getParticipantsByImdnState(ChatMessage.State.NotDelivered); - mUndeliveredHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE); - first = true; - for (ParticipantImdnState participant : participants) { - Address address = participant.getParticipant().getAddress(); - - LinphoneContact participantContact = - ContactsManager.getInstance().findContactFromAddress(address); - String participantDisplayName = - participantContact != null - ? participantContact.getFullName() - : LinphoneUtils.getAddressDisplayName(address); - - View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false); - v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE); - ((TextView) v.findViewById(R.id.name)).setText(participantDisplayName); - if (participantContact != null) { - ContactAvatar.displayAvatar(participantContact, v.findViewById(R.id.avatar_layout)); - } else { - ContactAvatar.displayAvatar( - participantDisplayName, v.findViewById(R.id.avatar_layout)); - } - - mUndelivered.addView(v); - first = false; - } - } -} diff --git a/app/src/main/java/org/linphone/compatibility/ApiTwentyFourPlus.java b/app/src/main/java/org/linphone/compatibility/ApiTwentyFourPlus.java index a3e7995e9..7d4c3ddd0 100644 --- a/app/src/main/java/org/linphone/compatibility/ApiTwentyFourPlus.java +++ b/app/src/main/java/org/linphone/compatibility/ApiTwentyFourPlus.java @@ -141,15 +141,13 @@ class ApiTwentyFourPlus { replyIntent, PendingIntent.FLAG_UPDATE_CURRENT); - Notification.Action replyAction = - new Notification.Action.Builder( - R.drawable.chat_send_over, - context.getString(R.string.notification_reply_label), - replyPendingIntent) - .addRemoteInput(remoteInput) - .setAllowGeneratedReplies(true) - .build(); - return replyAction; + return new Notification.Action.Builder( + R.drawable.chat_send_over, + context.getString(R.string.notification_reply_label), + replyPendingIntent) + .addRemoteInput(remoteInput) + .setAllowGeneratedReplies(true) + .build(); } public static Notification.Action getMarkMessageAsReadAction( @@ -166,14 +164,11 @@ class ApiTwentyFourPlus { markAsReadIntent, PendingIntent.FLAG_UPDATE_CURRENT); - Notification.Action markAsReadAction = - new Notification.Action.Builder( - R.drawable.chat_send_over, - context.getString(R.string.notification_mark_as_read_label), - markAsReadPendingIntent) - .build(); - - return markAsReadAction; + return new Notification.Action.Builder( + R.drawable.chat_send_over, + context.getString(R.string.notification_mark_as_read_label), + markAsReadPendingIntent) + .build(); } public static Notification.Action getCallAnswerAction(Context context, int callId) { @@ -185,14 +180,11 @@ class ApiTwentyFourPlus { PendingIntent.getBroadcast( context, callId, answerIntent, PendingIntent.FLAG_UPDATE_CURRENT); - Notification.Action answerAction = - new Notification.Action.Builder( - R.drawable.call_audio_start, - context.getString(R.string.notification_call_answer_label), - answerPendingIntent) - .build(); - - return answerAction; + return new Notification.Action.Builder( + R.drawable.call_audio_start, + context.getString(R.string.notification_call_answer_label), + answerPendingIntent) + .build(); } public static Notification.Action getCallDeclineAction(Context context, int callId) { @@ -204,13 +196,11 @@ class ApiTwentyFourPlus { PendingIntent.getBroadcast( context, callId, hangupIntent, PendingIntent.FLAG_UPDATE_CURRENT); - Notification.Action declineAction = - new Notification.Action.Builder( - R.drawable.call_hangup, - context.getString(R.string.notification_call_hangup_label), - hangupPendingIntent) - .build(); - return declineAction; + return new Notification.Action.Builder( + R.drawable.call_hangup, + context.getString(R.string.notification_call_hangup_label), + hangupPendingIntent) + .build(); } public static void closeContentProviderClient(ContentProviderClient client) { diff --git a/app/src/main/java/org/linphone/compatibility/ApiTwentyOnePlus.java b/app/src/main/java/org/linphone/compatibility/ApiTwentyOnePlus.java index e84eab1ca..b2f69f064 100644 --- a/app/src/main/java/org/linphone/compatibility/ApiTwentyOnePlus.java +++ b/app/src/main/java/org/linphone/compatibility/ApiTwentyOnePlus.java @@ -33,7 +33,6 @@ import org.linphone.R; @TargetApi(21) class ApiTwentyOnePlus { - @SuppressWarnings("deprecation") public static Notification createMessageNotification( Context context, int msgCount, diff --git a/app/src/main/java/org/linphone/compatibility/ApiTwentyThreePlus.java b/app/src/main/java/org/linphone/compatibility/ApiTwentyThreePlus.java index e960b810e..5482724a2 100644 --- a/app/src/main/java/org/linphone/compatibility/ApiTwentyThreePlus.java +++ b/app/src/main/java/org/linphone/compatibility/ApiTwentyThreePlus.java @@ -22,13 +22,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import android.annotation.TargetApi; import android.content.Context; import android.os.PowerManager; -import android.widget.TextView; @TargetApi(23) class ApiTwentyThreePlus { - public static void setTextAppearance(TextView textview, int style) { - textview.setTextAppearance(style); - } public static boolean isAppIdleMode(Context context) { return ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).isDeviceIdleMode(); diff --git a/app/src/main/java/org/linphone/compatibility/Compatibility.java b/app/src/main/java/org/linphone/compatibility/Compatibility.java index f969935b1..28fd0fbff 100644 --- a/app/src/main/java/org/linphone/compatibility/Compatibility.java +++ b/app/src/main/java/org/linphone/compatibility/Compatibility.java @@ -29,7 +29,6 @@ import android.content.Intent; import android.graphics.Bitmap; import android.os.Build; import android.provider.Settings; -import android.widget.TextView; import org.linphone.mediastream.Version; import org.linphone.notifications.Notifiable; @@ -167,14 +166,6 @@ public class Compatibility { return true; } - public static void setTextAppearance(TextView textview, Context context, int style) { - if (Version.sdkAboveOrEqual(Version.API23_MARSHMALLOW_60)) { - ApiTwentyThreePlus.setTextAppearance(textview, style); - } else { - textview.setTextAppearance(context, style); - } - } - public static void startService(Context context, Intent intent) { if (Version.sdkAboveOrEqual(Version.API26_O_80)) { ApiTwentySixPlus.startService(context, intent); diff --git a/app/src/main/java/org/linphone/compatibility/CompatibilityScaleGestureDetector.java b/app/src/main/java/org/linphone/compatibility/CompatibilityScaleGestureDetector.java index 14bdcef30..bcb51dd23 100644 --- a/app/src/main/java/org/linphone/compatibility/CompatibilityScaleGestureDetector.java +++ b/app/src/main/java/org/linphone/compatibility/CompatibilityScaleGestureDetector.java @@ -36,8 +36,8 @@ public class CompatibilityScaleGestureDetector listener = newListener; } - public boolean onTouchEvent(MotionEvent event) { - return detector.onTouchEvent(event); + public void onTouchEvent(MotionEvent event) { + detector.onTouchEvent(event); } @Override diff --git a/app/src/main/java/org/linphone/contacts/AndroidContact.java b/app/src/main/java/org/linphone/contacts/AndroidContact.java index e3e8a1601..f01b28de3 100644 --- a/app/src/main/java/org/linphone/contacts/AndroidContact.java +++ b/app/src/main/java/org/linphone/contacts/AndroidContact.java @@ -32,53 +32,40 @@ import android.provider.ContactsContract.Data; import android.provider.ContactsContract.RawContacts; import java.io.Serializable; import java.util.ArrayList; -import org.linphone.LinphoneManager; import org.linphone.LinphoneService; import org.linphone.R; import org.linphone.core.tools.Log; class AndroidContact implements Serializable { - protected String mAndroidId, mAndroidRawId, mAndroidLookupKey; - protected boolean isAndroidRawIdLinphone; + String mAndroidId; + private String mAndroidRawId; + private boolean isAndroidRawIdLinphone; - private transient ArrayList mChangesToCommit; + private final transient ArrayList mChangesToCommit; - protected AndroidContact() { + AndroidContact() { mChangesToCommit = new ArrayList<>(); isAndroidRawIdLinphone = false; } - protected String getAndroidId() { + String getAndroidId() { return mAndroidId; } - protected void setAndroidId(String id) { + void setAndroidId(String id) { mAndroidId = id; } - protected String getAndroidLookupKey() { - return mAndroidLookupKey; - } - - protected void setAndroidLookupKey(String lookupKey) { - mAndroidLookupKey = lookupKey; - } - - protected Uri getAndroidLookupUri() { - return ContactsContract.Contacts.getLookupUri( - Long.parseLong(mAndroidId), getAndroidLookupKey()); - } - - protected boolean isAndroidContact() { + boolean isAndroidContact() { return mAndroidId != null; } - protected void addChangesToCommit(ContentProviderOperation operation) { + private void addChangesToCommit(ContentProviderOperation operation) { Log.i("[Contact] Added operation " + operation); mChangesToCommit.add(operation); } - protected void saveChangesCommited() { + void saveChangesCommited() { if (ContactsManager.getInstance().hasReadContactsAccess() && mChangesToCommit.size() > 0) { try { ContentResolver contentResolver = LinphoneService.instance().getContentResolver(); @@ -123,11 +110,8 @@ class AndroidContact implements Serializable { } } - protected void createAndroidContact() { - if (LinphoneManager.getInstance() - .getContext() - .getResources() - .getBoolean(R.bool.use_linphone_tag)) { + void createAndroidContact() { + if (LinphoneService.instance().getResources().getBoolean(R.bool.use_linphone_tag)) { Log.i("[Contact] Creating contact using linphone account type"); addChangesToCommit( ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) @@ -157,21 +141,21 @@ class AndroidContact implements Serializable { } } - protected void deleteAndroidContact() { + void deleteAndroidContact() { ContactsManager.getInstance().delete(mAndroidId); } - protected Uri getContactThumbnailPictureUri() { + Uri getContactThumbnailPictureUri() { Uri person = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(mAndroidId)); return Uri.withAppendedPath(person, Contacts.Photo.CONTENT_DIRECTORY); } - protected Uri getContactPictureUri() { + Uri getContactPictureUri() { Uri person = ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(mAndroidId)); return Uri.withAppendedPath(person, Contacts.Photo.DISPLAY_PHOTO); } - protected void setName(String fn, String ln) { + void setName(String fn, String ln) { if ((fn == null || fn.isEmpty()) && (ln == null || ln.isEmpty())) { Log.e("[Contact] Can't set both first and last name to null or empty"); return; @@ -224,7 +208,7 @@ class AndroidContact implements Serializable { } } - protected void addNumberOrAddress(String value, String oldValueToReplace, boolean isSIP) { + void addNumberOrAddress(String value, String oldValueToReplace, boolean isSIP) { if (value == null || value.isEmpty()) { Log.e("[Contact] Can't add null or empty number or address"); return; @@ -373,7 +357,7 @@ class AndroidContact implements Serializable { } } - protected void removeNumberOrAddress(String noa, boolean isSIP) { + void removeNumberOrAddress(String noa, boolean isSIP) { if (noa == null || noa.isEmpty()) { Log.e("[Contact] Can't remove null or empty number or address."); return; @@ -381,7 +365,6 @@ class AndroidContact implements Serializable { if (mAndroidId == null) { Log.e("[Contact] Can't remove a number or address from non existing contact"); - return; } else { Log.i( "[Contact] Removing number or address " @@ -433,7 +416,7 @@ class AndroidContact implements Serializable { } } - protected void setOrganization(String org, String previousValue) { + void setOrganization(String org, String previousValue) { if (org == null || org.isEmpty()) { if (mAndroidId == null) { Log.e("[Contact] Can't set organization to null or empty for new contact"); @@ -506,7 +489,7 @@ class AndroidContact implements Serializable { } } - protected void setPhoto(byte[] photo) { + void setPhoto(byte[] photo) { if (photo == null) { Log.e("[Contact] Can't set null picture."); return; @@ -542,7 +525,7 @@ class AndroidContact implements Serializable { } } - protected String findRawContactID() { + private String findRawContactID() { ContentResolver resolver = LinphoneService.instance().getContentResolver(); String result = null; String[] projection = {ContactsContract.RawContacts._ID}; @@ -564,11 +547,8 @@ class AndroidContact implements Serializable { return result; } - protected void createRawLinphoneContactFromExistingAndroidContactIfNeeded(String fullName) { - if (LinphoneManager.getInstance() - .getContext() - .getResources() - .getBoolean(R.bool.use_linphone_tag)) { + void createRawLinphoneContactFromExistingAndroidContactIfNeeded() { + if (LinphoneService.instance().getResources().getBoolean(R.bool.use_linphone_tag)) { if (mAndroidId != null && (mAndroidRawId == null || !isAndroidRawIdLinphone)) { if (mAndroidRawId == null) { Log.i("[Contact] RAW ID not found for contact " + mAndroidId); diff --git a/app/src/main/java/org/linphone/contacts/AsyncContactsLoader.java b/app/src/main/java/org/linphone/contacts/AsyncContactsLoader.java index c74feddf8..9b77d0f06 100644 --- a/app/src/main/java/org/linphone/contacts/AsyncContactsLoader.java +++ b/app/src/main/java/org/linphone/contacts/AsyncContactsLoader.java @@ -53,25 +53,18 @@ class AsyncContactsLoader extends AsyncTask nativeIds = new ArrayList<>(); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - for (FriendList list : lc.getFriendsLists()) { + Core core = LinphoneManager.getCore(); + if (core != null) { + for (FriendList list : core.getFriendsLists()) { for (Friend friend : list.getFriends()) { if (isCancelled()) return data; @@ -139,7 +133,6 @@ class AsyncContactsLoader extends AsyncTask(); - mSipAddresses = initSipAddressFields(mContact); - mNumbers = initNumbersFields(mContact); - mAddSipAddress = mView.findViewById(R.id.add_address_field); + ImageView addSipAddress = mView.findViewById(R.id.add_address_field); if (getResources().getBoolean(R.bool.allow_only_one_sip_address)) { - mAddSipAddress.setVisibility(View.GONE); + addSipAddress.setVisibility(View.GONE); } - mAddSipAddress.setOnClickListener( + addSipAddress.setOnClickListener( new OnClickListener() { @Override public void onClick(View view) { @@ -345,11 +323,11 @@ public class ContactEditorFragment extends Fragment { } }); - mAddNumber = mView.findViewById(R.id.add_number_field); + ImageView addNumber = mView.findViewById(R.id.add_number_field); if (getResources().getBoolean(R.bool.allow_only_one_phone_number)) { - mAddNumber.setVisibility(View.GONE); + addNumber.setVisibility(View.GONE); } - mAddNumber.setOnClickListener( + addNumber.setOnClickListener( new OnClickListener() { @Override public void onClick(View view) { @@ -362,10 +340,20 @@ public class ContactEditorFragment extends Fragment { return mView; } + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putSerializable("Contact", mContact); + outState.putString("SipUri", mNewSipOrNumberToAdd); + outState.putString("DisplayName", mNewDisplayName); + } + @Override public void onResume() { super.onResume(); + displayContact(); + // Force hide keyboard getActivity() .getWindow() @@ -387,13 +375,71 @@ public class ContactEditorFragment extends Fragment { super.onPause(); } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == ADD_PHOTO && resultCode == Activity.RESULT_OK) { + if (data != null && data.getExtras() != null && data.getExtras().get("data") != null) { + Bitmap bm = (Bitmap) data.getExtras().get("data"); + editContactPicture(null, bm); + } else if (data != null && data.getData() != null) { + Uri selectedImageUri = data.getData(); + try { + Bitmap selectedImage = + MediaStore.Images.Media.getBitmap( + getActivity().getContentResolver(), selectedImageUri); + selectedImage = + Bitmap.createScaledBitmap(selectedImage, PHOTO_SIZE, PHOTO_SIZE, false); + editContactPicture(null, selectedImage); + } catch (IOException e) { + Log.e(e); + } + } else if (mPickedPhotoForContactUri != null) { + String filePath = mPickedPhotoForContactUri.getPath(); + editContactPicture(filePath, null); + } else { + File file = + new File( + FileUtils.getStorageDirectory(getActivity()), + getString(R.string.temp_photo_name)); + if (file.exists()) { + mPickedPhotoForContactUri = Uri.fromFile(file); + String filePath = mPickedPhotoForContactUri.getPath(); + editContactPicture(filePath, null); + } + } + } else { + super.onActivityResult(requestCode, resultCode, data); + } + } + + private void displayContact() { + boolean isOrgVisible = getResources().getBoolean(R.bool.display_contact_organization); + if (!isOrgVisible) { + mOrganization.setVisibility(View.GONE); + mView.findViewById(R.id.contactOrganizationTitle).setVisibility(View.GONE); + } else { + if (!mIsNewContact) { + mOrganization.setText(mContact.getOrganization()); + } + } + + if (mContact != null) { + ContactAvatar.displayAvatar(mContact, mView.findViewById(R.id.avatar_layout)); + } else { + ContactAvatar.displayAvatar("", mView.findViewById(R.id.avatar_layout)); + } + + mSipAddresses = initSipAddressFields(mContact); + mNumbers = initNumbersFields(mContact); + } + private void pickImage() { mPickedPhotoForContactUri = null; final List cameraIntents = new ArrayList<>(); final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File file = new File( - FileUtils.getStorageDirectory(LinphoneActivity.instance()), + FileUtils.getStorageDirectory(getActivity()), getString(R.string.temp_photo_name)); mPickedPhotoForContactUri = Uri.fromFile(file); captureIntent.putExtra("outputX", PHOTO_SIZE); @@ -417,44 +463,6 @@ public class ContactEditorFragment extends Fragment { startActivityForResult(chooserIntent, ADD_PHOTO); } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == ADD_PHOTO && resultCode == Activity.RESULT_OK) { - if (data != null && data.getExtras() != null && data.getExtras().get("data") != null) { - Bitmap bm = (Bitmap) data.getExtras().get("data"); - editContactPicture(null, bm); - } else if (data != null && data.getData() != null) { - Uri selectedImageUri = data.getData(); - try { - Bitmap selectedImage = - MediaStore.Images.Media.getBitmap( - LinphoneManager.getInstance().getContext().getContentResolver(), - selectedImageUri); - selectedImage = - Bitmap.createScaledBitmap(selectedImage, PHOTO_SIZE, PHOTO_SIZE, false); - editContactPicture(null, selectedImage); - } catch (IOException e) { - Log.e(e); - } - } else if (mPickedPhotoForContactUri != null) { - String filePath = mPickedPhotoForContactUri.getPath(); - editContactPicture(filePath, null); - } else { - File file = - new File( - FileUtils.getStorageDirectory(LinphoneActivity.instance()), - getString(R.string.temp_photo_name)); - if (file.exists()) { - mPickedPhotoForContactUri = Uri.fromFile(file); - String filePath = mPickedPhotoForContactUri.getPath(); - editContactPicture(filePath, null); - } - } - } else { - super.onActivityResult(requestCode, resultCode, data); - } - } - private void editContactPicture(String filePath, Bitmap image) { if (image == null) { image = BitmapFactory.decodeFile(filePath); @@ -478,7 +486,7 @@ public class ContactEditorFragment extends Fragment { private int getThumbnailSize() { int value = -1; Cursor c = - LinphoneActivity.instance() + getActivity() .getContentResolver() .query( DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI, diff --git a/app/src/main/java/org/linphone/contacts/ContactsActivity.java b/app/src/main/java/org/linphone/contacts/ContactsActivity.java new file mode 100644 index 000000000..4d4dd6fcf --- /dev/null +++ b/app/src/main/java/org/linphone/contacts/ContactsActivity.java @@ -0,0 +1,180 @@ +package org.linphone.contacts; + +/* +ContactsActivity.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.Manifest; +import android.app.Fragment; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Toast; +import org.linphone.R; +import org.linphone.activities.MainActivity; + +public class ContactsActivity extends MainActivity { + private boolean mEditOnClick; + private String mEditSipUri, mEditDisplayName; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mPermissionsToHave = + new String[] { + Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS + }; + } + + @Override + protected void onStart() { + super.onStart(); + + Fragment currentFragment = getFragmentManager().findFragmentById(R.id.fragmentContainer); + if (currentFragment == null) { + if (getIntent() != null && getIntent().getExtras() != null) { + Bundle extras = getIntent().getExtras(); + if (isTablet() || !extras.containsKey("Contact")) { + showContactsList(); + } + handleIntentExtras(extras); + } else { + showContactsList(); + if (isTablet()) { + showEmptyChildFragment(); + } + } + } + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + // Clean fragments stack upon return + while (getFragmentManager().getBackStackEntryCount() > 0) { + getFragmentManager().popBackStackImmediate(); + } + + handleIntentExtras(intent.getExtras()); + } + + @Override + protected void onResume() { + super.onResume(); + + mContactsSelected.setVisibility(View.VISIBLE); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString("EditSipUri", mEditSipUri); + outState.putString("EditDisplayName", mEditDisplayName); + outState.putBoolean("EditOnClick", mEditOnClick); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + mEditOnClick = savedInstanceState.getBoolean("EditOnClick", false); + mEditSipUri = savedInstanceState.getString("EditSipUri", null); + mEditDisplayName = savedInstanceState.getString("EditDisplayName", null); + } + + @Override + public void goBack() { + // 1 is for the empty fragment on tablets + if (!isTablet() || getFragmentManager().getBackStackEntryCount() > 1) { + if (popBackStack()) { + mEditOnClick = false; + return; + } + } + super.goBack(); + } + + private void handleIntentExtras(Bundle extras) { + if (extras == null) return; + + if (extras.containsKey("Contact")) { + LinphoneContact contact = (LinphoneContact) extras.get("Contact"); + if (extras.containsKey("Edit")) { + showContactEdit(contact, extras, false); + } else { + showContactDetails(contact, false); + } + } else if (extras.containsKey("CreateOrEdit")) { + mEditOnClick = extras.getBoolean("CreateOrEdit"); + mEditSipUri = extras.getString("SipUri", null); + mEditDisplayName = extras.getString("DisplayName", null); + + Toast.makeText(this, R.string.toast_choose_contact_for_edition, Toast.LENGTH_LONG) + .show(); + } + } + + public void showContactDetails(LinphoneContact contact) { + showContactDetails(contact, true); + } + + public void showContactEdit(LinphoneContact contact) { + showContactEdit(contact, true); + } + + private void showContactsList() { + ContactsFragment fragment = new ContactsFragment(); + changeFragment(fragment, "Contacts", false); + } + + private void showContactDetails(LinphoneContact contact, boolean isChild) { + if (mEditOnClick) { + showContactEdit(contact, isChild); + return; + } + + Bundle extras = new Bundle(); + if (contact != null) { + extras.putSerializable("Contact", contact); + } + ContactDetailsFragment fragment = new ContactDetailsFragment(); + fragment.setArguments(extras); + changeFragment(fragment, "Contact detail", isChild); + } + + private void showContactEdit(LinphoneContact contact, boolean isChild) { + showContactEdit(contact, new Bundle(), isChild); + } + + private void showContactEdit(LinphoneContact contact, Bundle extras, boolean isChild) { + if (contact != null) { + extras.putSerializable("Contact", contact); + } + if (mEditOnClick) { + mEditOnClick = false; + extras.putString("SipUri", mEditSipUri); + extras.putString("DisplayName", mEditDisplayName); + mEditSipUri = null; + mEditDisplayName = null; + } + ContactEditorFragment fragment = new ContactEditorFragment(); + fragment.setArguments(extras); + changeFragment(fragment, "Contact editor", isChild); + } +} diff --git a/app/src/main/java/org/linphone/contacts/ContactsAdapter.java b/app/src/main/java/org/linphone/contacts/ContactsAdapter.java index 87a9b5329..3183415d0 100644 --- a/app/src/main/java/org/linphone/contacts/ContactsAdapter.java +++ b/app/src/main/java/org/linphone/contacts/ContactsAdapter.java @@ -79,9 +79,8 @@ public class ContactsAdapter extends SelectableAdapter } holder.separator.setVisibility( mIsSearchMode - || (!mIsSearchMode - && getPositionForSection(getSectionForPosition(position)) - != position) + || (getPositionForSection(getSectionForPosition(position)) + != position) ? View.GONE : View.VISIBLE); holder.linphoneFriend.setVisibility(contact.isInFriendList() ? View.VISIBLE : View.GONE); diff --git a/app/src/main/java/org/linphone/contacts/ContactsFragment.java b/app/src/main/java/org/linphone/contacts/ContactsFragment.java index c73c2439b..18d36d86f 100644 --- a/app/src/main/java/org/linphone/contacts/ContactsFragment.java +++ b/app/src/main/java/org/linphone/contacts/ContactsFragment.java @@ -31,17 +31,14 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.SearchView; import android.widget.TextView; -import android.widget.Toast; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import java.util.ArrayList; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.utils.SelectableHelper; public class ContactsFragment extends Fragment @@ -51,12 +48,11 @@ public class ContactsFragment extends Fragment SelectableHelper.DeleteListener { private RecyclerView mContactsList; private TextView mNoSipContact, mNoContact; - private ImageView mAllContacts, mLinphoneContacts, mNewContact; + private ImageView mAllContacts; + private ImageView mLinphoneContacts; private boolean mOnlyDisplayLinphoneContacts; private View mAllContactsSelected, mLinphoneContactsSelected; private int mLastKnownPosition; - private boolean mEditOnClick = false, mEditConsumed = false, mOnlyDisplayChatAddress = false; - private String mSipAddressToAdd, mDisplayName = null; private SearchView mSearchView; private ProgressBar mContactsFetchInProgress; private LinearLayoutManager mLayoutManager; @@ -73,24 +69,6 @@ public class ContactsFragment extends Fragment mSelectionHelper = new SelectableHelper(view, this); mSelectionHelper.setDialogMessage(R.string.delete_contacts_text); - if (getArguments() != null) { - mEditOnClick = getArguments().getBoolean("EditOnClick"); - mSipAddressToAdd = getArguments().getString("SipAddress"); - if (getArguments().getString("DisplayName") != null) { - mDisplayName = getArguments().getString("DisplayName"); - } - mOnlyDisplayChatAddress = getArguments().getBoolean("ChatAddressOnly"); - - if (getArguments().getBoolean("EditOnClick")) { - Toast.makeText( - LinphoneActivity.instance(), - R.string.toast_choose_contact_for_edition, - Toast.LENGTH_LONG) - .show(); - } - getArguments().clear(); - } - mNoSipContact = view.findViewById(R.id.noSipContact); mNoContact = view.findViewById(R.id.noContact); mContactsList = view.findViewById(R.id.contactsList); @@ -100,7 +78,7 @@ public class ContactsFragment extends Fragment mAllContactsSelected = view.findViewById(R.id.all_contacts_select); mLinphoneContactsSelected = view.findViewById(R.id.linphone_contacts_select); mContactsFetchInProgress = view.findViewById(R.id.contactsFetchInProgress); - mNewContact = view.findViewById(R.id.newContact); + ImageView newContact = view.findViewById(R.id.newContact); mContactsRefresher = view.findViewById(R.id.contactsListRefresher); mContactsRefresher.setOnRefreshListener( @@ -137,13 +115,11 @@ public class ContactsFragment extends Fragment } }); - mNewContact.setOnClickListener( + newContact.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { - mEditConsumed = true; - ContactsManager.getInstance() - .createContact(getActivity(), mDisplayName, mSipAddressToAdd); + ((ContactsActivity) getActivity()).showContactEdit(null); } }); @@ -159,13 +135,11 @@ public class ContactsFragment extends Fragment mAllContacts.setEnabled(mOnlyDisplayLinphoneContacts); mLinphoneContacts.setEnabled(!mAllContacts.isEnabled()); } - mNewContact.setEnabled(LinphoneManager.getLc().getCallsNb() == 0); + newContact.setEnabled(LinphoneManager.getCore().getCallsNb() == 0); if (!ContactsManager.getInstance().contactsFetchedOnce()) { if (ContactsManager.getInstance().hasReadContactsAccess()) { mContactsFetchInProgress.setVisibility(View.VISIBLE); - } else { - LinphoneActivity.instance().checkAndRequestReadContactsPermission(); } } else { if (!mOnlyDisplayLinphoneContacts @@ -205,17 +179,92 @@ public class ContactsFragment extends Fragment return view; } - public void displayFirstContact() { - if (mContactsList != null - && mContactsList.getAdapter() != null - && mContactsList.getAdapter().getItemCount() > 0) { - ContactsAdapter mAdapt = (ContactsAdapter) mContactsList.getAdapter(); - LinphoneActivity.instance().displayContact((LinphoneContact) mAdapt.getItem(0), false); + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + } + + @Override + public void onItemClick(AdapterView adapter, View view, int position, long id) { + LinphoneContact contact = (LinphoneContact) adapter.getItemAtPosition(position); + mLastKnownPosition = mLayoutManager.findFirstVisibleItemPosition(); + ((ContactsActivity) getActivity()).showContactDetails(contact); + } + + @Override + public void onItemClicked(int position) { + LinphoneContact contact = (LinphoneContact) mContactAdapter.getItem(position); + + if (mContactAdapter.isEditionEnabled()) { + mContactAdapter.toggleSelection(position); } else { - LinphoneActivity.instance().displayEmptyFragment(); + mLastKnownPosition = mLayoutManager.findFirstVisibleItemPosition(); + ((ContactsActivity) getActivity()).showContactDetails(contact); } } + @Override + public boolean onItemLongClicked(int position) { + if (!mContactAdapter.isEditionEnabled()) { + mSelectionHelper.enterEditionMode(); + } + mContactAdapter.toggleSelection(position); + return true; + } + + @Override + public void onResume() { + super.onResume(); + ContactsManager.getInstance().addContactsListener(this); + + mOnlyDisplayLinphoneContacts = + ContactsManager.getInstance().isLinphoneContactsPrefered() + || getResources().getBoolean(R.bool.hide_non_linphone_contacts); + + changeContactsToggle(); + invalidate(); + } + + @Override + public void onPause() { + ContactsManager.getInstance().removeContactsListener(this); + super.onPause(); + } + + @Override + public void onContactsUpdated() { + if (mContactAdapter != null) { + mContactAdapter.updateDataSet( + mOnlyDisplayLinphoneContacts + ? ContactsManager.getInstance().getSIPContacts() + : ContactsManager.getInstance().getContacts()); + mContactAdapter.notifyDataSetChanged(); + + if (mContactAdapter.getItemCount() > 0) { + mNoContact.setVisibility(View.GONE); + mNoSipContact.setVisibility(View.GONE); + } + } + mContactsFetchInProgress.setVisibility(View.GONE); + mContactsRefresher.setRefreshing(false); + } + + @Override + public void onDeleteSelection(Object[] objectsToDelete) { + ArrayList ids = new ArrayList<>(); + int size = mContactAdapter.getSelectedItemCount(); + for (int i = size - 1; i >= 0; i--) { + LinphoneContact contact = (LinphoneContact) objectsToDelete[i]; + if (contact.isAndroidContact()) { + contact.deleteFriend(); + ids.add(contact.getAndroidId()); + } else { + contact.delete(); + } + } + ContactsManager.getInstance().deleteMultipleContactsAtOnce(ids); + } + private void searchContacts(String search) { boolean isEditionEnabled = false; if (search == null || search.length() == 0) { @@ -306,91 +355,6 @@ public class ContactsFragment extends Fragment } } - @Override - public void onItemClick(AdapterView adapter, View view, int position, long id) { - LinphoneContact contact = (LinphoneContact) adapter.getItemAtPosition(position); - if (mEditOnClick) { - mEditConsumed = true; - ContactsManager.getInstance().editContact(getActivity(), contact, mSipAddressToAdd); - } else { - mLastKnownPosition = mLayoutManager.findFirstVisibleItemPosition(); - LinphoneActivity.instance().displayContact(contact, mOnlyDisplayChatAddress); - } - } - - @Override - public void onItemClicked(int position) { - LinphoneContact contact = (LinphoneContact) mContactAdapter.getItem(position); - - if (mContactAdapter.isEditionEnabled()) { - mContactAdapter.toggleSelection(position); - - } else if (mEditOnClick) { - mEditConsumed = true; - ContactsManager.getInstance().editContact(getActivity(), contact, mSipAddressToAdd); - } else { - mLastKnownPosition = mLayoutManager.findFirstVisibleItemPosition(); - LinphoneActivity.instance().displayContact(contact, mOnlyDisplayChatAddress); - } - } - - @Override - public boolean onItemLongClicked(int position) { - if (!mContactAdapter.isEditionEnabled()) { - mSelectionHelper.enterEditionMode(); - } - mContactAdapter.toggleSelection(position); - return true; - } - - @Override - public void onResume() { - super.onResume(); - ContactsManager.getInstance().addContactsListener(this); - - if (mEditConsumed) { - mEditOnClick = false; - mSipAddressToAdd = null; - } - - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.CONTACTS_LIST); - mOnlyDisplayLinphoneContacts = - ContactsManager.getInstance().isLinphoneContactsPrefered() - || getResources().getBoolean(R.bool.hide_non_linphone_contacts); - } - changeContactsToggle(); - invalidate(); - } - - @Override - public void onPause() { - ContactsManager.getInstance().removeContactsListener(this); - super.onPause(); - } - - @Override - public void onContactsUpdated() { - if (!LinphoneActivity.isInstanciated() - || (LinphoneActivity.instance().getCurrentFragment() - != FragmentsAvailable.CONTACTS_LIST - && !LinphoneActivity.instance().isTablet())) return; - if (mContactAdapter != null) { - mContactAdapter.updateDataSet( - mOnlyDisplayLinphoneContacts - ? ContactsManager.getInstance().getSIPContacts() - : ContactsManager.getInstance().getContacts()); - mContactAdapter.notifyDataSetChanged(); - - if (mContactAdapter.getItemCount() > 0) { - mNoContact.setVisibility(View.GONE); - mNoSipContact.setVisibility(View.GONE); - } - } - mContactsFetchInProgress.setVisibility(View.GONE); - mContactsRefresher.setRefreshing(false); - } - private void invalidate() { if (mSearchView != null && mSearchView.getQuery().toString().length() > 0) { searchContacts(mSearchView.getQuery().toString()); @@ -399,20 +363,4 @@ public class ContactsFragment extends Fragment } mContactsList.scrollToPosition(mLastKnownPosition); } - - @Override - public void onDeleteSelection(Object[] objectsToDelete) { - ArrayList ids = new ArrayList<>(); - int size = mContactAdapter.getSelectedItemCount(); - for (int i = size - 1; i >= 0; i--) { - LinphoneContact contact = (LinphoneContact) objectsToDelete[i]; - if (contact.isAndroidContact()) { - contact.deleteFriend(); - ids.add(contact.getAndroidId()); - } else { - contact.delete(); - } - } - ContactsManager.getInstance().deleteMultipleContactsAtOnce(ids); - } } diff --git a/app/src/main/java/org/linphone/contacts/ContactsManager.java b/app/src/main/java/org/linphone/contacts/ContactsManager.java index e455ab94a..43b9caa88 100644 --- a/app/src/main/java/org/linphone/contacts/ContactsManager.java +++ b/app/src/main/java/org/linphone/contacts/ContactsManager.java @@ -29,18 +29,17 @@ import android.content.ContentProviderOperation; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; -import android.content.Intent; import android.content.pm.PackageManager; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; +import android.os.Handler; import android.os.RemoteException; import android.provider.ContactsContract; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.LinphoneService; import org.linphone.R; @@ -56,10 +55,8 @@ import org.linphone.core.tools.Log; import org.linphone.settings.LinphonePreferences; public class ContactsManager extends ContentObserver implements FriendListListener { - private static ContactsManager sInstance; - private List mContacts, mSipContacts; - private ArrayList mContactsUpdatedListeners; + private final ArrayList mContactsUpdatedListeners; private MagicSearch mMagicSearch; private boolean mContactsFetchedOnce = false; private Context mContext; @@ -67,18 +64,18 @@ public class ContactsManager extends ContentObserver implements FriendListListen private boolean mInitialized = false; public static ContactsManager getInstance() { - if (sInstance == null) sInstance = new ContactsManager(); - return sInstance; + return LinphoneService.instance().getContactsManager(); } - private ContactsManager() { - super(LinphoneService.instance().handler); + public ContactsManager(Context context, Handler handler) { + super(handler); + mContext = context; mContactsUpdatedListeners = new ArrayList<>(); mContacts = new ArrayList<>(); mSipContacts = new ArrayList<>(); - if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) { - mMagicSearch = LinphoneManager.getLcIfManagerNotDestroyedOrNull().createMagicSearch(); + if (LinphoneManager.getCore() != null) { + mMagicSearch = LinphoneManager.getCore().createMagicSearch(); mMagicSearch.setLimitedSearch(false); // Do not limit the number of results } } @@ -122,6 +119,8 @@ public class ContactsManager extends ContentObserver implements FriendListListen } public void destroy() { + mContext.getContentResolver().unregisterContentObserver(ContactsManager.getInstance()); + if (mLoadContactTask != null) { mLoadContactTask.cancel(true); } @@ -136,13 +135,12 @@ public class ContactsManager extends ContentObserver implements FriendListListen } mSipContacts.clear(); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - for (FriendList list : lc.getFriendsLists()) { + Core core = LinphoneManager.getCore(); + if (core != null) { + for (FriendList list : core.getFriendsLists()) { list.removeListener(this); } } - sInstance = null; } public void fetchContactsAsync() { @@ -153,45 +151,11 @@ public class ContactsManager extends ContentObserver implements FriendListListen Log.w("[Contacts Manager] Can't fetch contact without READ permission"); return; } - mLoadContactTask = new AsyncContactsLoader(mContext); + mLoadContactTask = new AsyncContactsLoader(); mContactsFetchedOnce = true; mLoadContactTask.executeOnExecutor(THREAD_POOL_EXECUTOR); } - public void editContact(Context context, LinphoneContact contact, String valueToAdd) { - if (context.getResources().getBoolean(R.bool.use_native_contact_editor)) { - Intent intent = new Intent(Intent.ACTION_EDIT); - Uri contactUri = contact.getAndroidLookupUri(); - intent.setDataAndType(contactUri, ContactsContract.Contacts.CONTENT_ITEM_TYPE); - intent.putExtra( - "finishActivityOnSaveCompleted", true); // So after save will go back here - if (valueToAdd != null) { - intent.putExtra(ContactsContract.Intents.Insert.IM_HANDLE, valueToAdd); - } - context.startActivity(intent); - } else { - LinphoneActivity.instance().editContact(contact, valueToAdd); - } - } - - public void createContact(Context context, String name, String valueToAdd) { - if (context.getResources().getBoolean(R.bool.use_native_contact_editor)) { - Intent intent = new Intent(ContactsContract.Intents.Insert.ACTION); - intent.setType(ContactsContract.RawContacts.CONTENT_TYPE); - intent.putExtra( - "finishActivityOnSaveCompleted", true); // So after save will go back here - if (name != null) { - intent.putExtra(ContactsContract.Intents.Insert.NAME, name); - } - if (valueToAdd != null) { - intent.putExtra(ContactsContract.Intents.Insert.IM_HANDLE, valueToAdd); - } - context.startActivity(intent); - } else { - LinphoneActivity.instance().addContact(name, valueToAdd); - } - } - public MagicSearch getMagicSearch() { return mMagicSearch; } @@ -256,7 +220,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen && !mContext.getResources().getBoolean(R.bool.force_use_of_linphone_friends); } - public boolean hasWriteContactsAccess() { + private boolean hasWriteContactsAccess() { if (mContext == null) { return false; } @@ -266,7 +230,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen Manifest.permission.WRITE_CONTACTS, mContext.getPackageName())); } - public boolean hasWriteSyncPermission() { + private boolean hasWriteSyncPermission() { if (mContext == null) { return false; } @@ -278,16 +242,14 @@ public class ContactsManager extends ContentObserver implements FriendListListen } public boolean isLinphoneContactsPrefered() { - ProxyConfig lpc = LinphoneManager.getLc().getDefaultProxyConfig(); + ProxyConfig lpc = LinphoneManager.getCore().getDefaultProxyConfig(); return lpc != null && lpc.getIdentityAddress() .getDomain() .equals(mContext.getString(R.string.default_domain)); } - public void initializeContactManager(Context context) { - mContext = context; - + public void initializeContactManager() { if (!mInitialized) { if (mContext.getResources().getBoolean(R.bool.use_linphone_tag)) { if (hasReadContactsAccess() @@ -352,12 +314,12 @@ public class ContactsManager extends ContentObserver implements FriendListListen Log.e("[Contacts Manager] Couldn't initialize sync account: " + e); } } else if (accounts != null) { - for (int i = 0; i < accounts.length; i++) { + for (Account account : accounts) { Log.i( "[Contacts Manager] Found account with name \"" - + accounts[i].name + + account.name + "\" and type \"" - + accounts[i].type + + account.type + "\""); makeContactAccountVisible(); } @@ -377,8 +339,8 @@ public class ContactsManager extends ContentObserver implements FriendListListen public synchronized LinphoneContact findContactFromAddress(Address address) { if (address == null) return null; - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - Friend lf = lc.findFriend(address); + Core core = LinphoneManager.getCore(); + Friend lf = core.findFriend(address); if (lf != null) { return (LinphoneContact) lf.getUserData(); } @@ -387,10 +349,10 @@ public class ContactsManager extends ContentObserver implements FriendListListen public synchronized LinphoneContact findContactFromPhoneNumber(String phoneNumber) { if (phoneNumber == null) return null; - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); ProxyConfig lpc = null; - if (lc != null) { - lpc = lc.getDefaultProxyConfig(); + if (core != null) { + lpc = core.getDefaultProxyConfig(); } if (lpc == null) return null; String normalized = lpc.normalizePhoneNumber(phoneNumber); @@ -402,7 +364,7 @@ public class ContactsManager extends ContentObserver implements FriendListListen } addr.setUriParam("user", "phone"); Friend lf = - lc.findFriend( + core.findFriend( addr); // Without this, the hashmap inside liblinphone won't find it... if (lf != null) { return (LinphoneContact) lf.getUserData(); diff --git a/app/src/main/java/org/linphone/contacts/LinphoneContact.java b/app/src/main/java/org/linphone/contacts/LinphoneContact.java index 8913733c0..6dd06f350 100644 --- a/app/src/main/java/org/linphone/contacts/LinphoneContact.java +++ b/app/src/main/java/org/linphone/contacts/LinphoneContact.java @@ -27,8 +27,8 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Locale; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; +import org.linphone.LinphoneService; import org.linphone.R; import org.linphone.core.Address; import org.linphone.core.Core; @@ -53,7 +53,6 @@ public class LinphoneContact extends AndroidContact super(); mAddresses = new ArrayList<>(); mAndroidId = null; - mAndroidLookupKey = null; mThumbnailUri = null; mPhotoUri = null; mHasSipAddress = false; @@ -176,10 +175,6 @@ public class LinphoneContact extends AndroidContact Picture related */ - public boolean hasPhoto() { - return mPhotoUri != null; - } - public Uri getPhotoUri() { return mPhotoUri; } @@ -202,7 +197,7 @@ public class LinphoneContact extends AndroidContact Number or address related */ - public void addNumberOrAddress(LinphoneNumberOrAddress noa) { + private void addNumberOrAddress(LinphoneNumberOrAddress noa) { if (noa == null) return; if (noa.isSIPAddress()) { mHasSipAddress = true; @@ -316,11 +311,11 @@ public class LinphoneContact extends AndroidContact private void createOrUpdateFriend() { boolean created = false; - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc == null) return; + Core core = LinphoneManager.getCore(); + if (core == null) return; if (!isFriend()) { - mFriend = lc.createFriend(); + mFriend = core.createFriend(); mFriend.enableSubscribes(false); mFriend.setIncSubscribePolicy(SubscribePolicy.SPDeny); if (isAndroidContact()) { @@ -350,7 +345,7 @@ public class LinphoneContact extends AndroidContact } for (LinphoneNumberOrAddress noa : mAddresses) { if (noa.isSIPAddress()) { - Address addr = lc.interpretUrl(noa.getValue()); + Address addr = core.interpretUrl(noa.getValue()); if (addr != null) { mFriend.addAddress(addr); } @@ -361,7 +356,7 @@ public class LinphoneContact extends AndroidContact mFriend.done(); } if (created) { - lc.addFriend(mFriend); + core.addFriend(mFriend); } if (!ContactsManager.getInstance().hasReadContactsAccess()) { @@ -374,9 +369,9 @@ public class LinphoneContact extends AndroidContact } public void deleteFriend() { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (mFriend != null && lc != null) { - for (FriendList list : lc.getFriendsLists()) { + Core core = LinphoneManager.getCore(); + if (mFriend != null && core != null) { + for (FriendList list : core.getFriendsLists()) { list.removeFriend(mFriend); } } @@ -436,7 +431,7 @@ public class LinphoneContact extends AndroidContact private void createFriend() { LinphoneContact contact = new LinphoneContact(); - Friend friend = LinphoneManager.getLc().createFriend(); + Friend friend = LinphoneManager.getCore().createFriend(); // Disable subscribes for now friend.enableSubscribes(false); friend.setIncSubscribePolicy(SubscribePolicy.SPDeny); @@ -465,8 +460,8 @@ public class LinphoneContact extends AndroidContact mHasSipAddress = mFriend.getAddress() != null; mOrganization = mFriend.getVcard().getOrganization(); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null && lc.vcardSupported()) { + Core core = LinphoneManager.getCore(); + if (core != null && core.vcardSupported()) { for (Address addr : mFriend.getAddresses()) { if (addr != null) { addNumberOrAddress( @@ -485,7 +480,7 @@ public class LinphoneContact extends AndroidContact } } - public void syncValuesFromAndroidContact(Context context) { + private void syncValuesFromAndroidContact(Context context) { Cursor c = context.getContentResolver() .query( @@ -515,16 +510,13 @@ public class LinphoneContact extends AndroidContact String data2 = c.getString(c.getColumnIndex("data2")); String data3 = c.getString(c.getColumnIndex("data3")); String data4 = c.getString(c.getColumnIndex("data4")); - String lookupKey = c.getString(c.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); - setAndroidLookupKey(lookupKey); setFullName(displayName); if (ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mime)) { addNumberOrAddress(new LinphoneNumberOrAddress(data1, data4)); } else if (ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE.equals(mime) - || LinphoneManager.getInstance() - .getContext() + || LinphoneService.instance() .getString(R.string.linphone_address_mime_type) .equals(mime)) { addNumberOrAddress(new LinphoneNumberOrAddress(data1, true)); @@ -537,7 +529,7 @@ public class LinphoneContact extends AndroidContact public void save() { saveChangesCommited(); - syncValuesFromAndroidContact(LinphoneActivity.instance()); + syncValuesFromAndroidContact(LinphoneService.instance()); createOrUpdateFriend(); } diff --git a/app/src/main/java/org/linphone/contacts/LinphoneNumberOrAddress.java b/app/src/main/java/org/linphone/contacts/LinphoneNumberOrAddress.java index 37b777095..47656c5bb 100644 --- a/app/src/main/java/org/linphone/contacts/LinphoneNumberOrAddress.java +++ b/app/src/main/java/org/linphone/contacts/LinphoneNumberOrAddress.java @@ -63,7 +63,7 @@ public class LinphoneNumberOrAddress implements Serializable, Comparable mContacts; private ArrayList mContactsSelected; private boolean mOnlySipContact = false; - private SearchContactViewHolder.ClickListener mListener; + private final SearchContactViewHolder.ClickListener mListener; private final boolean mIsOnlyOnePersonSelection; private String mPreviousSearch; private boolean mSecurityEnabled; @@ -116,12 +117,6 @@ public class SearchContactsAdapter extends RecyclerView.Adapter 0) { - if (sIsCallTransferOngoing) { - mCall.setImageResource(R.drawable.call_transfer); - } else { - mCall.setImageResource(R.drawable.call_add); - } - } else { - if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null - && LinphoneManager.getLcIfManagerNotDestroyedOrNull() - .getVideoActivationPolicy() - .getAutomaticallyInitiate()) { - mCall.setImageResource(R.drawable.call_video_start); - } else { - mCall.setImageResource(R.drawable.call_audio_start); - } - } - - mNumpad = view.findViewById(R.id.numpad); - if (mNumpad != null) { - mNumpad.setAddressWidget(mAddress); - } - - mAddContact = view.findViewById(R.id.add_contact); - mAddContact.setEnabled( - !(LinphoneActivity.isInstanciated() - && LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null - && LinphoneManager.getLc().getCallsNb() > 0)); - - mAddContactListener = - new OnClickListener() { - @Override - public void onClick(View v) { - LinphoneActivity.instance() - .displayContactsForEdition(mAddress.getText().toString()); - } - }; - mCancelListener = - new OnClickListener() { - @Override - public void onClick(View v) { - LinphoneActivity.instance() - .resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); - } - }; - mTransferListener = - new OnClickListener() { - @Override - public void onClick(View v) { - Core lc = LinphoneManager.getLc(); - if (lc.getCurrentCall() == null) { - return; - } - lc.transferCall(lc.getCurrentCall(), mAddress.getText().toString()); - sIsCallTransferOngoing = false; - LinphoneActivity.instance() - .resetClassicMenuLayoutAndGoBackToCallIfStillRunning(); - } - }; - - resetLayout(); - - if (getArguments() != null) { - String number = getArguments().getString("SipUri"); - String displayName = getArguments().getString("DisplayName"); - mAddress.setText(number); - if (displayName != null) { - mAddress.setDisplayedName(displayName); - } - } - - sInstance = this; - - return view; - } - - @Override - public void onPause() { - sInstance = null; - super.onPause(); - } - - @Override - public void onResume() { - super.onResume(); - sInstance = this; - - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.DIALER); - LinphoneActivity.instance().updateDialerFragment(); - LinphoneActivity.instance().showStatusBar(); - } - - boolean isOrientationLandscape = - getResources().getConfiguration().orientation - == Configuration.ORIENTATION_LANDSCAPE; - if (isOrientationLandscape && !getResources().getBoolean(R.bool.isTablet)) { - ((LinearLayout) mNumpad).setVisibility(View.GONE); - } else { - ((LinearLayout) mNumpad).setVisibility(View.VISIBLE); - } - - resetLayout(); - - String addressWaitingToBeCalled = LinphoneActivity.instance().addressWaitingToBeCalled; - if (addressWaitingToBeCalled != null) { - mAddress.setText(addressWaitingToBeCalled); - if (!LinphoneActivity.instance().isCallTransfer() - && getResources() - .getBoolean(R.bool.automatically_start_intercepted_outgoing_gsm_call)) { - newOutgoingCall(addressWaitingToBeCalled); - } - LinphoneActivity.instance().addressWaitingToBeCalled = null; - } - } - - public void resetLayout() { - if (!LinphoneActivity.isInstanciated()) { - return; - } - sIsCallTransferOngoing = LinphoneActivity.instance().isCallTransfer(); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc == null) { - return; - } - - if (lc.getCallsNb() > 0) { - if (sIsCallTransferOngoing) { - mCall.setImageResource(R.drawable.call_transfer); - mCall.setExternalClickListener(mTransferListener); - } else { - mCall.setImageResource(R.drawable.call_add); - mCall.resetClickListener(); - } - mAddContact.setEnabled(true); - mAddContact.setImageResource(R.drawable.call_back); - mAddContact.setOnClickListener(mCancelListener); - } else { - mCall.resetClickListener(); - if (LinphoneManager.getLc().getVideoActivationPolicy().getAutomaticallyInitiate()) { - mCall.setImageResource(R.drawable.call_video_start); - } else { - mCall.setImageResource(R.drawable.call_audio_start); - } - mAddContact.setEnabled(false); - mAddContact.setImageResource(R.drawable.contact_add); - mAddContact.setOnClickListener(mAddContactListener); - enableDisableAddContact(); - } - } - - public void enableDisableAddContact() { - mAddContact.setEnabled( - LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null - && LinphoneManager.getLc().getCallsNb() > 0 - || !mAddress.getText().toString().equals("")); - } - - public void displayTextInAddressBar(String numberOrSipAddress) { - mAddress.setText(numberOrSipAddress); - } - - public void newOutgoingCall(String numberOrSipAddress) { - displayTextInAddressBar(numberOrSipAddress); - LinphoneManager.getInstance().newOutgoingCall(mAddress); - } -} diff --git a/app/src/main/java/org/linphone/fragments/FragmentsAvailable.java b/app/src/main/java/org/linphone/fragments/FragmentsAvailable.java deleted file mode 100644 index 60e237a9a..000000000 --- a/app/src/main/java/org/linphone/fragments/FragmentsAvailable.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.linphone.fragments; - -/* -FragmentsAvailable.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -public enum FragmentsAvailable { - UNKNOW, - DIALER, - EMPTY, - HISTORY_LIST, - HISTORY_DETAIL, - CONTACTS_LIST, - CONTACT_DETAIL, - CONTACT_EDITOR, - ABOUT, - ACCOUNT_SETTINGS, - SETTINGS, - SETTINGS_SUBLEVEL, - CHAT_LIST, - CHAT, - CREATE_CHAT, - INFO_GROUP_CHAT, - GROUP_CHAT, - MESSAGE_IMDN, - CONTACT_DEVICES, - RECORDING_LIST; - - public boolean shouldAddItselfToTheRightOf(FragmentsAvailable fragment) { - switch (this) { - case HISTORY_DETAIL: - return fragment == HISTORY_LIST || fragment == HISTORY_DETAIL; - - case CONTACT_DETAIL: - return fragment == CONTACTS_LIST - || fragment == CONTACT_EDITOR - || fragment == CONTACT_DETAIL; - - case CONTACT_EDITOR: - return fragment == CONTACTS_LIST - || fragment == CONTACT_DETAIL - || fragment == CONTACT_EDITOR; - - case CHAT: - return fragment == CHAT_LIST || fragment == CHAT; - - case GROUP_CHAT: - return fragment == CHAT_LIST - || fragment == GROUP_CHAT - || fragment == INFO_GROUP_CHAT - || fragment == CREATE_CHAT; - - case MESSAGE_IMDN: - return fragment == GROUP_CHAT || fragment == MESSAGE_IMDN; - - case SETTINGS_SUBLEVEL: - return fragment == SETTINGS || fragment == SETTINGS_SUBLEVEL; - - case CONTACT_DEVICES: - return fragment == GROUP_CHAT || fragment == CONTACT_DEVICES; - - default: - return false; - } - } -} diff --git a/app/src/main/java/org/linphone/fragments/StatusFragment.java b/app/src/main/java/org/linphone/fragments/StatusFragment.java index 7fb84eda4..0ecf01c2a 100644 --- a/app/src/main/java/org/linphone/fragments/StatusFragment.java +++ b/app/src/main/java/org/linphone/fragments/StatusFragment.java @@ -36,7 +36,6 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import androidx.core.content.ContextCompat; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.LinphoneService; import org.linphone.R; @@ -63,6 +62,7 @@ public class StatusFragment extends Fragment { private CoreListenerStub mListener; private Dialog mZrtpDialog = null; private int mDisplayedQuality = -1; + private MenuClikedListener mMenuListener; @Override public View onCreateView( @@ -77,6 +77,17 @@ public class StatusFragment extends Fragment { mVoicemail = view.findViewById(R.id.voicemail); mVoicemailCount = view.findViewById(R.id.voicemail_count); + mMenuListener = null; + mMenu.setOnClickListener( + new OnClickListener() { + @Override + public void onClick(View v) { + if (mMenuListener != null) { + mMenuListener.onMenuCliked(); + } + } + }); + // We create it once to not delay the first display populateSliderContent(); @@ -84,7 +95,7 @@ public class StatusFragment extends Fragment { new CoreListenerStub() { @Override public void onRegistrationStateChanged( - final Core lc, + final Core core, final ProxyConfig proxy, final RegistrationState state, String smessage) { @@ -92,18 +103,18 @@ public class StatusFragment extends Fragment { return; } - if (lc.getProxyConfigList() == null) { + if (core.getProxyConfigList() == null) { mStatusLed.setImageResource(R.drawable.led_disconnected); mStatusText.setText(getString(R.string.no_account)); } else { mStatusLed.setVisibility(View.VISIBLE); } - if (lc.getDefaultProxyConfig() != null - && lc.getDefaultProxyConfig().equals(proxy)) { + if (core.getDefaultProxyConfig() != null + && core.getDefaultProxyConfig().equals(proxy)) { mStatusLed.setImageResource(getStatusIconResource(state)); mStatusText.setText(getStatusIconText(state)); - } else if (lc.getDefaultProxyConfig() == null) { + } else if (core.getDefaultProxyConfig() == null) { mStatusLed.setImageResource(getStatusIconResource(state)); mStatusText.setText(getStatusIconText(state)); } @@ -113,9 +124,7 @@ public class StatusFragment extends Fragment { new OnClickListener() { @Override public void onClick(View v) { - Core core = - LinphoneManager - .getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null) { core.refreshRegisters(); } @@ -128,7 +137,7 @@ public class StatusFragment extends Fragment { @Override public void onNotifyReceived( - Core lc, Event ev, String eventName, Content content) { + Core core, Event ev, String eventName, Content content) { if (!content.getType().equals("application")) return; if (!content.getSubtype().equals("simple-message-summary")) return; @@ -143,7 +152,7 @@ public class StatusFragment extends Fragment { try { unreadCount = Integer.parseInt(intToParse[0]); } catch (NumberFormatException nfe) { - + Log.e("[Status Fragment] " + nfe); } if (unreadCount > 0) { mVoicemailCount.setText(String.valueOf(unreadCount)); @@ -160,9 +169,7 @@ public class StatusFragment extends Fragment { mIsAttached = true; Activity activity = getActivity(); - if (activity instanceof LinphoneActivity) { - ((LinphoneActivity) activity).updateStatusFragment(this); - } else if (activity instanceof CallActivity) { + if (activity instanceof CallActivity) { ((CallActivity) activity).updateStatusFragment(this); } mIsInCall = @@ -179,44 +186,35 @@ public class StatusFragment extends Fragment { mIsAttached = false; } + public void setMenuListener(MenuClikedListener listener) { + mMenuListener = listener; + } + // NORMAL STATUS BAR private void populateSliderContent() { - if (LinphoneManager.isInstanciated() && LinphoneManager.getLc() != null) { + Core core = LinphoneManager.getCore(); + if (core != null) { mVoicemailCount.setVisibility(View.GONE); - if (mIsInCall && mIsAttached) { - // Call call = LinphoneManager.getLc().getCurrentCall(); - // initCallStatsRefresher(call, callStats); - } else if (!mIsInCall) { + if (!mIsInCall) { mVoicemailCount.setVisibility(View.VISIBLE); } - if (LinphoneManager.getLc().getProxyConfigList().length == 0) { + if (core.getProxyConfigList().length == 0) { mStatusLed.setImageResource(R.drawable.led_disconnected); mStatusText.setText(getString(R.string.no_account)); } } } - public void resetAccountStatus() { - if (LinphoneManager.getLc().getProxyConfigList().length == 0) { - mStatusLed.setImageResource(R.drawable.led_disconnected); - mStatusText.setText(getString(R.string.no_account)); - } - } - - public void enableSideMenu(boolean enabled) { - mMenu.setEnabled(enabled); - } - private int getStatusIconResource(RegistrationState state) { try { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); boolean defaultAccountConnected = - (lc != null - && lc.getDefaultProxyConfig() != null - && lc.getDefaultProxyConfig().getState() == RegistrationState.Ok); + (core != null + && core.getDefaultProxyConfig() != null + && core.getDefaultProxyConfig().getState() == RegistrationState.Ok); if (state == RegistrationState.Ok && defaultAccountConnected) { return R.drawable.led_connected; } else if (state == RegistrationState.Progress) { @@ -235,15 +233,11 @@ public class StatusFragment extends Fragment { private String getStatusIconText(RegistrationState state) { Context context = getActivity(); - if (!mIsAttached && LinphoneActivity.isInstanciated()) - context = LinphoneActivity.instance(); - else if (!mIsAttached && LinphoneService.isReady()) context = LinphoneService.instance(); + if (!mIsAttached && LinphoneService.isReady()) context = LinphoneService.instance(); try { if (state == RegistrationState.Ok - && LinphoneManager.getLcIfManagerNotDestroyedOrNull() - .getDefaultProxyConfig() - .getState() + && LinphoneManager.getCore().getDefaultProxyConfig().getState() == RegistrationState.Ok) { return context.getString(R.string.status_connected); } else if (state == RegistrationState.Progress) { @@ -266,7 +260,7 @@ public class StatusFragment extends Fragment { mRefreshHandler.postDelayed( mCallQualityUpdater = new Runnable() { - final Call mCurrentCall = LinphoneManager.getLc().getCurrentCall(); + final Call mCurrentCall = LinphoneManager.getCore().getCurrentCall(); public void run() { if (mCurrentCall == null) { @@ -311,16 +305,17 @@ public class StatusFragment extends Fragment { public void onResume() { super.onResume(); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.addListener(mListener); - ProxyConfig lpc = lc.getDefaultProxyConfig(); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.addListener(mListener); + ProxyConfig lpc = core.getDefaultProxyConfig(); if (lpc != null) { - mListener.onRegistrationStateChanged(lc, lpc, lpc.getState(), null); + mListener.onRegistrationStateChanged(core, lpc, lpc.getState(), null); } - Call call = lc.getCurrentCall(); - if (mIsInCall && (call != null || lc.getConferenceSize() > 1 || lc.getCallsNb() > 0)) { + Call call = core.getCurrentCall(); + if (mIsInCall + && (call != null || core.getConferenceSize() > 1 || core.getCallsNb() > 0)) { if (call != null) { startCallQuality(); refreshStatusItems(call); @@ -329,13 +324,13 @@ public class StatusFragment extends Fragment { mCallQuality.setVisibility(View.VISIBLE); // We are obviously connected - if (lc.getDefaultProxyConfig() == null) { + if (core.getDefaultProxyConfig() == null) { mStatusLed.setImageResource(R.drawable.led_disconnected); mStatusText.setText(getString(R.string.no_account)); } else { mStatusLed.setImageResource( - getStatusIconResource(lc.getDefaultProxyConfig().getState())); - mStatusText.setText(getStatusIconText(lc.getDefaultProxyConfig().getState())); + getStatusIconResource(core.getDefaultProxyConfig().getState())); + mStatusText.setText(getStatusIconText(core.getDefaultProxyConfig().getState())); } } } else { @@ -348,9 +343,9 @@ public class StatusFragment extends Fragment { public void onPause() { super.onPause(); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.removeListener(mListener); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.removeListener(mListener); } if (mCallQualityUpdater != null) { @@ -397,7 +392,7 @@ public class StatusFragment extends Fragment { public void showZRTPDialog(final Call call) { if (getActivity() == null) { - Log.w("Can't display ZRTP popup, no Activity"); + Log.w("[Status Fragment] Can't display ZRTP popup, no Activity"); return; } @@ -405,11 +400,14 @@ public class StatusFragment extends Fragment { String token = call.getAuthenticationToken(); if (token == null) { - Log.w("Can't display ZRTP popup, no token !"); + Log.w("[Status Fragment] Can't display ZRTP popup, no token !"); return; } if (token.length() < 4) { - Log.w("Can't display ZRTP popup, token is invalid (" + token + ")"); + Log.w( + "[Status Fragment] Can't display ZRTP popup, token is invalid (" + + token + + ")"); return; } @@ -492,4 +490,8 @@ public class StatusFragment extends Fragment { mZrtpDialog.show(); } } + + public interface MenuClikedListener { + void onMenuCliked(); + } } diff --git a/app/src/main/java/org/linphone/history/HistoryActivity.java b/app/src/main/java/org/linphone/history/HistoryActivity.java new file mode 100644 index 000000000..88712156a --- /dev/null +++ b/app/src/main/java/org/linphone/history/HistoryActivity.java @@ -0,0 +1,115 @@ +package org.linphone.history; + +/* +HistoryActivity.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.app.Fragment; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import org.linphone.LinphoneManager; +import org.linphone.R; +import org.linphone.activities.MainActivity; +import org.linphone.contacts.ContactsManager; +import org.linphone.contacts.LinphoneContact; +import org.linphone.core.Address; +import org.linphone.utils.LinphoneUtils; + +public class HistoryActivity extends MainActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + protected void onStart() { + super.onStart(); + + Fragment currentFragment = getFragmentManager().findFragmentById(R.id.fragmentContainer); + if (currentFragment == null) { + HistoryFragment fragment = new HistoryFragment(); + changeFragment(fragment, "History", false); + if (isTablet()) { + fragment.displayFirstLog(); + } + } + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + // Clean fragments stack upon return + while (getFragmentManager().getBackStackEntryCount() > 0) { + getFragmentManager().popBackStackImmediate(); + } + } + + @Override + protected void onResume() { + super.onResume(); + + mHistorySelected.setVisibility(View.VISIBLE); + LinphoneManager.getCore().resetMissedCallsCount(); + displayMissedCalls(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + } + + @Override + public void goBack() { + // 1 is for the empty fragment on tablets + if (!isTablet() || getFragmentManager().getBackStackEntryCount() > 1) { + if (popBackStack()) { + return; + } + } + super.goBack(); + } + + public void showHistoryDetails(Address address) { + Bundle extras = new Bundle(); + if (address != null) { + LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(address); + String displayName = + contact != null + ? contact.getFullName() + : LinphoneUtils.getAddressDisplayName(address.asStringUriOnly()); + String pictureUri = + contact != null && contact.getPhotoUri() != null + ? contact.getPhotoUri().toString() + : null; + + extras.putString("SipUri", address.asStringUriOnly()); + extras.putString("DisplayName", displayName); + extras.putString("PictureUri", pictureUri); + } + HistoryDetailFragment fragment = new HistoryDetailFragment(); + fragment.setArguments(extras); + changeFragment(fragment, "History detail", true); + } +} diff --git a/app/src/main/java/org/linphone/history/HistoryAdapter.java b/app/src/main/java/org/linphone/history/HistoryAdapter.java index b4f46bea3..c0412f218 100644 --- a/app/src/main/java/org/linphone/history/HistoryAdapter.java +++ b/app/src/main/java/org/linphone/history/HistoryAdapter.java @@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import android.annotation.SuppressLint; -import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -28,7 +27,6 @@ import androidx.annotation.NonNull; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.R; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; @@ -42,17 +40,17 @@ import org.linphone.views.ContactAvatar; public class HistoryAdapter extends SelectableAdapter { private final List mLogs; - private final Context mContext; + private final HistoryActivity mActivity; private final HistoryViewHolder.ClickListener mClickListener; public HistoryAdapter( - Context aContext, + HistoryActivity activity, List logs, HistoryViewHolder.ClickListener listener, SelectableHelper helper) { super(helper); mLogs = logs; - mContext = aContext; + mActivity = activity; mClickListener = listener; } @@ -71,9 +69,9 @@ public class HistoryAdapter extends SelectableAdapter { @Override public void onBindViewHolder(@NonNull final HistoryViewHolder holder, final int position) { - final CallLog log = mLogs.get(position); + CallLog log = mLogs.get(position); long timestamp = log.getStartDate() * 1000; - Address address; + final Address address; holder.contact.setSelected(true); // For automated horizontal scrolling of long texts Calendar logTime = Calendar.getInstance(); @@ -111,7 +109,7 @@ public class HistoryAdapter extends SelectableAdapter { LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(address); String displayName = null; - final String sipUri = (address != null) ? address.asString() : ""; + String sipUri = (address != null) ? address.asString() : ""; if (c != null) { displayName = c.getFullName(); @@ -134,9 +132,7 @@ public class HistoryAdapter extends SelectableAdapter { ? new View.OnClickListener() { @Override public void onClick(View v) { - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().displayHistoryDetail(sipUri, log); - } + mActivity.showHistoryDetails(address); } } : null); @@ -151,13 +147,13 @@ public class HistoryAdapter extends SelectableAdapter { private String timestampToHumanDate(Calendar cal) { SimpleDateFormat dateFormat; if (isToday(cal)) { - return mContext.getString(R.string.today); + return mActivity.getString(R.string.today); } else if (isYesterday(cal)) { - return mContext.getString(R.string.yesterday); + return mActivity.getString(R.string.yesterday); } else { dateFormat = new SimpleDateFormat( - mContext.getResources().getString(R.string.history_date_format)); + mActivity.getResources().getString(R.string.history_date_format)); } return dateFormat.format(cal.getTime()); diff --git a/app/src/main/java/org/linphone/history/HistoryDetailFragment.java b/app/src/main/java/org/linphone/history/HistoryDetailFragment.java index d36bd66a7..99ec47525 100644 --- a/app/src/main/java/org/linphone/history/HistoryDetailFragment.java +++ b/app/src/main/java/org/linphone/history/HistoryDetailFragment.java @@ -31,7 +31,6 @@ import android.widget.RelativeLayout; import android.widget.TextView; import java.util.Arrays; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.contacts.ContactsManager; @@ -47,14 +46,13 @@ import org.linphone.core.Factory; import org.linphone.core.FriendCapability; import org.linphone.core.ProxyConfig; import org.linphone.core.tools.Log; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.settings.LinphonePreferences; import org.linphone.utils.LinphoneUtils; import org.linphone.views.ContactAvatar; -public class HistoryDetailFragment extends Fragment implements OnClickListener { - private ImageView mDialBack, mChat, mAddToContacts, mGoToContact, mBack; - private View mView; +public class HistoryDetailFragment extends Fragment { + private ImageView mAddToContacts; + private ImageView mGoToContact; private TextView mContactName, mContactAddress; private String mSipUri, mDisplayName; private RelativeLayout mWaitLayout, mAvatarLayout, mChatSecured; @@ -69,41 +67,80 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener { mSipUri = getArguments().getString("SipUri"); mDisplayName = getArguments().getString("DisplayName"); - mView = inflater.inflate(R.layout.history_detail, container, false); + View view = inflater.inflate(R.layout.history_detail, container, false); - mWaitLayout = mView.findViewById(R.id.waitScreen); + mWaitLayout = view.findViewById(R.id.waitScreen); mWaitLayout.setVisibility(View.GONE); - mDialBack = mView.findViewById(R.id.call); - mDialBack.setOnClickListener(this); + ImageView dialBack = view.findViewById(R.id.call); + dialBack.setOnClickListener( + new OnClickListener() { + @Override + public void onClick(View v) { + LinphoneManager.getCallManager().newOutgoingCall(mSipUri, mDisplayName); + } + }); - mBack = mView.findViewById(R.id.back); - if (getResources().getBoolean(R.bool.isTablet)) { - mBack.setVisibility(View.INVISIBLE); - } else { - mBack.setOnClickListener(this); - } + ImageView back = view.findViewById(R.id.back); + back.setOnClickListener( + new OnClickListener() { + @Override + public void onClick(View v) { + ((HistoryActivity) getActivity()).goBack(); + } + }); + back.setVisibility( + getResources().getBoolean(R.bool.isTablet) ? View.INVISIBLE : View.VISIBLE); - mChat = mView.findViewById(R.id.chat); - mChat.setOnClickListener(this); + ImageView chat = view.findViewById(R.id.chat); + chat.setOnClickListener( + new OnClickListener() { + @Override + public void onClick(View v) { + goToChat(false); + } + }); - mChatSecured = mView.findViewById(R.id.chat_secured); - mChatSecured.setOnClickListener(this); + mChatSecured = view.findViewById(R.id.chat_secured); + mChatSecured.setOnClickListener( + new OnClickListener() { + @Override + public void onClick(View v) { + goToChat(true); + } + }); if (getResources().getBoolean(R.bool.disable_chat)) { - mChat.setVisibility(View.GONE); + chat.setVisibility(View.GONE); mChatSecured.setVisibility(View.GONE); } - mAddToContacts = mView.findViewById(R.id.add_contact); - mAddToContacts.setOnClickListener(this); + mAddToContacts = view.findViewById(R.id.add_contact); + mAddToContacts.setOnClickListener( + new OnClickListener() { + @Override + public void onClick(View v) { + Address addr = Factory.instance().createAddress(mSipUri); + if (addr != null) { + addr.clean(); + ((HistoryActivity) getActivity()) + .showContactsListForCreationOrEdition(addr); + } + } + }); - mGoToContact = mView.findViewById(R.id.goto_contact); - mGoToContact.setOnClickListener(this); + mGoToContact = view.findViewById(R.id.goto_contact); + mGoToContact.setOnClickListener( + new OnClickListener() { + @Override + public void onClick(View v) { + ((HistoryActivity) getActivity()).showContactDetails(mContact); + } + }); - mAvatarLayout = mView.findViewById(R.id.avatar_layout); - mContactName = mView.findViewById(R.id.contact_name); - mContactAddress = mView.findViewById(R.id.contact_address); + mAvatarLayout = view.findViewById(R.id.avatar_layout); + mContactName = view.findViewById(R.id.contact_name); + mContactAddress = view.findViewById(R.id.contact_address); mChatRoomCreationListener = new ChatRoomListenerStub() { @@ -111,14 +148,11 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener { public void onStateChanged(ChatRoom cr, ChatRoom.State newState) { if (newState == ChatRoom.State.Created) { mWaitLayout.setVisibility(View.GONE); - LinphoneActivity.instance() - .goToChat( - cr.getLocalAddress().asStringUriOnly(), - cr.getPeerAddress().asStringUriOnly(), - null); + ((HistoryActivity) getActivity()) + .showChatRoom(cr.getLocalAddress(), cr.getPeerAddress()); } else if (newState == ChatRoom.State.CreationFailed) { mWaitLayout.setVisibility(View.GONE); - LinphoneActivity.instance().displayChatRoomError(); + ((HistoryActivity) getActivity()).displayChatRoomError(); Log.e( "Group mChat room for address " + cr.getPeerAddress() @@ -127,56 +161,10 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener { } }; - mLogsList = mView.findViewById(R.id.logs_list); + mLogsList = view.findViewById(R.id.logs_list); displayHistory(); - return mView; - } - - private void displayHistory() { - Address lAddress = Factory.instance().createAddress(mSipUri); - mChatSecured.setVisibility(View.GONE); - - if (lAddress != null) { - CallLog[] logs = - LinphoneManager.getLcIfManagerNotDestroyedOrNull() - .getCallHistoryForAddress(lAddress); - List logsList = Arrays.asList(logs); - mLogsList.setAdapter( - new HistoryLogAdapter( - LinphoneActivity.instance(), R.layout.history_detail_cell, logsList)); - - mContactAddress.setText(LinphoneUtils.getDisplayableAddress(lAddress)); - mContact = ContactsManager.getInstance().findContactFromAddress(lAddress); - - if (mContact != null) { - mContactName.setText(mContact.getFullName()); - ContactAvatar.displayAvatar(mContact, mAvatarLayout); - mAddToContacts.setVisibility(View.GONE); - mGoToContact.setVisibility(View.VISIBLE); - - if (!getResources().getBoolean(R.bool.disable_chat) - && mContact.hasPresenceModelForUriOrTelCapability( - mSipUri, FriendCapability.LimeX3Dh)) { - mChatSecured.setVisibility(View.VISIBLE); - } - } else { - mContactName.setText( - mDisplayName == null - ? LinphoneUtils.getAddressDisplayName(mSipUri) - : mDisplayName); - ContactAvatar.displayAvatar( - LinphoneUtils.getAddressDisplayName(lAddress), mAvatarLayout); - mAddToContacts.setVisibility(View.VISIBLE); - mGoToContact.setVisibility(View.GONE); - } - } else { - mContactAddress.setText(mSipUri); - mContactName.setText( - mDisplayName == null - ? LinphoneUtils.getAddressDisplayName(mSipUri) - : mDisplayName); - } + return view; } @Override @@ -187,98 +175,93 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener { super.onPause(); } - public void changeDisplayedHistory(String sipUri, String displayName) { - if (displayName == null) { - displayName = LinphoneUtils.getUsernameFromAddress(sipUri); - } + private void displayHistory() { + if (mSipUri != null) { + Address lAddress = Factory.instance().createAddress(mSipUri); + mChatSecured.setVisibility(View.GONE); - mSipUri = sipUri; - mDisplayName = displayName; - displayHistory(); - } + if (lAddress != null) { + CallLog[] logs = LinphoneManager.getCore().getCallHistoryForAddress(lAddress); + List logsList = Arrays.asList(logs); + mLogsList.setAdapter( + new HistoryLogAdapter( + getActivity(), R.layout.history_detail_cell, logsList)); - @Override - public void onResume() { - super.onResume(); + mContactAddress.setText(LinphoneUtils.getDisplayableAddress(lAddress)); + mContact = ContactsManager.getInstance().findContactFromAddress(lAddress); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.HISTORY_DETAIL); - } - } + if (mContact != null) { + mContactName.setText(mContact.getFullName()); + ContactAvatar.displayAvatar(mContact, mAvatarLayout); + mAddToContacts.setVisibility(View.GONE); + mGoToContact.setVisibility(View.VISIBLE); - @Override - public void onClick(View v) { - int id = v.getId(); - - if (id == R.id.back) { - getFragmentManager().popBackStackImmediate(); - } - if (id == R.id.call) { - LinphoneActivity.instance().setAddresGoToDialerAndCall(mSipUri, mDisplayName); - } else if (id == R.id.chat || id == R.id.chat_secured) { - boolean isSecured = id == R.id.chat_secured; - Core lc = LinphoneManager.getLc(); - Address participant = Factory.instance().createAddress(mSipUri); - ChatRoom room = - lc.findOneToOneChatRoom( - lc.getDefaultProxyConfig().getContact(), participant, isSecured); - if (room != null) { - LinphoneActivity.instance() - .goToChat( - room.getLocalAddress().asStringUriOnly(), - room.getPeerAddress().asStringUriOnly(), - null); - } else { - ProxyConfig lpc = lc.getDefaultProxyConfig(); - if (lpc != null - && lpc.getConferenceFactoryUri() != null - && (isSecured - || !LinphonePreferences.instance().useBasicChatRoomFor1To1())) { - mWaitLayout.setVisibility(View.VISIBLE); - - ChatRoomParams params = lc.createDefaultChatRoomParams(); - params.enableEncryption(isSecured); - params.enableGroup(false); - // We don't want a basic chat room - params.setBackend(ChatRoomBackend.FlexisipChat); - - Address participants[] = new Address[1]; - participants[0] = participant; - - mChatRoom = - lc.createChatRoom( - params, - getString(R.string.dummy_group_chat_subject), - participants); - if (mChatRoom != null) { - mChatRoom.addListener(mChatRoomCreationListener); - } else { - Log.w("[History Detail Fragment] createChatRoom returned null..."); - mWaitLayout.setVisibility(View.GONE); + if (!getResources().getBoolean(R.bool.disable_chat) + && mContact.hasPresenceModelForUriOrTelCapability( + mSipUri, FriendCapability.LimeX3Dh)) { + mChatSecured.setVisibility(View.VISIBLE); } } else { - room = lc.getChatRoom(participant); - LinphoneActivity.instance() - .goToChat( - room.getLocalAddress().asStringUriOnly(), - room.getPeerAddress().asStringUriOnly(), - null); + mContactName.setText( + mDisplayName == null + ? LinphoneUtils.getAddressDisplayName(mSipUri) + : mDisplayName); + ContactAvatar.displayAvatar( + LinphoneUtils.getAddressDisplayName(lAddress), mAvatarLayout); + mAddToContacts.setVisibility(View.VISIBLE); + mGoToContact.setVisibility(View.GONE); } + } else { + mContactAddress.setText(mSipUri); + mContactName.setText( + mDisplayName == null + ? LinphoneUtils.getAddressDisplayName(mSipUri) + : mDisplayName); } - } else if (id == R.id.add_contact) { - Address addr = Factory.instance().createAddress(mSipUri); - if (addr != null) { - String address = - "sip:" + addr.getUsername() + "@" + addr.getDomain(); // Clean gruu param - if (addr.getDisplayName() != null) { - LinphoneActivity.instance() - .displayContactsForEdition(address, addr.getDisplayName()); + } + } + + private void goToChat(boolean isSecured) { + Core core = LinphoneManager.getCore(); + Address participant = Factory.instance().createAddress(mSipUri); + ChatRoom room = + core.findOneToOneChatRoom( + core.getDefaultProxyConfig().getContact(), participant, isSecured); + if (room != null) { + ((HistoryActivity) getActivity()) + .showChatRoom(room.getLocalAddress(), room.getPeerAddress()); + } else { + ProxyConfig lpc = core.getDefaultProxyConfig(); + if (lpc != null + && lpc.getConferenceFactoryUri() != null + && (isSecured || !LinphonePreferences.instance().useBasicChatRoomFor1To1())) { + mWaitLayout.setVisibility(View.VISIBLE); + + ChatRoomParams params = core.createDefaultChatRoomParams(); + params.enableEncryption(isSecured); + params.enableGroup(false); + // We don't want a basic chat room + params.setBackend(ChatRoomBackend.FlexisipChat); + + Address[] participants = new Address[1]; + participants[0] = participant; + + mChatRoom = + core.createChatRoom( + params, getString(R.string.dummy_group_chat_subject), participants); + if (mChatRoom != null) { + mChatRoom.addListener(mChatRoomCreationListener); } else { - LinphoneActivity.instance().displayContactsForEdition(address); + Log.w("[History Detail Fragment] createChatRoom returned null..."); + mWaitLayout.setVisibility(View.GONE); + } + } else { + room = core.getChatRoom(participant); + if (room != null) { + ((HistoryActivity) getActivity()) + .showChatRoom(room.getLocalAddress(), room.getPeerAddress()); } } - } else if (id == R.id.goto_contact) { - LinphoneActivity.instance().displayContact(mContact, false); } } } diff --git a/app/src/main/java/org/linphone/history/HistoryFragment.java b/app/src/main/java/org/linphone/history/HistoryFragment.java index 5db3963d8..ceda0edb5 100644 --- a/app/src/main/java/org/linphone/history/HistoryFragment.java +++ b/app/src/main/java/org/linphone/history/HistoryFragment.java @@ -2,7 +2,7 @@ package org.linphone.history; /* HistoryFragment.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import android.app.Fragment; -import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -36,7 +35,6 @@ import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.contacts.ContactsManager; @@ -44,7 +42,7 @@ import org.linphone.contacts.ContactsUpdatedListener; import org.linphone.core.Address; import org.linphone.core.Call; import org.linphone.core.CallLog; -import org.linphone.fragments.FragmentsAvailable; +import org.linphone.core.Core; import org.linphone.utils.SelectableHelper; public class HistoryFragment extends Fragment @@ -60,15 +58,12 @@ public class HistoryFragment extends Fragment private boolean mOnlyDisplayMissedCalls; private List mLogs; private HistoryAdapter mHistoryAdapter; - private LinearLayoutManager mLayoutManager; - private Context mContext; private SelectableHelper mSelectionHelper; @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.history, container, false); - mContext = getActivity().getApplicationContext(); mSelectionHelper = new SelectableHelper(view, this); mNoCallHistory = view.findViewById(R.id.no_call_history); @@ -76,13 +71,13 @@ public class HistoryFragment extends Fragment mHistoryList = view.findViewById(R.id.history_list); - mLayoutManager = new LinearLayoutManager(mContext); - mHistoryList.setLayoutManager(mLayoutManager); + LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); + mHistoryList.setLayoutManager(layoutManager); // Divider between items DividerItemDecoration dividerItemDecoration = new DividerItemDecoration( - mHistoryList.getContext(), mLayoutManager.getOrientation()); - dividerItemDecoration.setDrawable(mContext.getResources().getDrawable(R.drawable.divider)); + mHistoryList.getContext(), layoutManager.getOrientation()); + dividerItemDecoration.setDrawable(getResources().getDrawable(R.drawable.divider)); mHistoryList.addItemDecoration(dividerItemDecoration); mAllCalls = view.findViewById(R.id.all_calls); @@ -101,22 +96,124 @@ public class HistoryFragment extends Fragment return view; } + @Override + public void onResume() { + super.onResume(); + ContactsManager.getInstance().addContactsListener(this); + + mLogs = Arrays.asList(LinphoneManager.getCore().getCallLogs()); + hideHistoryListAndDisplayMessageIfEmpty(); + mHistoryAdapter = + new HistoryAdapter((HistoryActivity) getActivity(), mLogs, this, mSelectionHelper); + mHistoryList.setAdapter(mHistoryAdapter); + mSelectionHelper.setAdapter(mHistoryAdapter); + mSelectionHelper.setDialogMessage(R.string.call_log_delete_dialog); + } + + @Override + public void onPause() { + ContactsManager.getInstance().removeContactsListener(this); + super.onPause(); + } + + @Override + public void onContactsUpdated() { + HistoryAdapter adapter = (HistoryAdapter) mHistoryList.getAdapter(); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } + + @Override + public void onClick(View v) { + int id = v.getId(); + + if (id == R.id.all_calls) { + mAllCalls.setEnabled(false); + mAllCallsSelected.setVisibility(View.VISIBLE); + mMissedCallsSelected.setVisibility(View.INVISIBLE); + mMissedCalls.setEnabled(true); + mOnlyDisplayMissedCalls = false; + refresh(); + } + if (id == R.id.missed_calls) { + mAllCalls.setEnabled(true); + mAllCallsSelected.setVisibility(View.INVISIBLE); + mMissedCallsSelected.setVisibility(View.VISIBLE); + mMissedCalls.setEnabled(false); + mOnlyDisplayMissedCalls = true; + } + hideHistoryListAndDisplayMessageIfEmpty(); + mHistoryAdapter = + new HistoryAdapter((HistoryActivity) getActivity(), mLogs, this, mSelectionHelper); + mHistoryList.setAdapter(mHistoryAdapter); + mSelectionHelper.setAdapter(mHistoryAdapter); + mSelectionHelper.setDialogMessage(R.string.chat_room_delete_dialog); + } + + @Override + public void onItemClick(AdapterView adapter, View view, int position, long id) { + if (mHistoryAdapter.isEditionEnabled()) { + CallLog log = mLogs.get(position); + Core core = LinphoneManager.getCore(); + core.removeCallLog(log); + mLogs = Arrays.asList(core.getCallLogs()); + } + } + + @Override + public void onDeleteSelection(Object[] objectsToDelete) { + int size = mHistoryAdapter.getSelectedItemCount(); + for (int i = 0; i < size; i++) { + CallLog log = (CallLog) objectsToDelete[i]; + LinphoneManager.getCore().removeCallLog(log); + onResume(); + } + } + + @Override + public void onItemClicked(int position) { + if (mHistoryAdapter.isEditionEnabled()) { + mHistoryAdapter.toggleSelection(position); + } else { + CallLog log = mLogs.get(position); + Address address; + if (log.getDir() == Call.Dir.Incoming) { + address = log.getFromAddress(); + } else { + address = log.getToAddress(); + } + if (address != null) { + LinphoneManager.getCallManager().newOutgoingCall(address.asStringUriOnly(), null); + } + } + } + + @Override + public boolean onItemLongClicked(int position) { + if (!mHistoryAdapter.isEditionEnabled()) { + mSelectionHelper.enterEditionMode(); + } + mHistoryAdapter.toggleSelection(position); + return true; + } + private void refresh() { - mLogs = Arrays.asList(LinphoneManager.getLc().getCallLogs()); + mLogs = Arrays.asList(LinphoneManager.getCore().getCallLogs()); } public void displayFirstLog() { + Address addr; if (mLogs != null && mLogs.size() > 0) { - CallLog log = mLogs.get(0); - String addr; + CallLog log = mLogs.get(0); // More recent one is 0 if (log.getDir() == Call.Dir.Incoming) { - addr = log.getFromAddress().asString(); + addr = log.getFromAddress(); } else { - addr = log.getToAddress().asString(); + addr = log.getToAddress(); } - LinphoneActivity.instance().displayHistoryDetail(addr, log); + ((HistoryActivity) getActivity()).showHistoryDetails(addr); } else { - LinphoneActivity.instance().displayEmptyFragment(); + ((HistoryActivity) getActivity()).showEmptyChildFragment(); } } @@ -150,115 +247,4 @@ public class HistoryFragment extends Fragment mHistoryList.setVisibility(View.VISIBLE); } } - - @Override - public void onResume() { - super.onResume(); - ContactsManager.getInstance().addContactsListener(this); - - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.HISTORY_LIST); - LinphoneActivity.instance().displayMissedCalls(0); - } - - mLogs = Arrays.asList(LinphoneManager.getLc().getCallLogs()); - hideHistoryListAndDisplayMessageIfEmpty(); - mHistoryAdapter = - new HistoryAdapter( - getActivity().getApplicationContext(), mLogs, this, mSelectionHelper); - mHistoryList.setAdapter(mHistoryAdapter); - mSelectionHelper.setAdapter(mHistoryAdapter); - mSelectionHelper.setDialogMessage(R.string.call_log_delete_dialog); - } - - @Override - public void onPause() { - ContactsManager.getInstance().removeContactsListener(this); - super.onPause(); - } - - @Override - public void onContactsUpdated() { - if (!LinphoneActivity.isInstanciated() - || LinphoneActivity.instance().getCurrentFragment() - != FragmentsAvailable.HISTORY_LIST) return; - HistoryAdapter adapter = (HistoryAdapter) mHistoryList.getAdapter(); - if (adapter != null) { - adapter.notifyDataSetChanged(); - } - } - - @Override - public void onClick(View v) { - int id = v.getId(); - - if (id == R.id.all_calls) { - mAllCalls.setEnabled(false); - mAllCallsSelected.setVisibility(View.VISIBLE); - mMissedCallsSelected.setVisibility(View.INVISIBLE); - mMissedCalls.setEnabled(true); - mOnlyDisplayMissedCalls = false; - refresh(); - } - if (id == R.id.missed_calls) { - mAllCalls.setEnabled(true); - mAllCallsSelected.setVisibility(View.INVISIBLE); - mMissedCallsSelected.setVisibility(View.VISIBLE); - mMissedCalls.setEnabled(false); - mOnlyDisplayMissedCalls = true; - } - hideHistoryListAndDisplayMessageIfEmpty(); - mHistoryAdapter = new HistoryAdapter(mContext, mLogs, this, mSelectionHelper); - mHistoryList.setAdapter(mHistoryAdapter); - mSelectionHelper.setAdapter(mHistoryAdapter); - mSelectionHelper.setDialogMessage(R.string.chat_room_delete_dialog); - } - - @Override - public void onItemClick(AdapterView adapter, View view, int position, long id) { - if (mHistoryAdapter.isEditionEnabled()) { - CallLog log = mLogs.get(position); - LinphoneManager.getLc().removeCallLog(log); - mLogs = Arrays.asList(LinphoneManager.getLc().getCallLogs()); - } - } - - @Override - public void onDeleteSelection(Object[] objectsToDelete) { - int size = mHistoryAdapter.getSelectedItemCount(); - for (int i = 0; i < size; i++) { - CallLog log = (CallLog) objectsToDelete[i]; - LinphoneManager.getLc().removeCallLog(log); - onResume(); - } - } - - @Override - public void onItemClicked(int position) { - if (mHistoryAdapter.isEditionEnabled()) { - mHistoryAdapter.toggleSelection(position); - } else { - if (LinphoneActivity.isInstanciated()) { - CallLog log = mLogs.get(position); - Address address; - if (log.getDir() == Call.Dir.Incoming) { - address = log.getFromAddress(); - } else { - address = log.getToAddress(); - } - LinphoneActivity.instance() - .setAddresGoToDialerAndCall( - address.asStringUriOnly(), address.getDisplayName()); - } - } - } - - @Override - public boolean onItemLongClicked(int position) { - if (!mHistoryAdapter.isEditionEnabled()) { - mSelectionHelper.enterEditionMode(); - } - mHistoryAdapter.toggleSelection(position); - return true; - } } diff --git a/app/src/main/java/org/linphone/history/HistoryLogAdapter.java b/app/src/main/java/org/linphone/history/HistoryLogAdapter.java index 351444913..a1b00ef20 100644 --- a/app/src/main/java/org/linphone/history/HistoryLogAdapter.java +++ b/app/src/main/java/org/linphone/history/HistoryLogAdapter.java @@ -38,7 +38,7 @@ import org.linphone.core.CallLog; import org.linphone.utils.LinphoneUtils; class HistoryLogAdapter extends ArrayAdapter { - private Context mContext; + private final Context mContext; private final List mItems; private final int mResource; @@ -74,7 +74,10 @@ class HistoryLogAdapter extends ArrayAdapter { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View rowView = inflater.inflate(mResource, parent, false); + View rowView = convertView; + if (rowView == null) { + rowView = inflater.inflate(mResource, parent, false); + } CallLog callLog = getItem(position); String callTime = secondsToDisplayableString(callLog.getDuration()); @@ -103,7 +106,7 @@ class HistoryLogAdapter extends ArrayAdapter { } time.setText(callTime == null ? "" : callTime); - Long longDate = Long.parseLong(callDate); + long longDate = Long.parseLong(callDate); date.setText( LinphoneUtils.timestampToHumanDate( mContext, diff --git a/app/src/main/java/org/linphone/menu/SideMenuAccountsListAdapter.java b/app/src/main/java/org/linphone/menu/SideMenuAccountsListAdapter.java new file mode 100644 index 000000000..4741af966 --- /dev/null +++ b/app/src/main/java/org/linphone/menu/SideMenuAccountsListAdapter.java @@ -0,0 +1,126 @@ +package org.linphone.menu; + +/* +SideMenuAccountsListAdapter.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; +import java.util.ArrayList; +import java.util.List; +import org.linphone.LinphoneManager; +import org.linphone.R; +import org.linphone.core.Core; +import org.linphone.core.ProxyConfig; +import org.linphone.core.RegistrationState; +import org.linphone.core.tools.Log; +import org.linphone.settings.LinphonePreferences; + +class SideMenuAccountsListAdapter extends BaseAdapter { + private final Context mContext; + private List proxy_list; + + SideMenuAccountsListAdapter(Context context) { + mContext = context; + proxy_list = new ArrayList<>(); + refresh(); + } + + private void refresh() { + proxy_list = new ArrayList<>(); + Core core = LinphoneManager.getCore(); + for (ProxyConfig proxyConfig : core.getProxyConfigList()) { + if (proxyConfig != core.getDefaultProxyConfig()) { + proxy_list.add(proxyConfig); + } + } + } + + public int getCount() { + if (proxy_list != null) { + return proxy_list.size(); + } else { + return 0; + } + } + + public Object getItem(int position) { + return proxy_list.get(position); + } + + public long getItemId(int position) { + return position; + } + + public View getView(final int position, View convertView, ViewGroup parent) { + View view; + ProxyConfig lpc = (ProxyConfig) getItem(position); + if (convertView != null) { + view = convertView; + } else { + view = + LayoutInflater.from(mContext) + .inflate(R.layout.side_menu_account_cell, parent, false); + } + + ImageView status = view.findViewById(R.id.account_status); + TextView address = view.findViewById(R.id.account_address); + String sipAddress = lpc.getIdentityAddress().asStringUriOnly(); + + address.setText(sipAddress); + + int nbAccounts = LinphonePreferences.instance().getAccountCount(); + int accountIndex; + + for (int i = 0; i < nbAccounts; i++) { + String username = LinphonePreferences.instance().getAccountUsername(i); + String domain = LinphonePreferences.instance().getAccountDomain(i); + String id = "sip:" + username + "@" + domain; + if (id.equals(sipAddress)) { + accountIndex = i; + view.setTag(accountIndex); + break; + } + } + status.setImageResource(getStatusIconResource(lpc.getState())); + return view; + } + + private int getStatusIconResource(RegistrationState state) { + try { + if (state == RegistrationState.Ok) { + return R.drawable.led_connected; + } else if (state == RegistrationState.Progress) { + return R.drawable.led_inprogress; + } else if (state == RegistrationState.Failed) { + return R.drawable.led_error; + } else { + return R.drawable.led_disconnected; + } + } catch (Exception e) { + Log.e(e); + } + + return R.drawable.led_disconnected; + } +} diff --git a/app/src/main/java/org/linphone/menu/SideMenuAdapter.java b/app/src/main/java/org/linphone/menu/SideMenuAdapter.java new file mode 100644 index 000000000..dfe6009af --- /dev/null +++ b/app/src/main/java/org/linphone/menu/SideMenuAdapter.java @@ -0,0 +1,75 @@ +package org.linphone.menu; + +/* +SideMenuAdapter.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.List; +import org.linphone.R; + +class SideMenuAdapter extends ArrayAdapter { + private final List mItems; + private final int mResource; + + SideMenuAdapter(@NonNull Context context, int resource, @NonNull List objects) { + super(context, resource, objects); + mResource = resource; + mItems = objects; + } + + @Nullable + @Override + public SideMenuItem getItem(int position) { + return mItems.get(position); + } + + @Override + public int getCount() { + return mItems.size(); + } + + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + LayoutInflater inflater = + (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + View rowView = convertView; + if (rowView == null) { + rowView = inflater.inflate(mResource, parent, false); + } + + TextView textView = rowView.findViewById(R.id.item_name); + ImageView imageView = rowView.findViewById(R.id.item_icon); + + SideMenuItem item = getItem(position); + textView.setText(item.name); + imageView.setImageResource(item.icon); + + return rowView; + } +} diff --git a/app/src/main/java/org/linphone/menu/SideMenuFragment.java b/app/src/main/java/org/linphone/menu/SideMenuFragment.java new file mode 100644 index 000000000..f3f5c8d83 --- /dev/null +++ b/app/src/main/java/org/linphone/menu/SideMenuFragment.java @@ -0,0 +1,257 @@ +package org.linphone.menu; + +/* +SideMenuFragment.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.content.Intent; +import android.os.Bundle; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.fragment.app.Fragment; +import java.util.ArrayList; +import java.util.List; +import org.linphone.LinphoneManager; +import org.linphone.R; +import org.linphone.activities.AboutActivity; +import org.linphone.activities.MainActivity; +import org.linphone.assistant.MenuAssistantActivity; +import org.linphone.core.Core; +import org.linphone.core.ProxyConfig; +import org.linphone.core.RegistrationState; +import org.linphone.core.tools.Log; +import org.linphone.recording.RecordingsActivity; +import org.linphone.settings.LinphonePreferences; +import org.linphone.settings.SettingsActivity; +import org.linphone.utils.LinphoneUtils; + +public class SideMenuFragment extends Fragment { + private DrawerLayout mSideMenu; + private RelativeLayout mSideMenuContent; + private RelativeLayout mDefaultAccount; + private ListView mAccountsList, mSideMenuItemList; + private QuitClikedListener mQuitListener; + + @Nullable + @Override + public View onCreateView( + @NonNull LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.side_menu, container, false); + + List sideMenuItems = new ArrayList<>(); + if (getResources().getBoolean(R.bool.show_log_out_in_side_menu)) { + sideMenuItems.add( + new SideMenuItem( + getResources().getString(R.string.menu_logout), + R.drawable.quit_default)); + } + if (!getResources().getBoolean(R.bool.hide_assistant_from_side_menu)) { + sideMenuItems.add( + new SideMenuItem( + getResources().getString(R.string.menu_assistant), + R.drawable.menu_assistant)); + } + if (!getResources().getBoolean(R.bool.hide_settings_from_side_menu)) { + sideMenuItems.add( + new SideMenuItem( + getResources().getString(R.string.menu_settings), + R.drawable.menu_options)); + } + if (getResources().getBoolean(R.bool.enable_in_app_purchase)) { + sideMenuItems.add( + new SideMenuItem( + getResources().getString(R.string.inapp), R.drawable.menu_options)); + } + if (!getResources().getBoolean(R.bool.hide_recordings_from_side_menu)) { + sideMenuItems.add( + new SideMenuItem( + getResources().getString(R.string.menu_recordings), + R.drawable.menu_recordings)); + } + sideMenuItems.add( + new SideMenuItem( + getResources().getString(R.string.menu_about), R.drawable.menu_about)); + mSideMenuItemList = view.findViewById(R.id.item_list); + + mSideMenuItemList.setAdapter( + new SideMenuAdapter(getActivity(), R.layout.side_menu_item_cell, sideMenuItems)); + mSideMenuItemList.setOnItemClickListener( + new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + String selectedItem = mSideMenuItemList.getAdapter().getItem(i).toString(); + if (selectedItem.equals(getString(R.string.menu_logout))) { + Core core = LinphoneManager.getCore(); + if (core != null) { + core.setDefaultProxyConfig(null); + core.clearAllAuthInfo(); + core.clearProxyConfig(); + startActivity( + new Intent() + .setClass( + getActivity(), + MenuAssistantActivity.class)); + getActivity().finish(); + } + } else if (selectedItem.equals(getString(R.string.menu_settings))) { + startActivity(new Intent(getActivity(), SettingsActivity.class)); + } else if (selectedItem.equals(getString(R.string.menu_about))) { + startActivity(new Intent(getActivity(), AboutActivity.class)); + } else if (selectedItem.equals(getString(R.string.menu_assistant))) { + startActivity(new Intent(getActivity(), MenuAssistantActivity.class)); + } else if (selectedItem.equals(getString(R.string.menu_recordings))) { + startActivity(new Intent(getActivity(), RecordingsActivity.class)); + } + } + }); + + mAccountsList = view.findViewById(R.id.accounts_list); + mDefaultAccount = view.findViewById(R.id.default_account); + + RelativeLayout quitLayout = view.findViewById(R.id.side_menu_quit); + quitLayout.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mQuitListener != null) { + mQuitListener.onQuitClicked(); + } + } + }); + + return view; + } + + public void setQuitListener(QuitClikedListener listener) { + mQuitListener = listener; + } + + public void setDrawer(DrawerLayout drawer, RelativeLayout content) { + mSideMenu = drawer; + mSideMenuContent = content; + } + + public boolean isOpened() { + return mSideMenu != null && mSideMenu.isDrawerVisible(Gravity.LEFT); + } + + public void closeDrawer() { + openOrCloseSideMenu(false, false); + } + + public void openOrCloseSideMenu(boolean open, boolean animate) { + if (mSideMenu == null || mSideMenuContent == null) return; + + if (open) { + mSideMenu.openDrawer(mSideMenuContent, animate); + } else { + mSideMenu.closeDrawer(mSideMenuContent, animate); + } + } + + private void displayMainAccount() { + mDefaultAccount.setVisibility(View.VISIBLE); + ImageView status = mDefaultAccount.findViewById(R.id.main_account_status); + TextView address = mDefaultAccount.findViewById(R.id.main_account_address); + TextView displayName = mDefaultAccount.findViewById(R.id.main_account_display_name); + + ProxyConfig proxy = LinphoneManager.getCore().getDefaultProxyConfig(); + if (proxy == null) { + displayName.setText(getString(R.string.no_account)); + status.setVisibility(View.GONE); + address.setText(""); + mDefaultAccount.setOnClickListener(null); + } else { + address.setText(proxy.getIdentityAddress().asStringUriOnly()); + displayName.setText(LinphoneUtils.getAddressDisplayName(proxy.getIdentityAddress())); + status.setImageResource(getStatusIconResource(proxy.getState())); + status.setVisibility(View.VISIBLE); + + if (!getResources().getBoolean(R.bool.disable_accounts_settings_from_side_menu)) { + mDefaultAccount.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View view) { + ((MainActivity) getActivity()) + .showAccountSettings( + LinphonePreferences.instance() + .getDefaultAccountIndex()); + } + }); + } + } + } + + private int getStatusIconResource(RegistrationState state) { + try { + if (state == RegistrationState.Ok) { + return R.drawable.led_connected; + } else if (state == RegistrationState.Progress) { + return R.drawable.led_inprogress; + } else if (state == RegistrationState.Failed) { + return R.drawable.led_error; + } else { + return R.drawable.led_disconnected; + } + } catch (Exception e) { + Log.e(e); + } + + return R.drawable.led_disconnected; + } + + public void displayAccountsInSideMenu() { + Core core = LinphoneManager.getCore(); + if (core != null + && core.getProxyConfigList() != null + && core.getProxyConfigList().length > 1) { + mAccountsList.setVisibility(View.VISIBLE); + mAccountsList.setAdapter(new SideMenuAccountsListAdapter(getActivity())); + mAccountsList.setOnItemClickListener( + new AdapterView.OnItemClickListener() { + @Override + public void onItemClick( + AdapterView adapterView, View view, int i, long l) { + if (view != null && view.getTag() != null) { + int position = Integer.parseInt(view.getTag().toString()); + ((MainActivity) getActivity()).showAccountSettings(position); + } + } + }); + } else { + mAccountsList.setVisibility(View.GONE); + } + displayMainAccount(); + } + + public interface QuitClikedListener { + void onQuitClicked(); + } +} diff --git a/app/src/main/java/org/linphone/menu/SideMenuItem.java b/app/src/main/java/org/linphone/menu/SideMenuItem.java new file mode 100644 index 000000000..2e7d07265 --- /dev/null +++ b/app/src/main/java/org/linphone/menu/SideMenuItem.java @@ -0,0 +1,34 @@ +package org.linphone.menu; + +/* +SideMenuItem.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +public class SideMenuItem { + final String name; + final int icon; + + SideMenuItem(String name, int icon) { + this.name = name; + this.icon = icon; + } + + public String toString() { + return name; + } +} diff --git a/app/src/main/java/org/linphone/notifications/NotificationBroadcastReceiver.java b/app/src/main/java/org/linphone/notifications/NotificationBroadcastReceiver.java index 23565460b..ceb9154d9 100644 --- a/app/src/main/java/org/linphone/notifications/NotificationBroadcastReceiver.java +++ b/app/src/main/java/org/linphone/notifications/NotificationBroadcastReceiver.java @@ -2,7 +2,7 @@ package org.linphone.notifications; /* NotificationBroadcastReceiver.java -Copyright (C) 2018 Belledonne Communications, Grenoble, France +Copyright (C) 2018 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 @@ -25,7 +25,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.LinphoneService; import org.linphone.R; @@ -51,7 +50,7 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver { .getNotificationManager() .getSipUriForNotificationId(notifId); - Core core = LinphoneManager.getLc(); + Core core = LinphoneManager.getCore(); if (core == null) { Log.e("[Notification Broadcast Receiver] Couldn't get Core instance"); onError(context, notifId); @@ -88,10 +87,6 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver { } room.markAsRead(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance() - .displayMissedChats(LinphoneManager.getInstance().getUnreadMessageCount()); - } if (intent.getAction().equals(Compatibility.INTENT_REPLY_NOTIF_ACTION)) { final String reply = getMessageText(intent).toString(); @@ -131,7 +126,7 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver { .getNotificationManager() .getSipUriForCallNotificationId(notifId); - Core core = LinphoneManager.getLc(); + Core core = LinphoneManager.getCore(); if (core == null) { Log.e("[Notification Broadcast Receiver] Couldn't get Core instance"); return; diff --git a/app/src/main/java/org/linphone/notifications/NotificationsManager.java b/app/src/main/java/org/linphone/notifications/NotificationsManager.java index 2af730f7c..e311c3c19 100644 --- a/app/src/main/java/org/linphone/notifications/NotificationsManager.java +++ b/app/src/main/java/org/linphone/notifications/NotificationsManager.java @@ -29,23 +29,35 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; +import java.io.File; import java.util.HashMap; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.LinphoneService; import org.linphone.R; +import org.linphone.activities.DialerActivity; import org.linphone.call.CallActivity; import org.linphone.call.CallIncomingActivity; import org.linphone.call.CallOutgoingActivity; +import org.linphone.chat.ChatActivity; import org.linphone.compatibility.Compatibility; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; import org.linphone.core.Address; import org.linphone.core.Call; +import org.linphone.core.ChatMessage; +import org.linphone.core.ChatRoom; +import org.linphone.core.ChatRoomCapabilities; +import org.linphone.core.Content; +import org.linphone.core.Core; +import org.linphone.core.CoreListenerStub; +import org.linphone.core.Reason; import org.linphone.core.tools.Log; +import org.linphone.history.HistoryActivity; import org.linphone.settings.LinphonePreferences; +import org.linphone.utils.FileUtils; import org.linphone.utils.ImageUtils; import org.linphone.utils.LinphoneUtils; +import org.linphone.utils.MediaScannerListener; public class NotificationsManager { private static final int SERVICE_NOTIF_ID = 1; @@ -59,12 +71,15 @@ public class NotificationsManager { private int mLastNotificationId; private final Notification mServiceNotification; private int mCurrentForegroundServiceNotification; + private String mCurrentChatRoomAddress; + private CoreListenerStub mListener; public NotificationsManager(Context context) { mContext = context; mChatNotifMap = new HashMap<>(); mCallNotifMap = new HashMap<>(); mCurrentForegroundServiceNotification = 0; + mCurrentChatRoomAddress = null; mNM = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE); mNM.cancelAll(); @@ -80,7 +95,7 @@ public class NotificationsManager { Log.e(e); } - Intent notifIntent = new Intent(mContext, LinphoneActivity.class); + Intent notifIntent = new Intent(mContext, DialerActivity.class); notifIntent.putExtra("Notification", true); PendingIntent pendingIntent = @@ -100,10 +115,97 @@ public class NotificationsManager { if (isServiceNotificationDisplayed()) { startForeground(); } + + mListener = + new CoreListenerStub() { + + @Override + public void onMessageReceived( + Core core, final ChatRoom cr, final ChatMessage message) { + if (message.isOutgoing() + || mContext.getResources().getBoolean(R.bool.disable_chat) + || mContext.getResources() + .getBoolean(R.bool.disable_chat_message_notification)) { + return; + } + + if (mCurrentChatRoomAddress != null + && mCurrentChatRoomAddress.equals( + cr.getPeerAddress().asStringUriOnly())) { + Log.i( + "[Notifications Manager] Message received for currently displayed chat room, do not make a notification"); + return; + } + + if (message.getErrorInfo() != null + && message.getErrorInfo().getReason() + == Reason.UnsupportedContent) { + Log.w( + "[Notifications Manager] Message received but content is unsupported, do not notify it"); + return; + } + + if (!message.hasTextContent() + && message.getFileTransferInformation() == null) { + Log.w( + "[Notifications Manager] Message has no text or file transfer information to display, ignoring it..."); + return; + } + + final Address from = message.getFromAddress(); + final LinphoneContact contact = + ContactsManager.getInstance().findContactFromAddress(from); + final String textMessage = + (message.hasTextContent()) + ? message.getTextContent() + : mContext.getString( + R.string.content_description_incoming_file); + + String file = null; + for (Content c : message.getContents()) { + if (c.isFile()) { + file = c.getFilePath(); + LinphoneManager.getInstance() + .getMediaScanner() + .scanFile( + new File(file), + new MediaScannerListener() { + @Override + public void onMediaScanned( + String path, Uri uri) { + createNotification( + cr, + contact, + from, + textMessage, + message.getTime(), + uri, + FileUtils.getMimeFromFile(path)); + } + }); + break; + } + } + + if (file == null) { + createNotification( + cr, contact, from, textMessage, message.getTime(), null, null); + } + } + }; + + Core core = LinphoneManager.getCore(); + if (core != null) { + core.addListener(mListener); + } } public void destroy() { mNM.cancelAll(); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.removeListener(mListener); + } } public void startForeground() { @@ -111,7 +213,7 @@ public class NotificationsManager { mCurrentForegroundServiceNotification = SERVICE_NOTIF_ID; } - public void startForeground(Notification notification, int id) { + private void startForeground(Notification notification, int id) { LinphoneService.instance().startForeground(id, notification); mCurrentForegroundServiceNotification = id; } @@ -128,6 +230,13 @@ public class NotificationsManager { } } + public void setCurrentlyDisplayedChatRoom(String address) { + mCurrentChatRoomAddress = address; + if (address != null) { + resetMessageNotifCount(address); + } + } + public void sendNotification(int id, Notification notif) { mNM.notify(id, notif); } @@ -181,9 +290,8 @@ public class NotificationsManager { notif.setMyself(LinphoneUtils.getAddressDisplayName(localIdentity)); notif.setLocalIdentity(localIdentity.asString()); - Intent notifIntent = new Intent(mContext, LinphoneActivity.class); - notifIntent.putExtra("GoToChat", true); - notifIntent.putExtra("ChatContactSipUri", conferenceAddress); + Intent notifIntent = new Intent(mContext, ChatActivity.class); + notifIntent.putExtra("RemoteSipUri", conferenceAddress); notifIntent.putExtra("LocalSipUri", localIdentity.asStringUriOnly()); PendingIntent pendingIntent = PendingIntent.getActivity( @@ -234,9 +342,8 @@ public class NotificationsManager { notif.setMyself(LinphoneUtils.getAddressDisplayName(localIdentity)); notif.setLocalIdentity(localIdentity.asString()); - Intent notifIntent = new Intent(mContext, LinphoneActivity.class); - notifIntent.putExtra("GoToChat", true); - notifIntent.putExtra("ChatContactSipUri", fromSipUri); + Intent notifIntent = new Intent(mContext, ChatActivity.class); + notifIntent.putExtra("RemoteSipUri", fromSipUri); notifIntent.putExtra("LocalSipUri", localIdentity.asStringUriOnly()); PendingIntent pendingIntent = PendingIntent.getActivity( @@ -252,8 +359,7 @@ public class NotificationsManager { } public void displayMissedCallNotification(Call call) { - Intent missedCallNotifIntent = new Intent(mContext, LinphoneActivity.class); - missedCallNotifIntent.putExtra("GoToHistory", true); + Intent missedCallNotifIntent = new Intent(mContext, HistoryActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity( mContext, @@ -261,8 +367,7 @@ public class NotificationsManager { missedCallNotifIntent, PendingIntent.FLAG_UPDATE_CURRENT); - int missedCallCount = - LinphoneManager.getLcIfManagerNotDestroyedOrNull().getMissedCallsCount(); + int missedCallCount = LinphoneManager.getCore().getMissedCallsCount(); String body; if (missedCallCount > 1) { body = @@ -411,9 +516,8 @@ public class NotificationsManager { return null; } - public void displayInappNotification(String message) { - Intent notifIntent = new Intent(mContext, LinphoneActivity.class); - notifIntent.putExtra("GoToInapp", true); + /*public void displayInappNotification(String message) { + Intent notifIntent = new Intent(mContext, InAppPurchaseActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity( mContext, IN_APP_NOTIF_ID, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT); @@ -425,9 +529,67 @@ public class NotificationsManager { message, pendingIntent); sendNotification(IN_APP_NOTIF_ID, notif); - } + }*/ public void dismissNotification(int notifId) { mNM.cancel(notifId); } + + private void createNotification( + ChatRoom cr, + LinphoneContact contact, + Address from, + String textMessage, + long time, + Uri file, + String mime) { + if (cr.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { + if (contact != null) { + displayMessageNotification( + cr.getPeerAddress().asStringUriOnly(), + contact.getFullName(), + contact.getThumbnailUri(), + textMessage, + cr.getLocalAddress(), + time, + file, + mime); + } else { + displayMessageNotification( + cr.getPeerAddress().asStringUriOnly(), + from.getUsername(), + null, + textMessage, + cr.getLocalAddress(), + time, + file, + mime); + } + } else { + String subject = cr.getSubject(); + if (contact != null) { + displayGroupChatMessageNotification( + subject, + cr.getPeerAddress().asStringUriOnly(), + contact.getFullName(), + contact.getThumbnailUri(), + textMessage, + cr.getLocalAddress(), + time, + file, + mime); + } else { + displayGroupChatMessageNotification( + subject, + cr.getPeerAddress().asStringUriOnly(), + from.getUsername(), + null, + textMessage, + cr.getLocalAddress(), + time, + file, + mime); + } + } + } } diff --git a/app/src/main/java/org/linphone/purchase/InAppPurchaseActivity.java b/app/src/main/java/org/linphone/purchase/InAppPurchaseActivity.java index b78d5f793..9a138b98e 100644 --- a/app/src/main/java/org/linphone/purchase/InAppPurchaseActivity.java +++ b/app/src/main/java/org/linphone/purchase/InAppPurchaseActivity.java @@ -42,7 +42,6 @@ public class InAppPurchaseActivity extends Activity private static InAppPurchaseActivity sInstance; private InAppPurchaseHelper mInAppPurchaseHelper; - private ImageView mCancel, mBack; private ProgressBar mInProgress; private List mPurchasedItems; @@ -63,10 +62,10 @@ public class InAppPurchaseActivity extends Activity mInProgress = findViewById(R.id.purchaseItemsFetchInProgress); mInProgress.setVisibility(View.VISIBLE); - mBack = findViewById(R.id.back); + ImageView mBack = findViewById(R.id.back); mBack.setOnClickListener(this); mBack.setVisibility(View.INVISIBLE); - mCancel = findViewById(R.id.cancel); + ImageView mCancel = findViewById(R.id.cancel); mCancel.setOnClickListener(this); sInstance = this; @@ -168,9 +167,7 @@ public class InAppPurchaseActivity extends Activity xmlRpcHelper.updateAccountExpireAsync( new XmlRpcListenerBase() { @Override - public void onAccountExpireUpdated() { - // TODO - } + public void onAccountExpireUpdated() {} }, LinphonePreferences.instance().getAccountUsername(0), LinphonePreferences.instance().getAccountHa1(0), diff --git a/app/src/main/java/org/linphone/purchase/InAppPurchaseFragment.java b/app/src/main/java/org/linphone/purchase/InAppPurchaseFragment.java index 5792e11ea..950dc4053 100644 --- a/app/src/main/java/org/linphone/purchase/InAppPurchaseFragment.java +++ b/app/src/main/java/org/linphone/purchase/InAppPurchaseFragment.java @@ -36,12 +36,10 @@ import org.linphone.core.ProxyConfig; import org.linphone.settings.LinphonePreferences; public class InAppPurchaseFragment extends Fragment implements View.OnClickListener { - private LinearLayout mUsernameLayout; - private EditText mUsername, mEmail; + private EditText mUsername; private TextView mErrorMessage; private boolean mUsernameOk = false, mEmailOk = false; - private String mDefaultUsername, mDefaultEmail; private Button mBuyItemButton; @Override @@ -58,13 +56,13 @@ public class InAppPurchaseFragment extends Fragment implements View.OnClickListe displayBuySubscriptionButton(item); - mDefaultEmail = InAppPurchaseActivity.instance().getGmailAccount(); - mDefaultUsername = + String mDefaultEmail = InAppPurchaseActivity.instance().getGmailAccount(); + String mDefaultUsername = LinphonePreferences.instance() .getAccountUsername( LinphonePreferences.instance().getDefaultAccountIndex()); - mUsernameLayout = view.findViewById(R.id.username_layout); + LinearLayout mUsernameLayout = view.findViewById(R.id.username_layout); mUsername = view.findViewById(R.id.username); if (!getResources().getBoolean(R.bool.hide_username_in_inapp)) { mUsernameLayout.setVisibility(View.VISIBLE); @@ -81,7 +79,7 @@ public class InAppPurchaseFragment extends Fragment implements View.OnClickListe } } - mEmail = view.findViewById(R.id.email); + EditText mEmail = view.findViewById(R.id.email); if (mDefaultEmail != null) { mEmail.setText(mDefaultEmail); mEmailOk = true; @@ -116,7 +114,7 @@ public class InAppPurchaseFragment extends Fragment implements View.OnClickListe } private boolean isUsernameCorrect(String username) { - ProxyConfig lpc = LinphoneManager.getLc().createProxyConfig(); + ProxyConfig lpc = LinphoneManager.getCore().createProxyConfig(); return lpc.isPhoneNumber(username); } @@ -135,7 +133,7 @@ public class InAppPurchaseFragment extends Fragment implements View.OnClickListe private String getUsername() { String username = this.mUsername.getText().toString(); - ProxyConfig lpc = LinphoneManager.getLc().createProxyConfig(); + ProxyConfig lpc = LinphoneManager.getCore().createProxyConfig(); username = lpc.normalizePhoneNumber(username); return username.toLowerCase(Locale.getDefault()); } diff --git a/app/src/main/java/org/linphone/purchase/InAppPurchaseHelper.java b/app/src/main/java/org/linphone/purchase/InAppPurchaseHelper.java index 517c17ff4..fb80adb80 100644 --- a/app/src/main/java/org/linphone/purchase/InAppPurchaseHelper.java +++ b/app/src/main/java/org/linphone/purchase/InAppPurchaseHelper.java @@ -43,33 +43,33 @@ import org.linphone.xmlrpc.XmlRpcHelper; import org.linphone.xmlrpc.XmlRpcListenerBase; class InAppPurchaseHelper { - public static final int API_VERSION = 3; - public static final int ACTIVITY_RESULT_CODE_PURCHASE_ITEM = 11089; + private static final int API_VERSION = 3; + private static final int ACTIVITY_RESULT_CODE_PURCHASE_ITEM = 11089; - public static final String SKU_DETAILS_ITEM_LIST = "ITEM_ID_LIST"; - public static final String SKU_DETAILS_LIST = "DETAILS_LIST"; - public static final String SKU_DETAILS_PRODUCT_ID = "productId"; - public static final String SKU_DETAILS_PRICE = "price"; - public static final String SKU_DETAILS_TITLE = "title"; - public static final String SKU_DETAILS_DESC = "description"; + private static final String SKU_DETAILS_ITEM_LIST = "ITEM_ID_LIST"; + private static final String SKU_DETAILS_LIST = "DETAILS_LIST"; + private static final String SKU_DETAILS_PRODUCT_ID = "productId"; + private static final String SKU_DETAILS_PRICE = "price"; + private static final String SKU_DETAILS_TITLE = "title"; + private static final String SKU_DETAILS_DESC = "description"; public static final String ITEM_TYPE_INAPP = "inapp"; - public static final String ITEM_TYPE_SUBS = "subs"; + private static final String ITEM_TYPE_SUBS = "subs"; - public static final int RESPONSE_RESULT_OK = 0; - public static final int RESULT_USER_CANCELED = 1; - public static final int RESULT_SERVICE_UNAVAILABLE = 2; - public static final int RESULT_BILLING_UNAVAILABLE = 3; - public static final int RESULT_ITEM_UNAVAILABLE = 4; - public static final int RESULT_DEVELOPER_ERROR = 5; - public static final int RESULT_ERROR = 6; - public static final int RESULT_ITEM_ALREADY_OWNED = 7; - public static final int RESULT_ITEM_NOT_OWNED = 8; + private static final int RESPONSE_RESULT_OK = 0; + private static final int RESULT_USER_CANCELED = 1; + private static final int RESULT_SERVICE_UNAVAILABLE = 2; + private static final int RESULT_BILLING_UNAVAILABLE = 3; + private static final int RESULT_ITEM_UNAVAILABLE = 4; + private static final int RESULT_DEVELOPER_ERROR = 5; + private static final int RESULT_ERROR = 6; + private static final int RESULT_ITEM_ALREADY_OWNED = 7; + private static final int RESULT_ITEM_NOT_OWNED = 8; - public static final String RESPONSE_CODE = "RESPONSE_CODE"; - public static final String RESPONSE_BUY_INTENT = "BUY_INTENT"; - public static final String RESPONSE_INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA"; - public static final String RESPONSE_INAPP_SIGNATURE = "INAPP_DATA_SIGNATURE"; + private static final String RESPONSE_CODE = "RESPONSE_CODE"; + private static final String RESPONSE_BUY_INTENT = "BUY_INTENT"; + private static final String RESPONSE_INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA"; + private static final String RESPONSE_INAPP_SIGNATURE = "INAPP_DATA_SIGNATURE"; public static final String RESPONSE_INAPP_ITEM_LIST = "INAPP_PURCHASE_ITEM_LIST"; public static final String RESPONSE_INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST"; public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST"; @@ -83,11 +83,11 @@ class InAppPurchaseHelper { public static final String PURCHASE_DETAILS_PAYLOAD = "developerPayload"; public static final String PURCHASE_DETAILS_PURCHASE_TOKEN = "purchaseToken"; - public static final String CLIENT_ERROR_SUBSCRIPTION_PURCHASE_NOT_AVAILABLE = + private static final String CLIENT_ERROR_SUBSCRIPTION_PURCHASE_NOT_AVAILABLE = "SUBSCRIPTION_PURCHASE_NOT_AVAILABLE"; - public static final String CLIENT_ERROR_BIND_TO_BILLING_SERVICE_FAILED = + private static final String CLIENT_ERROR_BIND_TO_BILLING_SERVICE_FAILED = "BIND_TO_BILLING_SERVICE_FAILED"; - public static final String CLIENT_ERROR_BILLING_SERVICE_UNAVAILABLE = + private static final String CLIENT_ERROR_BILLING_SERVICE_UNAVAILABLE = "BILLING_SERVICE_UNAVAILABLE"; private final Context mContext; @@ -333,7 +333,7 @@ class InAppPurchaseHelper { } private Purchasable verifySignature() { - // TODO FIXME rework to be async + // TODO rework to be async /*XmlRpcHelper helper = new XmlRpcHelper(); if (helper.verifySignature(payload, signature)) { try { diff --git a/app/src/main/java/org/linphone/purchase/InAppPurchaseListFragment.java b/app/src/main/java/org/linphone/purchase/InAppPurchaseListFragment.java index 1bb2b0ab2..b0aea0553 100644 --- a/app/src/main/java/org/linphone/purchase/InAppPurchaseListFragment.java +++ b/app/src/main/java/org/linphone/purchase/InAppPurchaseListFragment.java @@ -32,7 +32,6 @@ import java.util.List; import org.linphone.R; public class InAppPurchaseListFragment extends Fragment implements AdapterView.OnItemClickListener { - private ListView mInappList; private LayoutInflater mInflater; private List mPurchasableItems; @@ -43,7 +42,7 @@ public class InAppPurchaseListFragment extends Fragment implements AdapterView.O View view = inflater.inflate(R.layout.in_app_list, container, false); mPurchasableItems = InAppPurchaseActivity.instance().getPurchasedItems(); - mInappList = view.findViewById(R.id.inapp_list); + ListView mInappList = view.findViewById(R.id.inapp_list); if (mPurchasableItems != null) { mInappList.setAdapter(new InAppListAdapter()); diff --git a/app/src/main/java/org/linphone/purchase/InAppPurchaseListenerBase.java b/app/src/main/java/org/linphone/purchase/InAppPurchaseListenerBase.java index 774f1a312..729040372 100644 --- a/app/src/main/java/org/linphone/purchase/InAppPurchaseListenerBase.java +++ b/app/src/main/java/org/linphone/purchase/InAppPurchaseListenerBase.java @@ -23,44 +23,23 @@ import java.util.ArrayList; public class InAppPurchaseListenerBase implements InAppPurchaseListener { @Override - public void onServiceAvailableForQueries() { - // TODO Auto-generated method stub - - } + public void onServiceAvailableForQueries() {} @Override - public void onAvailableItemsForPurchaseQueryFinished(ArrayList items) { - // TODO Auto-generated method stub - - } + public void onAvailableItemsForPurchaseQueryFinished(ArrayList items) {} @Override - public void onPurchasedItemsQueryFinished(ArrayList items) { - // TODO Auto-generated method stub - - } + public void onPurchasedItemsQueryFinished(ArrayList items) {} @Override - public void onPurchasedItemConfirmationQueryFinished(boolean success) { - // TODO Auto-generated method stub - - } + public void onPurchasedItemConfirmationQueryFinished(boolean success) {} @Override - public void onRecoverAccountSuccessful() { - // TODO Auto-generated method stub - - } + public void onRecoverAccountSuccessful() {} @Override - public void onActivateAccountSuccessful(boolean success) { - // TODO Auto-generated method stub - - } + public void onActivateAccountSuccessful(boolean success) {} @Override - public void onError(String error) { - // TODO Auto-generated method stub - - } + public void onError(String error) {} } diff --git a/app/src/main/java/org/linphone/receivers/AccountEnableReceiver.java b/app/src/main/java/org/linphone/receivers/AccountEnableReceiver.java index 7f856ee03..47e5c3b43 100644 --- a/app/src/main/java/org/linphone/receivers/AccountEnableReceiver.java +++ b/app/src/main/java/org/linphone/receivers/AccountEnableReceiver.java @@ -34,12 +34,7 @@ public class AccountEnableReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { int prefsAccountIndex = (int) (long) intent.getLongExtra(FIELD_ID, -1); boolean enable = intent.getBooleanExtra(FIELD_ACTIVE, true); - Log.i( - TAG, - "Received broadcast for index=" - + Integer.toString(prefsAccountIndex) - + ",enable=" - + Boolean.toString(enable)); + Log.i(TAG, "Received broadcast for index=" + prefsAccountIndex + ",enable=" + enable); if (prefsAccountIndex < 0 || prefsAccountIndex >= LinphonePreferences.instance().getAccountCount()) return; LinphonePreferences.instance().setAccountEnabled(prefsAccountIndex, enable); diff --git a/app/src/main/java/org/linphone/receivers/BluetoothManager.java b/app/src/main/java/org/linphone/receivers/BluetoothManager.java index f5c7e0411..f8fc814fb 100644 --- a/app/src/main/java/org/linphone/receivers/BluetoothManager.java +++ b/app/src/main/java/org/linphone/receivers/BluetoothManager.java @@ -31,12 +31,9 @@ import android.media.AudioManager; import java.util.List; import org.linphone.LinphoneManager; import org.linphone.LinphoneService; -import org.linphone.call.CallActivity; import org.linphone.core.tools.Log; public class BluetoothManager extends BroadcastReceiver { - private static BluetoothManager sInstance; - private Context mContext; private AudioManager mAudioManager; private BluetoothAdapter mBluetoothAdapter; @@ -53,17 +50,17 @@ public class BluetoothManager extends BroadcastReceiver { "BluetoothManager", "[Bluetooth] Manager tried to init but LinphoneService not ready yet..."); } - sInstance = this; + initBluetooth(); } public static BluetoothManager getInstance() { - if (sInstance == null) { - sInstance = new BluetoothManager(); + if (LinphoneService.isReady()) { + return LinphoneService.instance().getBluetoothManager(); } - return sInstance; + return null; } - public void initBluetooth() { + private void initBluetooth() { if (!ensureInit()) { android.util.Log.w( "BluetoothManager", @@ -118,7 +115,7 @@ public class BluetoothManager extends BroadcastReceiver { mIsBluetoothConnected = false; android.util.Log.d( "BluetoothManager", "[Bluetooth] Headset disconnected"); - LinphoneManager.getInstance().routeAudioToReceiver(); + LinphoneManager.getAudioManager().routeAudioToEarPiece(); } } }; @@ -134,9 +131,7 @@ public class BluetoothManager extends BroadcastReceiver { } private void refreshCallView() { - if (CallActivity.isInstanciated()) { - CallActivity.instance().refreshInCallActions(); - } + LinphoneManager.getCallManager().refreshInCallActions(); } private boolean ensureInit() { @@ -283,8 +278,8 @@ public class BluetoothManager extends BroadcastReceiver { android.util.Log.w("BluetoothManager", "[Bluetooth] Stopped!"); - if (LinphoneManager.isInstanciated()) { - LinphoneManager.getInstance().routeAudioToReceiver(); + if (LinphoneService.isReady()) { + LinphoneManager.getAudioManager().routeAudioToEarPiece(); } refreshCallView(); @@ -306,7 +301,7 @@ public class BluetoothManager extends BroadcastReceiver { } public void onReceive(Context context, Intent intent) { - if (!LinphoneManager.isInstanciated()) return; + if (!LinphoneService.isReady()) return; String action = intent.getAction(); if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(action)) { diff --git a/app/src/main/java/org/linphone/receivers/BootReceiver.java b/app/src/main/java/org/linphone/receivers/BootReceiver.java index e10cec238..3ca1b1500 100644 --- a/app/src/main/java/org/linphone/receivers/BootReceiver.java +++ b/app/src/main/java/org/linphone/receivers/BootReceiver.java @@ -22,7 +22,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import org.linphone.LinphoneManager; import org.linphone.LinphoneService; import org.linphone.compatibility.Compatibility; import org.linphone.settings.LinphonePreferences; @@ -31,21 +30,21 @@ public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - LinphonePreferences.instance().setContext(context); if (intent.getAction().equalsIgnoreCase(Intent.ACTION_SHUTDOWN)) { android.util.Log.d( "LinphoneBootReceiver", "Device is shutting down, destroying Core to unregister"); - LinphoneManager.destroy(); + context.stopService( + new Intent(Intent.ACTION_MAIN).setClass(context, LinphoneService.class)); } else { boolean autostart = LinphonePreferences.instance().isAutoStartEnabled(); android.util.Log.i( "LinphoneBootReceiver", "Device is starting, auto_start is " + autostart); if (autostart && !LinphoneService.isReady()) { - Intent lLinphoneServiceIntent = new Intent(Intent.ACTION_MAIN); - lLinphoneServiceIntent.setClass(context, LinphoneService.class); - lLinphoneServiceIntent.putExtra("ForceStartForeground", true); - Compatibility.startService(context, lLinphoneServiceIntent); + Intent linphoneServiceIntent = new Intent(Intent.ACTION_MAIN); + linphoneServiceIntent.setClass(context, LinphoneService.class); + linphoneServiceIntent.putExtra("ForceStartForeground", true); + Compatibility.startService(context, linphoneServiceIntent); } } } diff --git a/app/src/main/java/org/linphone/receivers/HookReceiver.java b/app/src/main/java/org/linphone/receivers/HookReceiver.java index f58936667..b4268028f 100644 --- a/app/src/main/java/org/linphone/receivers/HookReceiver.java +++ b/app/src/main/java/org/linphone/receivers/HookReceiver.java @@ -2,7 +2,7 @@ package org.linphone.receivers; /* HookReceiver.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -31,19 +31,14 @@ public class HookReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { if (isOrderedBroadcast()) abortBroadcast(); Bundle extras = intent.getExtras(); - boolean b = extras.getBoolean("hookoff"); - if (b) { - // handset on - Log.i(" ======>>>>>> HookReceiver - handset ON"); - LinphoneManager.getInstance().enableSpeaker(false); - if (!LinphoneManager.getInstance().isHansetModeOn()) - LinphoneManager.getInstance().setHandsetMode(true); + boolean handsetOn = extras.getBoolean("hookoff"); + Log.i("[Hook Receiver] Handset " + handsetOn); + LinphoneManager.getCallManager().setHandsetMode(handsetOn); + if (handsetOn) { + LinphoneManager.getAudioManager().routeAudioToEarPiece(); } else { - // handset off - Log.i(" ======>>>>>> HookReceiver - handset OFF"); - LinphoneManager.getInstance().enableSpeaker(true); - LinphoneManager.getInstance().setHandsetMode(false); + LinphoneManager.getAudioManager().routeAudioToSpeaker(); } } } diff --git a/app/src/main/java/org/linphone/receivers/PhoneStateChangedReceiver.java b/app/src/main/java/org/linphone/receivers/PhoneStateChangedReceiver.java index 6a988004d..d01dc6d1f 100644 --- a/app/src/main/java/org/linphone/receivers/PhoneStateChangedReceiver.java +++ b/app/src/main/java/org/linphone/receivers/PhoneStateChangedReceiver.java @@ -24,6 +24,7 @@ import android.content.Context; import android.content.Intent; import android.telephony.TelephonyManager; import org.linphone.LinphoneManager; +import org.linphone.LinphoneService; import org.linphone.core.Core; /** Pause current SIP calls when GSM phone rings or is active. */ @@ -32,14 +33,14 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { final String extraState = intent.getStringExtra(TelephonyManager.EXTRA_STATE); - if (!LinphoneManager.isInstanciated()) return; + if (!LinphoneService.isReady()) return; if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(extraState) || TelephonyManager.EXTRA_STATE_RINGING.equals(extraState)) { LinphoneManager.getInstance().setCallGsmON(true); - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.pauseAllCalls(); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.pauseAllCalls(); } } else if (TelephonyManager.EXTRA_STATE_IDLE.equals(extraState)) { LinphoneManager.getInstance().setCallGsmON(false); diff --git a/app/src/main/java/org/linphone/recording/Recording.java b/app/src/main/java/org/linphone/recording/Recording.java index 7e178695d..3e94047ca 100644 --- a/app/src/main/java/org/linphone/recording/Recording.java +++ b/app/src/main/java/org/linphone/recording/Recording.java @@ -71,7 +71,7 @@ class Recording implements PlayerListener, Comparable { } }; - mPlayer = LinphoneManager.getLc().createLocalPlayer(null, null, null); + mPlayer = LinphoneManager.getCore().createLocalPlayer(null, null, null); mPlayer.addListener(this); } diff --git a/app/src/main/java/org/linphone/recording/RecordingsFragment.java b/app/src/main/java/org/linphone/recording/RecordingsActivity.java similarity index 62% rename from app/src/main/java/org/linphone/recording/RecordingsFragment.java rename to app/src/main/java/org/linphone/recording/RecordingsActivity.java index 63251c904..05f0fb334 100644 --- a/app/src/main/java/org/linphone/recording/RecordingsFragment.java +++ b/app/src/main/java/org/linphone/recording/RecordingsActivity.java @@ -1,8 +1,8 @@ package org.linphone.recording; /* -RecordingsFragment.java -Copyright (C) 2018 Belledonne Communications, Grenoble, France +RecordingsActivity.java +Copyright (C) 2019 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 @@ -19,14 +19,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import android.app.Fragment; -import android.content.Context; +import android.Manifest; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; @@ -35,63 +34,135 @@ import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; -import org.linphone.fragments.FragmentsAvailable; +import org.linphone.activities.MainActivity; import org.linphone.utils.FileUtils; import org.linphone.utils.SelectableHelper; -public class RecordingsFragment extends Fragment - implements AdapterView.OnItemClickListener, - RecordingViewHolder.ClickListener, - SelectableHelper.DeleteListener { +public class RecordingsActivity extends MainActivity + implements SelectableHelper.DeleteListener, RecordingViewHolder.ClickListener { private RecyclerView mRecordingList; private List mRecordings; private TextView mNoRecordings; private RecordingsAdapter mRecordingsAdapter; - private LinearLayoutManager mLayoutManager; - private Context mContext; private SelectableHelper mSelectableHelper; - private ImageView mBackButton; @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.recordings_list, container, false); + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mOnBackPressGoHome = false; - mContext = getActivity().getApplicationContext(); - mSelectableHelper = new SelectableHelper(view, this); + // Uses the fragment container layout to inflate the about view instead of using a fragment + View recordingsView = + LayoutInflater.from(this).inflate(R.layout.recordings_list, null, false); + LinearLayout fragmentContainer = findViewById(R.id.fragmentContainer); + LinearLayout.LayoutParams params = + new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + fragmentContainer.addView(recordingsView, params); - mRecordingList = view.findViewById(R.id.recording_list); - mNoRecordings = view.findViewById(R.id.no_recordings); - - mBackButton = view.findViewById(R.id.back); - if (getResources().getBoolean(R.bool.isTablet)) { - mBackButton.setVisibility(View.INVISIBLE); - } else { - mBackButton.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View view) { - LinphoneActivity.instance().popBackStack(); - } - }); + if (isTablet()) { + findViewById(R.id.fragmentContainer2).setVisibility(View.GONE); } - mLayoutManager = new LinearLayoutManager(mContext); + ImageView backButton = findViewById(R.id.back); + backButton.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + goBack(); + } + }); + + mSelectableHelper = new SelectableHelper(findViewById(R.id.root_layout), this); + + mRecordingList = findViewById(R.id.recording_list); + mNoRecordings = findViewById(R.id.no_recordings); + + LinearLayoutManager mLayoutManager = new LinearLayoutManager(this); mRecordingList.setLayoutManager(mLayoutManager); // Divider between items DividerItemDecoration dividerItemDecoration = - new DividerItemDecoration( - mRecordingList.getContext(), mLayoutManager.getOrientation()); - dividerItemDecoration.setDrawable(mContext.getResources().getDrawable(R.drawable.divider)); + new DividerItemDecoration(this, mLayoutManager.getOrientation()); + dividerItemDecoration.setDrawable(getResources().getDrawable(R.drawable.divider)); mRecordingList.addItemDecoration(dividerItemDecoration); mRecordings = new ArrayList<>(); - return view; + mPermissionsToHave = + new String[] { + Manifest.permission.READ_EXTERNAL_STORAGE, + }; + } + + @Override + protected void onResume() { + super.onResume(); + + hideTopBar(); + hideTabBar(); + + LinphoneManager.getAudioManager().setAudioManagerModeNormal(); + LinphoneManager.getAudioManager().routeAudioToSpeaker(); + + removeDeletedRecordings(); + searchForRecordings(); + + hideRecordingListAndDisplayMessageIfEmpty(); + mRecordingsAdapter = new RecordingsAdapter(this, mRecordings, this, mSelectableHelper); + mRecordingList.setAdapter(mRecordingsAdapter); + mSelectableHelper.setAdapter(mRecordingsAdapter); + mSelectableHelper.setDialogMessage(R.string.recordings_delete_dialog); + } + + @Override + protected void onPause() { + super.onPause(); + + LinphoneManager.getAudioManager().routeAudioToEarPiece(); + + // Close all opened mRecordings + for (Recording r : mRecordings) { + if (!r.isClosed()) { + if (r.isPlaying()) r.pause(); + r.close(); + } + } + } + + @Override + public void onDeleteSelection(Object[] objectsToDelete) { + int size = mRecordingsAdapter.getSelectedItemCount(); + for (int i = 0; i < size; i++) { + Recording record = (Recording) objectsToDelete[i]; + + if (record.isPlaying()) record.pause(); + record.close(); + + File recordingFile = new File(record.getRecordPath()); + if (recordingFile.delete()) { + mRecordings.remove(record); + } + } + hideRecordingListAndDisplayMessageIfEmpty(); + } + + @Override + public void onItemClicked(int position) { + if (mRecordingsAdapter.isEditionEnabled()) { + mRecordingsAdapter.toggleSelection(position); + } + } + + @Override + public boolean onItemLongClicked(int position) { + if (!mRecordingsAdapter.isEditionEnabled()) { + mSelectableHelper.enterEditionMode(); + } + mRecordingsAdapter.toggleSelection(position); + return true; } private void hideRecordingListAndDisplayMessageIfEmpty() { @@ -105,7 +176,7 @@ public class RecordingsFragment extends Fragment } private void removeDeletedRecordings() { - String recordingsDirectory = FileUtils.getRecordingsDirectory(mContext); + String recordingsDirectory = FileUtils.getRecordingsDirectory(this); File directory = new File(recordingsDirectory); if (directory.exists() && directory.isDirectory()) { @@ -129,11 +200,12 @@ public class RecordingsFragment extends Fragment } private void searchForRecordings() { - String recordingsDirectory = FileUtils.getRecordingsDirectory(mContext); + String recordingsDirectory = FileUtils.getRecordingsDirectory(this); File directory = new File(recordingsDirectory); if (directory.exists() && directory.isDirectory()) { File[] existingRecordings = directory.listFiles(); + if (existingRecordings == null) return; for (File f : existingRecordings) { boolean exists = false; @@ -146,7 +218,7 @@ public class RecordingsFragment extends Fragment if (!exists) { if (Recording.RECORD_PATTERN.matcher(f.getPath()).matches()) { - mRecordings.add(new Recording(mContext, f.getPath())); + mRecordings.add(new Recording(this, f.getPath())); } } } @@ -154,97 +226,4 @@ public class RecordingsFragment extends Fragment Collections.sort(mRecordings); } } - - @Override - public void onResume() { - super.onResume(); - - // This is necessary, without it you won't be able to remove mRecordings as you won't be - // allowed to. - LinphoneActivity.instance().checkAndRequestExternalStoragePermission(); - - LinphoneManager.getInstance().setAudioManagerModeNormal(); - LinphoneManager.getInstance().routeAudioToSpeaker(); - - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.RECORDING_LIST); - } - - removeDeletedRecordings(); - searchForRecordings(); - - hideRecordingListAndDisplayMessageIfEmpty(); - mRecordingsAdapter = - new RecordingsAdapter( - getActivity().getApplicationContext(), - mRecordings, - this, - mSelectableHelper); - mRecordingList.setAdapter(mRecordingsAdapter); - mSelectableHelper.setAdapter(mRecordingsAdapter); - mSelectableHelper.setDialogMessage(R.string.recordings_delete_dialog); - } - - @Override - public void onPause() { - super.onPause(); - - LinphoneManager.getInstance().routeAudioToReceiver(); - - // Close all opened mRecordings - for (Recording r : mRecordings) { - if (!r.isClosed()) { - if (r.isPlaying()) r.pause(); - r.close(); - } - } - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (mRecordingsAdapter.isEditionEnabled()) { - Recording record = mRecordings.get(position); - - if (record.isPlaying()) record.pause(); - record.close(); - - File recordingFile = new File(record.getRecordPath()); - if (recordingFile.delete()) { - mRecordings.remove(record); - } - } - } - - @Override - public void onItemClicked(int position) { - if (mRecordingsAdapter.isEditionEnabled()) { - mRecordingsAdapter.toggleSelection(position); - } - } - - @Override - public boolean onItemLongClicked(int position) { - if (!mRecordingsAdapter.isEditionEnabled()) { - mSelectableHelper.enterEditionMode(); - } - mRecordingsAdapter.toggleSelection(position); - return true; - } - - @Override - public void onDeleteSelection(Object[] objectsToDelete) { - int size = mRecordingsAdapter.getSelectedItemCount(); - for (int i = 0; i < size; i++) { - Recording record = (Recording) objectsToDelete[i]; - - if (record.isPlaying()) record.pause(); - record.close(); - - File recordingFile = new File(record.getRecordPath()); - if (recordingFile.delete()) { - mRecordings.remove(record); - } - } - hideRecordingListAndDisplayMessageIfEmpty(); - } } diff --git a/app/src/main/java/org/linphone/settings/AccountSettingsFragment.java b/app/src/main/java/org/linphone/settings/AccountSettingsFragment.java index e5671958d..4d7215dd7 100644 --- a/app/src/main/java/org/linphone/settings/AccountSettingsFragment.java +++ b/app/src/main/java/org/linphone/settings/AccountSettingsFragment.java @@ -19,7 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import android.app.Fragment; import android.content.Intent; import android.os.Bundle; import android.text.InputType; @@ -29,7 +28,6 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.assistant.PhoneAccountLinkingAssistantActivity; @@ -42,7 +40,6 @@ import org.linphone.core.NatPolicy; import org.linphone.core.ProxyConfig; import org.linphone.core.TransportType; import org.linphone.core.tools.Log; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.settings.widget.BasicSetting; import org.linphone.settings.widget.ListSetting; import org.linphone.settings.widget.SettingListenerBase; @@ -50,9 +47,8 @@ import org.linphone.settings.widget.SwitchSetting; import org.linphone.settings.widget.TextSetting; import org.linphone.utils.PushNotificationUtils; -public class AccountSettingsFragment extends Fragment { - protected View mRootView; - protected LinphonePreferences mPrefs; +public class AccountSettingsFragment extends SettingsFragment { + private View mRootView; private int mAccountIndex; private ProxyConfig mProxyConfig; private AuthInfo mAuthInfo; @@ -93,7 +89,7 @@ public class AccountSettingsFragment extends Fragment { } mProxyConfig = null; - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (mAccountIndex >= 0 && core != null) { ProxyConfig[] proxyConfigs = core.getProxyConfigList(); if (proxyConfigs.length > mAccountIndex) { @@ -117,14 +113,6 @@ public class AccountSettingsFragment extends Fragment { public void onResume() { super.onResume(); - mPrefs = LinphonePreferences.instance(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance() - .selectMenu( - FragmentsAvailable.SETTINGS_SUBLEVEL, - getString(R.string.pref_sipaccount)); - } - updateValues(); } @@ -132,7 +120,7 @@ public class AccountSettingsFragment extends Fragment { public void onPause() { super.onPause(); if (mIsNewlyCreatedAccount) { - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null && mProxyConfig != null && mAuthInfo != null) { core.addAuthInfo(mAuthInfo); core.addProxyConfig(mProxyConfig); @@ -143,7 +131,7 @@ public class AccountSettingsFragment extends Fragment { } } - protected void loadSettings() { + private void loadSettings() { mUsername = mRootView.findViewById(R.id.pref_username); mUserId = mRootView.findViewById(R.id.pref_auth_userid); @@ -188,7 +176,7 @@ public class AccountSettingsFragment extends Fragment { PushNotificationUtils.isAvailable(getActivity()) ? View.VISIBLE : View.GONE); mChangePassword = mRootView.findViewById(R.id.pref_change_password); - mChangePassword.setVisibility(View.GONE); // TODO + mChangePassword.setVisibility(View.GONE); // TODO add feature mDeleteAccount = mRootView.findViewById(R.id.pref_delete_account); @@ -198,7 +186,7 @@ public class AccountSettingsFragment extends Fragment { initTransportList(); } - protected void setListeners() { + private void setListeners() { mUsername.setListener( new SettingListenerBase() { @Override @@ -234,7 +222,7 @@ public class AccountSettingsFragment extends Fragment { if (mAuthInfo != null) { mAuthInfo.setUserid(newValue); - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null) { core.refreshRegisters(); } @@ -251,8 +239,7 @@ public class AccountSettingsFragment extends Fragment { if (mAuthInfo != null) { mAuthInfo.setHa1(null); mAuthInfo.setPassword(newValue); - - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null) { core.addAuthInfo(mAuthInfo); core.refreshRegisters(); @@ -338,7 +325,7 @@ public class AccountSettingsFragment extends Fragment { mProxyConfig.edit(); NatPolicy natPolicy = mProxyConfig.getNatPolicy(); if (natPolicy == null) { - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null) { natPolicy = core.createNatPolicy(); mProxyConfig.setNatPolicy(natPolicy); @@ -427,12 +414,13 @@ public class AccountSettingsFragment extends Fragment { @Override public void onBoolValueChanged(boolean newValue) { if (mProxyConfig != null) { - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null && newValue) { core.setDefaultProxyConfig(mProxyConfig); mUseAsDefault.setEnabled(false); } - LinphoneActivity.instance().refreshAccounts(); + // FIXME TODO + // LinphoneActivity.instance().refreshAccounts(); } else { Log.e("[Account Settings] No proxy config !"); } @@ -466,7 +454,7 @@ public class AccountSettingsFragment extends Fragment { NatPolicy natPolicy = mProxyConfig.getNatPolicy(); if (natPolicy == null) { - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null) { natPolicy = core.createNatPolicy(); mProxyConfig.setNatPolicy(natPolicy); @@ -531,7 +519,7 @@ public class AccountSettingsFragment extends Fragment { new SettingListenerBase() { @Override public void onClicked() { - // TODO + // TODO add feature } }); @@ -539,7 +527,7 @@ public class AccountSettingsFragment extends Fragment { new SettingListenerBase() { @Override public void onClicked() { - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null) { if (mProxyConfig != null) { core.removeProxyConfig(mProxyConfig); @@ -548,8 +536,9 @@ public class AccountSettingsFragment extends Fragment { core.removeAuthInfo(mAuthInfo); } } - LinphoneActivity.instance().displaySettings(); - LinphoneActivity.instance().refreshAccounts(); + // FIXME TODO + /*LinphoneActivity.instance().displaySettings(); + LinphoneActivity.instance().refreshAccounts();*/ } }); @@ -559,8 +548,7 @@ public class AccountSettingsFragment extends Fragment { public void onClicked() { Intent assistant = new Intent(); assistant.setClass( - LinphoneActivity.instance(), - PhoneAccountLinkingAssistantActivity.class); + getActivity(), PhoneAccountLinkingAssistantActivity.class); assistant.putExtra("AccountNumber", mAccountIndex); startActivity(assistant); } @@ -596,8 +584,8 @@ public class AccountSettingsFragment extends Fragment { }); } - protected void updateValues() { - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + private void updateValues() { + Core core = LinphoneManager.getCore(); if (core == null) return; // Create a proxy config if there is none @@ -645,8 +633,7 @@ public class AccountSettingsFragment extends Fragment { mDisable.setChecked(!mProxyConfig.registerEnabled()); - mUseAsDefault.setChecked( - core != null && mProxyConfig.equals(core.getDefaultProxyConfig())); + mUseAsDefault.setChecked(mProxyConfig.equals(core.getDefaultProxyConfig())); mUseAsDefault.setEnabled(!mUseAsDefault.isChecked()); mOutboundProxy.setChecked(mProxyConfig.getRoute() != null); diff --git a/app/src/main/java/org/linphone/settings/AdvancedSettingsFragment.java b/app/src/main/java/org/linphone/settings/AdvancedSettingsFragment.java index 97ba3d1be..9be6935ac 100644 --- a/app/src/main/java/org/linphone/settings/AdvancedSettingsFragment.java +++ b/app/src/main/java/org/linphone/settings/AdvancedSettingsFragment.java @@ -19,7 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -31,18 +30,16 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.annotation.Nullable; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneService; import org.linphone.R; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.settings.widget.BasicSetting; import org.linphone.settings.widget.SettingListenerBase; import org.linphone.settings.widget.SwitchSetting; import org.linphone.settings.widget.TextSetting; -public class AdvancedSettingsFragment extends Fragment { - protected View mRootView; - protected LinphonePreferences mPrefs; +public class AdvancedSettingsFragment extends SettingsFragment { + private View mRootView; + private LinphonePreferences mPrefs; private SwitchSetting mDebug, mJavaLogger, @@ -69,17 +66,11 @@ public class AdvancedSettingsFragment extends Fragment { super.onResume(); mPrefs = LinphonePreferences.instance(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance() - .selectMenu( - FragmentsAvailable.SETTINGS_SUBLEVEL, - getString(R.string.pref_advanced_title)); - } updateValues(); } - protected void loadSettings() { + private void loadSettings() { mDebug = mRootView.findViewById(R.id.pref_debug); mJavaLogger = mRootView.findViewById(R.id.pref_java_debug); @@ -108,7 +99,7 @@ public class AdvancedSettingsFragment extends Fragment { mDeviceName = mRootView.findViewById(R.id.pref_device_name); } - protected void setListeners() { + private void setListeners() { mDebug.setListener( new SettingListenerBase() { @Override @@ -159,6 +150,7 @@ public class AdvancedSettingsFragment extends Fragment { @Override public void onBoolValueChanged(boolean newValue) { mPrefs.enableDarkMode(newValue); + getActivity().recreate(); } }); @@ -190,7 +182,7 @@ public class AdvancedSettingsFragment extends Fragment { new SettingListenerBase() { @Override public void onClicked() { - Context context = LinphoneActivity.instance(); + Context context = getActivity(); Intent i = new Intent(); i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); i.addCategory(Intent.CATEGORY_DEFAULT); @@ -198,7 +190,10 @@ public class AdvancedSettingsFragment extends Fragment { i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - startActivityForResult(i, LinphoneActivity.ANDROID_APP_SETTINGS_ACTIVITY); + // FIXME TODO + // startActivityForResult(i, + // LinphoneActivity.ANDROID_APP_SETTINGS_ACTIVITY); + startActivity(i); } }); @@ -211,7 +206,7 @@ public class AdvancedSettingsFragment extends Fragment { }); } - protected void updateValues() { + private void updateValues() { mDebug.setChecked(mPrefs.isDebugEnabled()); mJavaLogger.setChecked(mPrefs.useJavaLogger()); @@ -230,7 +225,7 @@ public class AdvancedSettingsFragment extends Fragment { mUsername.setValue(mPrefs.getDefaultUsername()); - mDeviceName.setValue(mPrefs.getDeviceName(LinphoneActivity.instance())); + mDeviceName.setValue(mPrefs.getDeviceName(getActivity())); setListeners(); } diff --git a/app/src/main/java/org/linphone/settings/AudioSettingsFragment.java b/app/src/main/java/org/linphone/settings/AudioSettingsFragment.java index 4348fa8ce..272549878 100644 --- a/app/src/main/java/org/linphone/settings/AudioSettingsFragment.java +++ b/app/src/main/java/org/linphone/settings/AudioSettingsFragment.java @@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import android.Manifest; -import android.app.Fragment; import android.content.Context; import android.content.pm.PackageManager; import android.media.AudioManager; @@ -31,23 +30,21 @@ import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import androidx.annotation.Nullable; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.core.Core; import org.linphone.core.CoreListenerStub; import org.linphone.core.EcCalibratorStatus; import org.linphone.core.PayloadType; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.settings.widget.BasicSetting; import org.linphone.settings.widget.ListSetting; import org.linphone.settings.widget.SettingListenerBase; import org.linphone.settings.widget.SwitchSetting; import org.linphone.settings.widget.TextSetting; -public class AudioSettingsFragment extends Fragment { - protected View mRootView; - protected LinphonePreferences mPrefs; +public class AudioSettingsFragment extends SettingsFragment { + private View mRootView; + private LinphonePreferences mPrefs; private SwitchSetting mEchoCanceller, mAdaptiveRateControl; private TextSetting mMicGain, mSpeakerGain; @@ -71,17 +68,11 @@ public class AudioSettingsFragment extends Fragment { super.onResume(); mPrefs = LinphonePreferences.instance(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance() - .selectMenu( - FragmentsAvailable.SETTINGS_SUBLEVEL, - getString(R.string.pref_audio_title)); - } updateValues(); } - protected void loadSettings() { + private void loadSettings() { mEchoCanceller = mRootView.findViewById(R.id.pref_echo_cancellation); mAdaptiveRateControl = mRootView.findViewById(R.id.pref_adaptive_rate_control); @@ -101,7 +92,7 @@ public class AudioSettingsFragment extends Fragment { mAudioCodecs = mRootView.findViewById(R.id.pref_audio_codecs); } - protected void setListeners() { + private void setListeners() { mEchoCanceller.setListener( new SettingListenerBase() { @Override @@ -141,7 +132,7 @@ public class AudioSettingsFragment extends Fragment { int bitrate = Integer.valueOf(newValue); mPrefs.setCodecBitrateLimit(bitrate); - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); for (final PayloadType pt : core.getAudioPayloadTypes()) { if (pt.isVbr()) { pt.setNormalBitrate(bitrate); @@ -165,8 +156,9 @@ public class AudioSettingsFragment extends Fragment { if (recordAudio == PackageManager.PERMISSION_GRANTED) { startEchoCancellerCalibration(); } else { - LinphoneActivity.instance() - .checkAndRequestRecordAudioPermissionForEchoCanceller(); + ((SettingsActivity) getActivity()) + .requestPermissionIfNotGranted( + Manifest.permission.RECORD_AUDIO); } } }); @@ -182,20 +174,21 @@ public class AudioSettingsFragment extends Fragment { Manifest.permission.RECORD_AUDIO, getActivity().getPackageName()); if (recordAudio == PackageManager.PERMISSION_GRANTED) { - if (LinphoneManager.getInstance().getEchoTesterStatus()) { + if (LinphoneManager.getAudioManager().getEchoTesterStatus()) { stopEchoTester(); } else { startEchoTester(); } } else { - LinphoneActivity.instance() - .checkAndRequestRecordAudioPermissionsForEchoTester(); + ((SettingsActivity) getActivity()) + .requestPermissionIfNotGranted( + Manifest.permission.RECORD_AUDIO); } } }); } - protected void updateValues() { + private void updateValues() { mEchoCanceller.setChecked(mPrefs.echoCancellationEnabled()); mAdaptiveRateControl.setChecked(mPrefs.adaptiveRateControlEnabled()); @@ -220,7 +213,7 @@ public class AudioSettingsFragment extends Fragment { private void populateAudioCodecs() { mAudioCodecs.removeAllViews(); - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null) { for (final PayloadType pt : core.getAudioPayloadTypes()) { final SwitchSetting codec = new SwitchSetting(getActivity()); @@ -248,21 +241,19 @@ public class AudioSettingsFragment extends Fragment { } } - public void startEchoTester() { - if (LinphoneManager.getInstance().startEchoTester() > 0) { - mEchoTester.setSubtitle("Is running"); - } + private void startEchoTester() { + LinphoneManager.getAudioManager().startEchoTester(); + mEchoTester.setSubtitle("Is running"); } private void stopEchoTester() { - if (LinphoneManager.getInstance().stopEchoTester() > 0) { - mEchoTester.setSubtitle("Is stopped"); - } + LinphoneManager.getAudioManager().stopEchoTester(); + mEchoTester.setSubtitle("Is stopped"); } - public void startEchoCancellerCalibration() { - if (LinphoneManager.getInstance().getEchoTesterStatus()) stopEchoTester(); - LinphoneManager.getLc() + private void startEchoCancellerCalibration() { + if (LinphoneManager.getAudioManager().getEchoTesterStatus()) stopEchoTester(); + LinphoneManager.getCore() .addListener( new CoreListenerStub() { @Override @@ -270,7 +261,7 @@ public class AudioSettingsFragment extends Fragment { Core core, EcCalibratorStatus status, int delayMs) { if (status == EcCalibratorStatus.InProgress) return; core.removeListener(this); - LinphoneManager.getInstance().routeAudioToReceiver(); + LinphoneManager.getAudioManager().routeAudioToEarPiece(); if (status == EcCalibratorStatus.DoneNoEcho) { mEchoCalibration.setSubtitle(getString(R.string.no_echo)); @@ -289,6 +280,6 @@ public class AudioSettingsFragment extends Fragment { .setMode(AudioManager.MODE_NORMAL); } }); - LinphoneManager.getInstance().startEcCalibration(); + LinphoneManager.getAudioManager().startEcCalibration(); } } diff --git a/app/src/main/java/org/linphone/settings/CallSettingsFragment.java b/app/src/main/java/org/linphone/settings/CallSettingsFragment.java index a973c727d..23456a8da 100644 --- a/app/src/main/java/org/linphone/settings/CallSettingsFragment.java +++ b/app/src/main/java/org/linphone/settings/CallSettingsFragment.java @@ -19,7 +19,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import android.app.Fragment; +import android.Manifest; +import android.content.pm.PackageManager; import android.os.Bundle; import android.text.InputType; import android.view.LayoutInflater; @@ -28,21 +29,19 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.core.Core; import org.linphone.core.MediaEncryption; import org.linphone.core.tools.Log; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.settings.widget.ListSetting; import org.linphone.settings.widget.SettingListenerBase; import org.linphone.settings.widget.SwitchSetting; import org.linphone.settings.widget.TextSetting; -public class CallSettingsFragment extends Fragment { - protected View mRootView; - protected LinphonePreferences mPrefs; +public class CallSettingsFragment extends SettingsFragment { + private View mRootView; + private LinphonePreferences mPrefs; private SwitchSetting mDeviceRingtone, mVibrateIncomingCall, @@ -68,17 +67,11 @@ public class CallSettingsFragment extends Fragment { super.onResume(); mPrefs = LinphonePreferences.instance(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance() - .selectMenu( - FragmentsAvailable.SETTINGS_SUBLEVEL, - getString(R.string.pref_call_title)); - } updateValues(); } - protected void loadSettings() { + private void loadSettings() { mDeviceRingtone = mRootView.findViewById(R.id.pref_device_ringtone); mVibrateIncomingCall = mRootView.findViewById(R.id.pref_vibrate_on_incoming_calls); @@ -102,12 +95,24 @@ public class CallSettingsFragment extends Fragment { mAutoAnswerTime.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI); } - protected void setListeners() { + private void setListeners() { mDeviceRingtone.setListener( new SettingListenerBase() { @Override public void onBoolValueChanged(boolean newValue) { - mPrefs.enableDeviceRingtone(newValue); + int readExternalStorage = + getActivity() + .getPackageManager() + .checkPermission( + Manifest.permission.READ_EXTERNAL_STORAGE, + getActivity().getPackageName()); + if (readExternalStorage == PackageManager.PERMISSION_GRANTED) { + mPrefs.enableDeviceRingtone(newValue); + } else { + ((SettingsActivity) getActivity()) + .requestPermissionIfNotGranted( + Manifest.permission.READ_EXTERNAL_STORAGE); + } } }); @@ -193,7 +198,7 @@ public class CallSettingsFragment extends Fragment { }); } - protected void updateValues() { + private void updateValues() { mDeviceRingtone.setChecked(mPrefs.isDeviceRingtoneEnabled()); mVibrateIncomingCall.setChecked(mPrefs.isIncomingCallVibrationEnabled()); @@ -223,7 +228,7 @@ public class CallSettingsFragment extends Fragment { entries.add(getString(R.string.pref_none)); values.add(String.valueOf(MediaEncryption.None.toInt())); - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null && !getResources().getBoolean(R.bool.disable_all_security_features_for_markets)) { boolean hasZrtp = core.mediaEncryptionSupported(MediaEncryption.ZRTP); diff --git a/app/src/main/java/org/linphone/settings/ChatSettingsFragment.java b/app/src/main/java/org/linphone/settings/ChatSettingsFragment.java index 25db7cde1..a9ca7142f 100644 --- a/app/src/main/java/org/linphone/settings/ChatSettingsFragment.java +++ b/app/src/main/java/org/linphone/settings/ChatSettingsFragment.java @@ -19,7 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.os.Build; @@ -30,19 +29,17 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.annotation.Nullable; -import org.linphone.LinphoneActivity; import org.linphone.R; import org.linphone.core.tools.Log; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.mediastream.Version; import org.linphone.settings.widget.BasicSetting; import org.linphone.settings.widget.ListSetting; import org.linphone.settings.widget.SettingListenerBase; import org.linphone.settings.widget.TextSetting; -public class ChatSettingsFragment extends Fragment { - protected View mRootView; - protected LinphonePreferences mPrefs; +public class ChatSettingsFragment extends SettingsFragment { + private View mRootView; + private LinphonePreferences mPrefs; private TextSetting mSharingServer, mMaxSizeForAutoDownloadIncomingFiles; private BasicSetting mAndroidNotificationSettings; @@ -64,17 +61,11 @@ public class ChatSettingsFragment extends Fragment { super.onResume(); mPrefs = LinphonePreferences.instance(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance() - .selectMenu( - FragmentsAvailable.SETTINGS_SUBLEVEL, - getString(R.string.pref_chat_title)); - } updateValues(); } - protected void loadSettings() { + private void loadSettings() { mSharingServer = mRootView.findViewById(R.id.pref_image_sharing_server); mSharingServer.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI); @@ -86,7 +77,7 @@ public class ChatSettingsFragment extends Fragment { mAndroidNotificationSettings = mRootView.findViewById(R.id.pref_android_app_notif_settings); } - protected void setListeners() { + private void setListeners() { mSharingServer.setListener( new SettingListenerBase() { @Override @@ -126,7 +117,7 @@ public class ChatSettingsFragment extends Fragment { @Override public void onClicked() { if (Build.VERSION.SDK_INT >= Version.API26_O_80) { - Context context = LinphoneActivity.instance(); + Context context = getActivity(); Intent i = new Intent(); i.setAction(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS); i.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName()); @@ -143,7 +134,7 @@ public class ChatSettingsFragment extends Fragment { }); } - protected void updateValues() { + private void updateValues() { mSharingServer.setValue(mPrefs.getSharingPictureServerUrl()); updateAutoDownloadSettingsFromValue(mPrefs.getAutoDownloadFileMaxSize()); diff --git a/app/src/main/java/org/linphone/settings/LinphonePreferences.java b/app/src/main/java/org/linphone/settings/LinphonePreferences.java index ea21a8066..225aa4f02 100644 --- a/app/src/main/java/org/linphone/settings/LinphonePreferences.java +++ b/app/src/main/java/org/linphone/settings/LinphonePreferences.java @@ -29,8 +29,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; +import org.linphone.LinphoneService; import org.linphone.R; import org.linphone.compatibility.Compatibility; import org.linphone.core.Address; @@ -67,32 +67,37 @@ public class LinphonePreferences { return sInstance; } + public void destroy() { + mContext = null; + sInstance = null; + } + public void setContext(Context c) { mContext = c; mBasePath = mContext.getFilesDir().getAbsolutePath(); } private String getString(int key) { - if (mContext == null && LinphoneManager.isInstanciated()) { - mContext = LinphoneManager.getInstance().getContext(); + if (mContext == null && LinphoneService.isReady()) { + mContext = LinphoneService.instance(); } return mContext.getString(key); } private Core getLc() { - if (!LinphoneManager.isInstanciated()) return null; + if (!LinphoneService.isReady()) return null; - return LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + return LinphoneManager.getCore(); } public Config getConfig() { - Core lc = getLc(); - if (lc != null) { - return lc.getConfig(); + Core core = getLc(); + if (core != null) { + return core.getConfig(); } - if (!LinphoneManager.isInstanciated()) { + if (!LinphoneService.isReady()) { File linphonerc = new File(mBasePath + "/.linphonerc"); if (linphonerc.exists()) { return Factory.instance().createConfig(linphonerc.getAbsolutePath()); @@ -114,7 +119,7 @@ public class LinphonePreferences { return Factory.instance().createConfigFromString(text.toString()); } } else { - return Factory.instance().createConfig(LinphoneManager.getInstance().configFile); + return Factory.instance().createConfig(LinphoneManager.getInstance().getConfigFile()); } return null; } @@ -225,7 +230,7 @@ public class LinphonePreferences { } } - public boolean isAccountEnabled(int n) { + private boolean isAccountEnabled(int n) { return getProxyConfig(n).registerEnabled(); } // End of accounts settings @@ -575,8 +580,8 @@ public class LinphonePreferences { public void setPushNotificationEnabled(boolean enable) { getConfig().setBool("app", "push_notification", enable); - Core lc = getLc(); - if (lc == null) { + Core core = getLc(); + if (core == null) { return; } @@ -584,8 +589,8 @@ public class LinphonePreferences { // Add push infos to exisiting proxy configs String regId = getPushNotificationRegistrationID(); String appId = getString(R.string.gcm_defaultSenderId); - if (regId != null && lc.getProxyConfigList().length > 0) { - for (ProxyConfig lpc : lc.getProxyConfigList()) { + if (regId != null && core.getProxyConfigList().length > 0) { + for (ProxyConfig lpc : core.getProxyConfigList()) { if (lpc == null) continue; if (!lpc.isPushNotificationAllowed()) { lpc.edit(); @@ -621,11 +626,11 @@ public class LinphonePreferences { Log.i( "[Push Notification] Refreshing registers to ensure token is up to date: " + regId); - lc.refreshRegisters(); + core.refreshRegisters(); } } else { - if (lc.getProxyConfigList().length > 0) { - for (ProxyConfig lpc : lc.getProxyConfigList()) { + if (core.getProxyConfigList().length > 0) { + for (ProxyConfig lpc : core.getProxyConfigList()) { lpc.edit(); lpc.setContactUriParameters(null); lpc.done(); @@ -634,7 +639,7 @@ public class LinphonePreferences { "[Push Notification] infos removed from proxy config " + lpc.getIdentityAddress().asStringUriOnly()); } - lc.refreshRegisters(); + core.refreshRegisters(); } } } @@ -742,7 +747,7 @@ public class LinphonePreferences { if (getLc().tunnelAvailable()) { Tunnel tunnel = getLc().getTunnel(); if (mTunnelConfig == null) { - TunnelConfig servers[] = tunnel.getServers(); + TunnelConfig[] servers = tunnel.getServers(); if (servers.length > 0) { mTunnelConfig = servers[0]; } else { @@ -800,10 +805,6 @@ public class LinphonePreferences { // End of tunnel settings - public boolean isFirstRemoteProvisioning() { - return getConfig().getBool("app", "first_remote_provisioning", true); - } - public boolean adaptiveRateControlEnabled() { if (getLc() == null) return false; return getLc().adaptiveRateControlEnabled(); @@ -935,13 +936,7 @@ public class LinphonePreferences { } public void enableOverlay(boolean enable) { - getConfig() - .setBool( - "app", - "display_overlay", - enable - && LinphoneActivity.isInstanciated() - && LinphoneActivity.instance().checkAndRequestOverlayPermission()); + getConfig().setBool("app", "display_overlay", enable); } public boolean isDeviceRingtoneEnabled() { @@ -1025,9 +1020,6 @@ public class LinphonePreferences { public void enableDarkMode(boolean enable) { getConfig().setBool("app", "dark_mode", enable); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().recreate(); - } } public String getDeviceName(Context context) { diff --git a/app/src/main/java/org/linphone/settings/MenuSettingsFragment.java b/app/src/main/java/org/linphone/settings/MenuSettingsFragment.java new file mode 100644 index 000000000..f32ac1e8a --- /dev/null +++ b/app/src/main/java/org/linphone/settings/MenuSettingsFragment.java @@ -0,0 +1,223 @@ +package org.linphone.settings; + +/* +MenuSettingsFragment.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; +import androidx.annotation.Nullable; +import org.linphone.LinphoneManager; +import org.linphone.R; +import org.linphone.core.Core; +import org.linphone.core.ProxyConfig; +import org.linphone.settings.widget.BasicSetting; +import org.linphone.settings.widget.LedSetting; +import org.linphone.settings.widget.SettingListenerBase; +import org.linphone.utils.LinphoneUtils; + +public class MenuSettingsFragment extends SettingsFragment { + private View mRootView; + private BasicSetting mTunnel, mAudio, mVideo, mCall, mChat, mNetwork, mAdvanced; + private LinearLayout mAccounts; + private TextView mAccountsHeader; + + @Nullable + @Override + public View onCreateView( + LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { + mRootView = inflater.inflate(R.layout.settings, container, false); + + loadSettings(); + setListeners(); + + return mRootView; + } + + @Override + public void onResume() { + super.onResume(); + + updateValues(); + } + + private void loadSettings() { + mAccounts = mRootView.findViewById(R.id.accounts_settings_list); + mAccountsHeader = mRootView.findViewById(R.id.accounts_settings_list_header); + + mTunnel = mRootView.findViewById(R.id.pref_tunnel); + + mAudio = mRootView.findViewById(R.id.pref_audio); + + mVideo = mRootView.findViewById(R.id.pref_video); + + mCall = mRootView.findViewById(R.id.pref_call); + + mChat = mRootView.findViewById(R.id.pref_chat); + + mNetwork = mRootView.findViewById(R.id.pref_network); + + mAdvanced = mRootView.findViewById(R.id.pref_advanced); + } + + private void setListeners() { + mTunnel.setListener( + new SettingListenerBase() { + @Override + public void onClicked() { + ((SettingsActivity) getActivity()) + .showSettings( + new TunnelSettingsFragment(), + getString(R.string.pref_tunnel_title)); + } + }); + + mAudio.setListener( + new SettingListenerBase() { + @Override + public void onClicked() { + ((SettingsActivity) getActivity()) + .showSettings( + new AudioSettingsFragment(), + getString(R.string.pref_audio_title)); + } + }); + + mVideo.setListener( + new SettingListenerBase() { + @Override + public void onClicked() { + ((SettingsActivity) getActivity()) + .showSettings( + new VideoSettingsFragment(), + getString(R.string.pref_video_title)); + } + }); + + mCall.setListener( + new SettingListenerBase() { + @Override + public void onClicked() { + ((SettingsActivity) getActivity()) + .showSettings( + new CallSettingsFragment(), + getString(R.string.pref_call_title)); + } + }); + + mChat.setListener( + new SettingListenerBase() { + @Override + public void onClicked() { + ((SettingsActivity) getActivity()) + .showSettings( + new ChatSettingsFragment(), + getString(R.string.pref_chat_title)); + } + }); + + mNetwork.setListener( + new SettingListenerBase() { + @Override + public void onClicked() { + ((SettingsActivity) getActivity()) + .showSettings( + new NetworkSettingsFragment(), + getString(R.string.pref_network_title)); + } + }); + + mAdvanced.setListener( + new SettingListenerBase() { + @Override + public void onClicked() { + ((SettingsActivity) getActivity()) + .showSettings( + new AdvancedSettingsFragment(), + getString(R.string.pref_advanced_title)); + } + }); + } + + private void updateValues() { + Core core = LinphoneManager.getCore(); + if (core != null) { + mTunnel.setVisibility(core.tunnelAvailable() ? View.VISIBLE : View.GONE); + initAccounts(core); + } + + if (getResources().getBoolean(R.bool.hide_accounts)) { + mAccounts.setVisibility(View.GONE); + mAccountsHeader.setVisibility(View.GONE); + } + } + + private void initAccounts(Core core) { + mAccounts.removeAllViews(); + ProxyConfig[] proxyConfigs = core.getProxyConfigList(); + + if (proxyConfigs == null || proxyConfigs.length == 0) { + mAccountsHeader.setVisibility(View.GONE); + } else { + mAccountsHeader.setVisibility(View.VISIBLE); + int i = 0; + for (ProxyConfig proxyConfig : proxyConfigs) { + final LedSetting account = new LedSetting(getActivity()); + account.setTitle( + LinphoneUtils.getDisplayableAddress(proxyConfig.getIdentityAddress())); + + if (proxyConfig.equals(core.getDefaultProxyConfig())) { + account.setSubtitle(getString(R.string.default_account_flag)); + } + + switch (proxyConfig.getState()) { + case Ok: + account.setColor(LedSetting.Color.GREEN); + break; + case Failed: + account.setColor(LedSetting.Color.RED); + break; + case Progress: + account.setColor(LedSetting.Color.ORANGE); + break; + case None: + case Cleared: + account.setColor(LedSetting.Color.GRAY); + break; + } + + final int accountIndex = i; + account.setListener( + new SettingListenerBase() { + @Override + public void onClicked() { + ((SettingsActivity) getActivity()) + .showAccountSettings(accountIndex, true); + } + }); + + mAccounts.addView(account); + i += 1; + } + } + } +} diff --git a/app/src/main/java/org/linphone/settings/NetworkSettingsFragment.java b/app/src/main/java/org/linphone/settings/NetworkSettingsFragment.java index 870df4afe..2773b795f 100644 --- a/app/src/main/java/org/linphone/settings/NetworkSettingsFragment.java +++ b/app/src/main/java/org/linphone/settings/NetworkSettingsFragment.java @@ -19,7 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import android.app.Fragment; import android.content.Intent; import android.os.Bundle; import android.text.InputType; @@ -27,10 +26,8 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.annotation.Nullable; -import org.linphone.LinphoneActivity; import org.linphone.R; import org.linphone.core.tools.Log; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.settings.widget.BasicSetting; import org.linphone.settings.widget.SettingListenerBase; import org.linphone.settings.widget.SwitchSetting; @@ -38,9 +35,9 @@ import org.linphone.settings.widget.TextSetting; import org.linphone.utils.DeviceUtils; import org.linphone.utils.PushNotificationUtils; -public class NetworkSettingsFragment extends Fragment { - protected View mRootView; - protected LinphonePreferences mPrefs; +public class NetworkSettingsFragment extends SettingsFragment { + private View mRootView; + private LinphonePreferences mPrefs; private SwitchSetting mWifiOnly, mIpv6, mPush, mRandomPorts, mIce, mTurn; private TextSetting mSipPort, mStunServer, mTurnUsername, mTurnPassword; @@ -62,17 +59,11 @@ public class NetworkSettingsFragment extends Fragment { super.onResume(); mPrefs = LinphonePreferences.instance(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance() - .selectMenu( - FragmentsAvailable.SETTINGS_SUBLEVEL, - getString(R.string.pref_network_title)); - } updateValues(); } - protected void loadSettings() { + private void loadSettings() { mWifiOnly = mRootView.findViewById(R.id.pref_wifi_only); mIpv6 = mRootView.findViewById(R.id.pref_ipv6); @@ -101,7 +92,7 @@ public class NetworkSettingsFragment extends Fragment { mRootView.findViewById(R.id.pref_android_battery_protected_settings); } - protected void setListeners() { + private void setListeners() { mWifiOnly.setListener( new SettingListenerBase() { @Override @@ -205,9 +196,7 @@ public class NetworkSettingsFragment extends Fragment { @Override public void onClicked() { mPrefs.powerSaverDialogPrompted(true); - Intent intent = - DeviceUtils.getDevicePowerManagerIntent( - LinphoneActivity.instance()); + Intent intent = DeviceUtils.getDevicePowerManagerIntent(getActivity()); if (intent != null) { startActivity(intent); } @@ -215,7 +204,7 @@ public class NetworkSettingsFragment extends Fragment { }); } - protected void updateValues() { + private void updateValues() { mWifiOnly.setChecked(mPrefs.isWifiOnlyEnabled()); mIpv6.setChecked(mPrefs.isUsingIpv6()); @@ -242,9 +231,7 @@ public class NetworkSettingsFragment extends Fragment { mTurnPassword.setEnabled(mPrefs.isTurnEnabled()); mAndroidBatterySaverSettings.setVisibility( - DeviceUtils.hasDevicePowerManager(LinphoneActivity.instance()) - ? View.VISIBLE - : View.GONE); + DeviceUtils.hasDevicePowerManager(getActivity()) ? View.VISIBLE : View.GONE); setListeners(); } diff --git a/app/src/main/java/org/linphone/settings/SettingsActivity.java b/app/src/main/java/org/linphone/settings/SettingsActivity.java new file mode 100644 index 000000000..ea46b1341 --- /dev/null +++ b/app/src/main/java/org/linphone/settings/SettingsActivity.java @@ -0,0 +1,155 @@ +package org.linphone.settings; + +/* +SettingsActivity.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.app.Fragment; +import android.app.FragmentManager; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.provider.Settings; +import androidx.annotation.Nullable; +import org.linphone.R; +import org.linphone.activities.MainActivity; +import org.linphone.compatibility.Compatibility; +import org.linphone.core.tools.Log; + +public class SettingsActivity extends MainActivity { + private static final int PERMISSIONS_REQUEST_OVERLAY = 206; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mOnBackPressGoHome = false; + } + + @Override + protected void onStart() { + super.onStart(); + + Fragment currentFragment = getFragmentManager().findFragmentById(R.id.fragmentContainer); + if (currentFragment == null) { + if (getIntent() != null && getIntent().getExtras() != null) { + Bundle extras = getIntent().getExtras(); + if (isTablet() || !extras.containsKey("Account")) { + showSettingsMenu(); + } + handleIntentExtras(extras); + } else { + showSettingsMenu(); + } + } + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + // Clean fragments stack upon return + while (getFragmentManager().getBackStackEntryCount() > 0) { + getFragmentManager().popBackStackImmediate(); + } + + handleIntentExtras(intent.getExtras()); + } + + @Override + protected void onResume() { + super.onResume(); + + hideTabBar(); + + int count = getFragmentManager().getBackStackEntryCount(); + if (count == 0) { + showTopBarWithTitle(getString(R.string.settings)); + } else { + FragmentManager.BackStackEntry entry = + getFragmentManager().getBackStackEntryAt(count - 1); + showTopBarWithTitle(entry.getName()); + } + } + + @Override + public void goBack() { + // 1 is for the empty fragment on tablets + if (!isTablet()) { + if (popBackStack()) { + showTopBarWithTitle(getString(R.string.settings)); + return; + } + } + super.goBack(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + if (requestCode == PERMISSIONS_REQUEST_OVERLAY) { + if (Compatibility.canDrawOverlays(this)) { + LinphonePreferences.instance().enableOverlay(true); + } + } + super.onActivityResult(requestCode, resultCode, data); + } + + private void handleIntentExtras(Bundle extras) { + if (extras != null && extras.containsKey("Account")) { + int accountIndex = extras.getInt("Account"); + showAccountSettings(accountIndex, isTablet()); + } + } + + private void showSettingsMenu() { + Bundle extras = new Bundle(); + MenuSettingsFragment menuSettingsFragment = new MenuSettingsFragment(); + menuSettingsFragment.setArguments(extras); + changeFragment(menuSettingsFragment, getString(R.string.settings), false); + showTopBarWithTitle(getString(R.string.settings)); + } + + public void showSettings(Fragment fragment, String name) { + changeFragment(fragment, name, true); + showTopBarWithTitle(name); + } + + public void showAccountSettings(int accountIndex, boolean isChild) { + Bundle extras = new Bundle(); + extras.putInt("Account", accountIndex); + AccountSettingsFragment accountSettingsFragment = new AccountSettingsFragment(); + accountSettingsFragment.setArguments(extras); + changeFragment(accountSettingsFragment, getString(R.string.pref_sipaccount), isChild); + showTopBarWithTitle(getString(R.string.pref_sipaccount)); + } + + public boolean checkAndRequestOverlayPermission() { + Log.i( + "[Permission] Draw overlays permission is " + + (Compatibility.canDrawOverlays(this) ? "granted" : "denied")); + if (!Compatibility.canDrawOverlays(this)) { + Log.i("[Permission] Asking for overlay"); + Intent intent = + new Intent( + Settings.ACTION_MANAGE_OVERLAY_PERMISSION, + Uri.parse("package:" + getPackageName())); + startActivityForResult(intent, PERMISSIONS_REQUEST_OVERLAY); + return false; + } + return true; + } +} diff --git a/app/src/main/java/org/linphone/settings/SettingsFragment.java b/app/src/main/java/org/linphone/settings/SettingsFragment.java index 5080c133f..6b3fc47af 100644 --- a/app/src/main/java/org/linphone/settings/SettingsFragment.java +++ b/app/src/main/java/org/linphone/settings/SettingsFragment.java @@ -1,7 +1,7 @@ package org.linphone.settings; /* -SettingsFragment.java +MenuSettingsFragment.java Copyright (C) 2019 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or @@ -20,192 +20,5 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import android.app.Fragment; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.TextView; -import androidx.annotation.Nullable; -import org.linphone.LinphoneActivity; -import org.linphone.LinphoneManager; -import org.linphone.R; -import org.linphone.core.Core; -import org.linphone.core.ProxyConfig; -import org.linphone.fragments.FragmentsAvailable; -import org.linphone.settings.widget.BasicSetting; -import org.linphone.settings.widget.LedSetting; -import org.linphone.settings.widget.SettingListenerBase; -import org.linphone.utils.LinphoneUtils; -public class SettingsFragment extends Fragment { - protected View mRootView; - private BasicSetting mTunnel, mAudio, mVideo, mCall, mChat, mNetwork, mAdvanced; - private LinearLayout mAccounts; - private TextView mAccountsHeader; - - @Nullable - @Override - public View onCreateView( - LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { - mRootView = inflater.inflate(R.layout.settings, container, false); - - loadSettings(); - setListeners(); - - return mRootView; - } - - @Override - public void onResume() { - super.onResume(); - - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().selectMenu(FragmentsAvailable.SETTINGS); - } - - updateValues(); - } - - protected void loadSettings() { - mAccounts = mRootView.findViewById(R.id.accounts_settings_list); - mAccountsHeader = mRootView.findViewById(R.id.accounts_settings_list_header); - - mTunnel = mRootView.findViewById(R.id.pref_tunnel); - - mAudio = mRootView.findViewById(R.id.pref_audio); - - mVideo = mRootView.findViewById(R.id.pref_video); - - mCall = mRootView.findViewById(R.id.pref_call); - - mChat = mRootView.findViewById(R.id.pref_chat); - - mNetwork = mRootView.findViewById(R.id.pref_network); - - mAdvanced = mRootView.findViewById(R.id.pref_advanced); - } - - protected void setListeners() { - mTunnel.setListener( - new SettingListenerBase() { - @Override - public void onClicked() { - LinphoneActivity.instance() - .displaySubSettings(new TunnelSettingsFragment()); - } - }); - - mAudio.setListener( - new SettingListenerBase() { - @Override - public void onClicked() { - LinphoneActivity.instance().displaySubSettings(new AudioSettingsFragment()); - } - }); - - mVideo.setListener( - new SettingListenerBase() { - @Override - public void onClicked() { - LinphoneActivity.instance().displaySubSettings(new VideoSettingsFragment()); - } - }); - - mCall.setListener( - new SettingListenerBase() { - @Override - public void onClicked() { - LinphoneActivity.instance().displaySubSettings(new CallSettingsFragment()); - } - }); - - mChat.setListener( - new SettingListenerBase() { - @Override - public void onClicked() { - LinphoneActivity.instance().displaySubSettings(new ChatSettingsFragment()); - } - }); - - mNetwork.setListener( - new SettingListenerBase() { - @Override - public void onClicked() { - LinphoneActivity.instance() - .displaySubSettings(new NetworkSettingsFragment()); - } - }); - - mAdvanced.setListener( - new SettingListenerBase() { - @Override - public void onClicked() { - LinphoneActivity.instance() - .displaySubSettings(new AdvancedSettingsFragment()); - } - }); - } - - protected void updateValues() { - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (core != null) { - mTunnel.setVisibility(core.tunnelAvailable() ? View.VISIBLE : View.GONE); - initAccounts(core); - } - - if (getResources().getBoolean(R.bool.hide_accounts)) { - mAccounts.setVisibility(View.GONE); - mAccountsHeader.setVisibility(View.GONE); - } - } - - private void initAccounts(Core core) { - mAccounts.removeAllViews(); - ProxyConfig[] proxyConfigs = core.getProxyConfigList(); - - if (proxyConfigs == null || proxyConfigs.length == 0) { - mAccountsHeader.setVisibility(View.GONE); - } else { - mAccountsHeader.setVisibility(View.VISIBLE); - int i = 0; - for (ProxyConfig proxyConfig : proxyConfigs) { - final LedSetting account = new LedSetting(getActivity()); - account.setTitle( - LinphoneUtils.getDisplayableAddress(proxyConfig.getIdentityAddress())); - - if (proxyConfig.equals(core.getDefaultProxyConfig())) { - account.setSubtitle(getString(R.string.default_account_flag)); - } - - switch (proxyConfig.getState()) { - case Ok: - account.setColor(LedSetting.Color.GREEN); - break; - case Failed: - account.setColor(LedSetting.Color.RED); - break; - case Progress: - account.setColor(LedSetting.Color.ORANGE); - break; - case None: - case Cleared: - account.setColor(LedSetting.Color.GRAY); - break; - } - - final int accountIndex = i; - account.setListener( - new SettingListenerBase() { - @Override - public void onClicked() { - LinphoneActivity.instance().displayAccountSettings(accountIndex); - } - }); - - mAccounts.addView(account); - i += 1; - } - } - } -} +public abstract class SettingsFragment extends Fragment {} diff --git a/app/src/main/java/org/linphone/settings/TunnelSettingsFragment.java b/app/src/main/java/org/linphone/settings/TunnelSettingsFragment.java index a64027201..48efd473b 100644 --- a/app/src/main/java/org/linphone/settings/TunnelSettingsFragment.java +++ b/app/src/main/java/org/linphone/settings/TunnelSettingsFragment.java @@ -19,24 +19,21 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import android.app.Fragment; import android.os.Bundle; import android.text.InputType; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.annotation.Nullable; -import org.linphone.LinphoneActivity; import org.linphone.R; import org.linphone.core.tools.Log; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.settings.widget.ListSetting; import org.linphone.settings.widget.SettingListenerBase; import org.linphone.settings.widget.TextSetting; -public class TunnelSettingsFragment extends Fragment { - protected View mRootView; - protected LinphonePreferences mPrefs; +public class TunnelSettingsFragment extends SettingsFragment { + private View mRootView; + private LinphonePreferences mPrefs; private TextSetting mHost, mPort; private ListSetting mMode; @@ -57,17 +54,11 @@ public class TunnelSettingsFragment extends Fragment { super.onResume(); mPrefs = LinphonePreferences.instance(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance() - .selectMenu( - FragmentsAvailable.SETTINGS_SUBLEVEL, - getString(R.string.pref_tunnel_title)); - } updateValues(); } - protected void loadSettings() { + private void loadSettings() { mHost = mRootView.findViewById(R.id.pref_tunnel_host); mPort = mRootView.findViewById(R.id.pref_tunnel_port); @@ -76,7 +67,7 @@ public class TunnelSettingsFragment extends Fragment { mMode = mRootView.findViewById(R.id.pref_tunnel_mode); } - protected void setListeners() { + private void setListeners() { mHost.setListener( new SettingListenerBase() { @Override @@ -106,7 +97,7 @@ public class TunnelSettingsFragment extends Fragment { }); } - protected void updateValues() { + private void updateValues() { mHost.setValue(mPrefs.getTunnelHost()); mPort.setValue(mPrefs.getTunnelPort()); diff --git a/app/src/main/java/org/linphone/settings/VideoSettingsFragment.java b/app/src/main/java/org/linphone/settings/VideoSettingsFragment.java index 3cba62a4c..7f3ad4ddd 100644 --- a/app/src/main/java/org/linphone/settings/VideoSettingsFragment.java +++ b/app/src/main/java/org/linphone/settings/VideoSettingsFragment.java @@ -19,7 +19,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import android.app.Fragment; import android.os.Bundle; import android.text.InputType; import android.view.LayoutInflater; @@ -30,7 +29,6 @@ import android.widget.TextView; import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.core.Core; @@ -38,15 +36,14 @@ import org.linphone.core.Factory; import org.linphone.core.PayloadType; import org.linphone.core.VideoDefinition; import org.linphone.core.tools.Log; -import org.linphone.fragments.FragmentsAvailable; import org.linphone.settings.widget.ListSetting; import org.linphone.settings.widget.SettingListenerBase; import org.linphone.settings.widget.SwitchSetting; import org.linphone.settings.widget.TextSetting; -public class VideoSettingsFragment extends Fragment { - protected View mRootView; - protected LinphonePreferences mPrefs; +public class VideoSettingsFragment extends SettingsFragment { + private View mRootView; + private LinphonePreferences mPrefs; private SwitchSetting mEnable, mAutoInitiate, mAutoAccept, mOverlay; private ListSetting mPreset, mSize, mFps; @@ -70,17 +67,11 @@ public class VideoSettingsFragment extends Fragment { super.onResume(); mPrefs = LinphonePreferences.instance(); - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance() - .selectMenu( - FragmentsAvailable.SETTINGS_SUBLEVEL, - getString(R.string.pref_video_title)); - } updateValues(); } - protected void loadSettings() { + private void loadSettings() { mEnable = mRootView.findViewById(R.id.pref_video_enable); mAutoInitiate = mRootView.findViewById(R.id.pref_video_initiate_call_with_video); @@ -104,7 +95,7 @@ public class VideoSettingsFragment extends Fragment { mVideoCodecsHeader = mRootView.findViewById(R.id.pref_video_codecs_header); } - protected void setListeners() { + private void setListeners() { mEnable.setListener( new SettingListenerBase() { @Override @@ -138,7 +129,10 @@ public class VideoSettingsFragment extends Fragment { new SettingListenerBase() { @Override public void onBoolValueChanged(boolean newValue) { - mPrefs.enableOverlay(newValue); + mPrefs.enableOverlay( + newValue + && ((SettingsActivity) getActivity()) + .checkAndRequestOverlayPermission()); } }); @@ -186,7 +180,7 @@ public class VideoSettingsFragment extends Fragment { }); } - protected void updateValues() { + private void updateValues() { mEnable.setChecked(mPrefs.isVideoEnabled()); updateVideoSettingsVisibility(mPrefs.isVideoEnabled()); @@ -241,7 +235,7 @@ public class VideoSettingsFragment extends Fragment { private void populateVideoCodecs() { mVideoCodecs.removeAllViews(); - Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + Core core = LinphoneManager.getCore(); if (core != null) { for (final PayloadType pt : core.getVideoPayloadTypes()) { final SwitchSetting codec = new SwitchSetting(getActivity()); diff --git a/app/src/main/java/org/linphone/settings/widget/BasicSetting.java b/app/src/main/java/org/linphone/settings/widget/BasicSetting.java index 99191a3e9..f4067c969 100644 --- a/app/src/main/java/org/linphone/settings/widget/BasicSetting.java +++ b/app/src/main/java/org/linphone/settings/widget/BasicSetting.java @@ -31,10 +31,11 @@ import androidx.annotation.Nullable; import org.linphone.R; public class BasicSetting extends LinearLayout { - protected Context mContext; - protected View mView; - protected TextView mTitle, mSubtitle; - protected SettingListener mListener; + final Context mContext; + View mView; + private TextView mTitle; + private TextView mSubtitle; + SettingListener mListener; public BasicSetting(Context context) { super(context); @@ -54,13 +55,13 @@ public class BasicSetting extends LinearLayout { init(attrs, defStyleAttr, 0); } - public BasicSetting(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + BasicSetting(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mContext = context; init(attrs, defStyleAttr, defStyleRes); } - protected void inflateView() { + void inflateView() { mView = LayoutInflater.from(mContext).inflate(R.layout.settings_widget_basic, this, true); } @@ -68,7 +69,7 @@ public class BasicSetting extends LinearLayout { mListener = listener; } - protected void init(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { + void init(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { inflateView(); mTitle = mView.findViewById(R.id.setting_title); diff --git a/app/src/main/java/org/linphone/settings/widget/CheckBoxSetting.java b/app/src/main/java/org/linphone/settings/widget/CheckBoxSetting.java index 253a8ac41..769d5e499 100644 --- a/app/src/main/java/org/linphone/settings/widget/CheckBoxSetting.java +++ b/app/src/main/java/org/linphone/settings/widget/CheckBoxSetting.java @@ -30,7 +30,7 @@ import androidx.annotation.Nullable; import org.linphone.R; public class CheckBoxSetting extends BasicSetting { - protected CheckBox mCheckBox; + private CheckBox mCheckBox; public CheckBoxSetting(Context context) { super(context); @@ -93,7 +93,7 @@ public class CheckBoxSetting extends BasicSetting { return mCheckBox.isChecked(); } - public void toggle() { + private void toggle() { mCheckBox.toggle(); } } diff --git a/app/src/main/java/org/linphone/settings/widget/LedSetting.java b/app/src/main/java/org/linphone/settings/widget/LedSetting.java index 182672257..1f6779306 100644 --- a/app/src/main/java/org/linphone/settings/widget/LedSetting.java +++ b/app/src/main/java/org/linphone/settings/widget/LedSetting.java @@ -34,7 +34,7 @@ public class LedSetting extends BasicSetting { RED } - protected ImageView mLed; + private ImageView mLed; public LedSetting(Context context) { super(context); diff --git a/app/src/main/java/org/linphone/settings/widget/ListSetting.java b/app/src/main/java/org/linphone/settings/widget/ListSetting.java index b0633f75b..85009c6ba 100644 --- a/app/src/main/java/org/linphone/settings/widget/ListSetting.java +++ b/app/src/main/java/org/linphone/settings/widget/ListSetting.java @@ -33,9 +33,9 @@ import java.util.List; import org.linphone.R; public class ListSetting extends BasicSetting implements AdapterView.OnItemSelectedListener { - protected Spinner mSpinner; - protected List mItems; - protected List mItemsValues; + private Spinner mSpinner; + private List mItems; + private List mItemsValues; public ListSetting(Context context) { super(context); diff --git a/app/src/main/java/org/linphone/settings/widget/SettingListener.java b/app/src/main/java/org/linphone/settings/widget/SettingListener.java index 8e4f997f3..58b67cf91 100644 --- a/app/src/main/java/org/linphone/settings/widget/SettingListener.java +++ b/app/src/main/java/org/linphone/settings/widget/SettingListener.java @@ -19,7 +19,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -public interface SettingListener { +interface SettingListener { void onClicked(); void onTextValueChanged(String newValue); diff --git a/app/src/main/java/org/linphone/settings/widget/SwitchSetting.java b/app/src/main/java/org/linphone/settings/widget/SwitchSetting.java index f788de59a..046f521f4 100644 --- a/app/src/main/java/org/linphone/settings/widget/SwitchSetting.java +++ b/app/src/main/java/org/linphone/settings/widget/SwitchSetting.java @@ -30,7 +30,7 @@ import androidx.annotation.Nullable; import org.linphone.R; public class SwitchSetting extends BasicSetting { - protected Switch mSwitch; + private Switch mSwitch; public SwitchSetting(Context context) { super(context); @@ -91,7 +91,7 @@ public class SwitchSetting extends BasicSetting { return mSwitch.isChecked(); } - public void toggle() { + private void toggle() { mSwitch.toggle(); } } diff --git a/app/src/main/java/org/linphone/settings/widget/TextSetting.java b/app/src/main/java/org/linphone/settings/widget/TextSetting.java index 94437b089..8d92c4b42 100644 --- a/app/src/main/java/org/linphone/settings/widget/TextSetting.java +++ b/app/src/main/java/org/linphone/settings/widget/TextSetting.java @@ -30,7 +30,7 @@ import androidx.annotation.Nullable; import org.linphone.R; public class TextSetting extends BasicSetting implements TextWatcher { - protected EditText mInput; + private EditText mInput; public TextSetting(Context context) { super(context); diff --git a/app/src/main/java/org/linphone/utils/ActivityMonitor.java b/app/src/main/java/org/linphone/utils/ActivityMonitor.java new file mode 100644 index 000000000..bcd91241a --- /dev/null +++ b/app/src/main/java/org/linphone/utils/ActivityMonitor.java @@ -0,0 +1,140 @@ +package org.linphone.utils; + +/* +ActivityMonitor.java +Copyright (C) 2017 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; +import java.util.ArrayList; +import org.linphone.LinphoneManager; +import org.linphone.LinphoneService; +import org.linphone.core.tools.Log; + +/** + * Believe me or not, but knowing the application visibility state on Android is a nightmare. After + * two days of hard work I ended with the following class, that does the job more or less reliabily. + */ +public class ActivityMonitor implements Application.ActivityLifecycleCallbacks { + private final ArrayList activities = new ArrayList<>(); + private boolean mActive = false; + private int mRunningActivities = 0; + private InactivityChecker mLastChecker; + + @Override + public synchronized void onActivityCreated(Activity activity, Bundle savedInstanceState) { + Log.i("[Activity Monitor] Activity created:" + activity); + if (!activities.contains(activity)) activities.add(activity); + } + + @Override + public void onActivityStarted(Activity activity) { + Log.i("Activity started:" + activity); + } + + @Override + public synchronized void onActivityResumed(Activity activity) { + Log.i("[Activity Monitor] Activity resumed:" + activity); + if (activities.contains(activity)) { + mRunningActivities++; + Log.i("[Activity Monitor] runningActivities=" + mRunningActivities); + checkActivity(); + } + } + + @Override + public synchronized void onActivityPaused(Activity activity) { + Log.i("[Activity Monitor] Activity paused:" + activity); + if (activities.contains(activity)) { + mRunningActivities--; + Log.i("[Activity Monitor] runningActivities=" + mRunningActivities); + checkActivity(); + } + } + + @Override + public void onActivityStopped(Activity activity) { + Log.i("[Activity Monitor] Activity stopped:" + activity); + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) {} + + @Override + public synchronized void onActivityDestroyed(Activity activity) { + Log.i("[Activity Monitor] Activity destroyed:" + activity); + activities.remove(activity); + } + + void startInactivityChecker() { + if (mLastChecker != null) mLastChecker.cancel(); + LinphoneService.instance() + .handler + .postDelayed((mLastChecker = new InactivityChecker()), 2000); + } + + void checkActivity() { + if (mRunningActivities == 0) { + if (mActive) startInactivityChecker(); + } else if (mRunningActivities > 0) { + if (!mActive) { + mActive = true; + onForegroundMode(); + } + if (mLastChecker != null) { + mLastChecker.cancel(); + mLastChecker = null; + } + } + } + + private void onBackgroundMode() { + Log.i("[Activity Monitor] App has entered background mode"); + if (LinphoneManager.getCore() != null) { + LinphoneManager.getCore().enterBackground(); + } + } + + private void onForegroundMode() { + Log.i("[Activity Monitor] App has left background mode"); + if (LinphoneManager.getCore() != null) { + LinphoneManager.getCore().enterForeground(); + } + } + + class InactivityChecker implements Runnable { + private boolean isCanceled; + + void cancel() { + isCanceled = true; + } + + @Override + public void run() { + synchronized (LinphoneService.instance()) { + if (!isCanceled) { + if (ActivityMonitor.this.mRunningActivities == 0 && mActive) { + mActive = false; + onBackgroundMode(); + } + } + } + } + } +} diff --git a/app/src/main/java/org/linphone/utils/AndroidAudioManager.java b/app/src/main/java/org/linphone/utils/AndroidAudioManager.java new file mode 100644 index 000000000..1b5528847 --- /dev/null +++ b/app/src/main/java/org/linphone/utils/AndroidAudioManager.java @@ -0,0 +1,377 @@ +package org.linphone.utils; + +/* +AndroidAudioManager.java +Copyright (C) 2019 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +import static android.media.AudioManager.MODE_RINGTONE; +import static android.media.AudioManager.STREAM_RING; +import static android.media.AudioManager.STREAM_VOICE_CALL; + +import android.content.Context; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.Vibrator; +import android.provider.Settings; +import android.telephony.TelephonyManager; +import android.view.KeyEvent; +import java.io.FileInputStream; +import java.io.IOException; +import org.linphone.LinphoneManager; +import org.linphone.R; +import org.linphone.core.Call; +import org.linphone.core.Core; +import org.linphone.core.CoreListenerStub; +import org.linphone.core.EcCalibratorStatus; +import org.linphone.core.tools.Log; +import org.linphone.receivers.BluetoothManager; +import org.linphone.settings.LinphonePreferences; + +public class AndroidAudioManager { + private static final int LINPHONE_VOLUME_STREAM = STREAM_VOICE_CALL; + + private Context mContext; + private AudioManager mAudioManager; + private Call mRingingCall; + private MediaPlayer mRingerPlayer; + private final Vibrator mVibrator; + + private boolean mIsRinging; + private boolean mAudioFocused; + private boolean mEchoTesterIsRunning; + + private CoreListenerStub mListener; + + public AndroidAudioManager(Context context) { + mContext = context; + mAudioManager = ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)); + mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); + mEchoTesterIsRunning = false; + + mListener = + new CoreListenerStub() { + @Override + public void onCallStateChanged( + final Core core, + final Call call, + final Call.State state, + final String message) { + if (state == Call.State.IncomingReceived + || (state == Call.State.IncomingEarlyMedia + && mContext.getResources() + .getBoolean( + R.bool.allow_ringing_while_early_media))) { + // Brighten screen for at least 10 seconds + if (core.getCallsNb() == 1) { + requestAudioFocus(STREAM_RING); + + mRingingCall = call; + startRinging(); + // otherwise there is the beep + } + } else if (call == mRingingCall && mIsRinging) { + // previous state was ringing, so stop ringing + stopRinging(); + } + + if (state == Call.State.Connected) { + if (core.getCallsNb() == 1) { + // It is for incoming calls, because outgoing calls enter + // MODE_IN_COMMUNICATION immediately when they start. + // However, incoming call first use the MODE_RINGING to play the + // local ring. + if (call.getDir() == Call.Dir.Incoming) { + setAudioManagerInCallMode(); + // mAudioManager.abandonAudioFocus(null); + requestAudioFocus(STREAM_VOICE_CALL); + } + } + } else if (state == Call.State.End || state == Call.State.Error) { + if (core.getCallsNb() == 0) { + if (mAudioFocused) { + int res = mAudioManager.abandonAudioFocus(null); + Log.d( + "[Audio Manager] Audio focus released a bit later: " + + (res + == AudioManager + .AUDIOFOCUS_REQUEST_GRANTED + ? "Granted" + : "Denied")); + mAudioFocused = false; + } + + TelephonyManager tm = + (TelephonyManager) + mContext.getSystemService( + Context.TELEPHONY_SERVICE); + if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) { + Log.d( + "[Audio Manager] ---AndroidAudioManager: back to MODE_NORMAL"); + mAudioManager.setMode(AudioManager.MODE_NORMAL); + Log.d( + "[Audio Manager] All call terminated, routing back to earpiece"); + routeAudioToEarPiece(); + } + } + } + if (state == Call.State.OutgoingInit) { + // Enter the MODE_IN_COMMUNICATION mode as soon as possible, so that + // ringback is heard normally in earpiece or bluetooth receiver. + setAudioManagerInCallMode(); + requestAudioFocus(STREAM_VOICE_CALL); + startBluetooth(); + } + + if (state == Call.State.StreamsRunning) { + startBluetooth(); + setAudioManagerInCallMode(); + } + } + + @Override + public void onEcCalibrationResult( + Core core, EcCalibratorStatus status, int delay_ms) { + mAudioManager.setMode(AudioManager.MODE_NORMAL); + mAudioManager.abandonAudioFocus(null); + Log.i("[Audio Manager] Set audio mode on 'Normal'"); + } + }; + + Core core = LinphoneManager.getCore(); + if (core != null) { + core.addListener(mListener); + } + } + + public void destroy() { + Core core = LinphoneManager.getCore(); + if (core != null) { + core.removeListener(mListener); + } + } + + /* Audio routing */ + + public void setAudioManagerModeNormal() { + mAudioManager.setMode(AudioManager.MODE_NORMAL); + } + + public void routeAudioToEarPiece() { + routeAudioToSpeakerHelper(false); + } + + public void routeAudioToSpeaker() { + routeAudioToSpeakerHelper(true); + } + + public boolean isAudioRoutedToSpeaker() { + return mAudioManager.isSpeakerphoneOn(); + } + + /* Echo cancellation */ + + public void startEcCalibration() { + Core core = LinphoneManager.getCore(); + if (core == null) { + return; + } + + routeAudioToSpeaker(); + setAudioManagerInCallMode(); + Log.i("[Audio Manager] Set audio mode on 'Voice Communication'"); + requestAudioFocus(STREAM_VOICE_CALL); + int oldVolume = mAudioManager.getStreamVolume(STREAM_VOICE_CALL); + int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL); + mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0); + core.startEchoCancellerCalibration(); + mAudioManager.setStreamVolume(STREAM_VOICE_CALL, oldVolume, 0); + } + + public void startEchoTester() { + Core core = LinphoneManager.getCore(); + if (core == null) { + return; + } + + routeAudioToSpeaker(); + setAudioManagerInCallMode(); + Log.i("[Audio Manager] Set audio mode on 'Voice Communication'"); + requestAudioFocus(STREAM_VOICE_CALL); + int maxVolume = mAudioManager.getStreamMaxVolume(STREAM_VOICE_CALL); + int sampleRate; + mAudioManager.setStreamVolume(STREAM_VOICE_CALL, maxVolume, 0); + String sampleRateProperty = + mAudioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE); + sampleRate = Integer.parseInt(sampleRateProperty); + core.startEchoTester(sampleRate); + mEchoTesterIsRunning = true; + } + + public void stopEchoTester() { + Core core = LinphoneManager.getCore(); + if (core == null) { + return; + } + + mEchoTesterIsRunning = false; + core.stopEchoTester(); + routeAudioToEarPiece(); + mAudioManager.setMode(AudioManager.MODE_NORMAL); + Log.i("[Audio Manager] Set audio mode on 'Normal'"); + } + + public boolean getEchoTesterStatus() { + return mEchoTesterIsRunning; + } + + public boolean onKeyVolumeAdjust(int keyCode) { + if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { + adjustVolume(1); + return true; + } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { + adjustVolume(-1); + return true; + } + return false; + } + + private void setAudioManagerInCallMode() { + if (mAudioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) { + Log.w("[Audio Manager] already in MODE_IN_COMMUNICATION, skipping..."); + return; + } + Log.d("[Audio Manager] Mode: MODE_IN_COMMUNICATION"); + + mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); + } + + private void startBluetooth() { + if (BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) { + BluetoothManager.getInstance().routeAudioToBluetooth(); + } + } + + private void requestAudioFocus(int stream) { + if (!mAudioFocused) { + int res = + mAudioManager.requestAudioFocus( + null, stream, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE); + Log.d( + "[Audio Manager] Audio focus requested: " + + (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED + ? "Granted" + : "Denied")); + if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) mAudioFocused = true; + } + } + + private synchronized void startRinging() { + if (!LinphonePreferences.instance().isDeviceRingtoneEnabled()) { + // Enable speaker audio route, linphone library will do the ringing itself automatically + routeAudioToSpeaker(); + return; + } + + if (mContext.getResources().getBoolean(R.bool.allow_ringing_while_early_media)) { + routeAudioToSpeaker(); // Need to be able to ear the ringtone during the early media + } + + mAudioManager.setMode(MODE_RINGTONE); + + try { + if ((mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE + || mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) + && mVibrator != null + && LinphonePreferences.instance().isIncomingCallVibrationEnabled()) { + long[] patern = {0, 1000, 1000}; + mVibrator.vibrate(patern, 1); + } + if (mRingerPlayer == null) { + requestAudioFocus(STREAM_RING); + mRingerPlayer = new MediaPlayer(); + mRingerPlayer.setAudioStreamType(STREAM_RING); + + String ringtone = + LinphonePreferences.instance() + .getRingtone(Settings.System.DEFAULT_RINGTONE_URI.toString()); + try { + if (ringtone.startsWith("content://")) { + mRingerPlayer.setDataSource(mContext, Uri.parse(ringtone)); + } else { + FileInputStream fis = new FileInputStream(ringtone); + mRingerPlayer.setDataSource(fis.getFD()); + fis.close(); + } + } catch (IOException e) { + Log.e(e, "[Audio Manager] Cannot set ringtone"); + } + + mRingerPlayer.prepare(); + mRingerPlayer.setLooping(true); + mRingerPlayer.start(); + } else { + Log.w("[Audio Manager] Already ringing"); + } + } catch (Exception e) { + Log.e(e, "[Audio Manager] Cannot handle incoming call"); + } + mIsRinging = true; + } + + private synchronized void stopRinging() { + if (mRingerPlayer != null) { + mRingerPlayer.stop(); + mRingerPlayer.release(); + mRingerPlayer = null; + } + if (mVibrator != null) { + mVibrator.cancel(); + } + + mIsRinging = false; + if (!BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) { + if (mContext.getResources().getBoolean(R.bool.isTablet)) { + Log.d("[Audio Manager] Stopped ringing, routing back to speaker"); + routeAudioToSpeaker(); + } else { + Log.d("[Audio Manager] Stopped ringing, routing back to earpiece"); + routeAudioToEarPiece(); + } + } + } + + private void routeAudioToSpeakerHelper(boolean speakerOn) { + Log.w( + "[Audio Manager] Routing audio to " + + (speakerOn ? "speaker" : "earpiece") + + ", disabling bluetooth audio route"); + BluetoothManager.getInstance().disableBluetoothSCO(); + + mAudioManager.setSpeakerphoneOn(speakerOn); + } + + private void adjustVolume(int i) { + // starting from ICS, volume must be adjusted by the application, at least for + // STREAM_VOICE_CALL volume stream + mAudioManager.adjustStreamVolume( + LINPHONE_VOLUME_STREAM, + i < 0 ? AudioManager.ADJUST_LOWER : AudioManager.ADJUST_RAISE, + AudioManager.FLAG_SHOW_UI); + } +} diff --git a/app/src/main/java/org/linphone/utils/FileUtils.java b/app/src/main/java/org/linphone/utils/FileUtils.java index 8a636c546..fa9b4f67c 100644 --- a/app/src/main/java/org/linphone/utils/FileUtils.java +++ b/app/src/main/java/org/linphone/utils/FileUtils.java @@ -39,8 +39,6 @@ import java.util.Date; import java.util.Locale; import org.linphone.LinphoneManager; import org.linphone.core.Address; -import org.linphone.core.ChatMessage; -import org.linphone.core.Content; import org.linphone.core.Friend; import org.linphone.core.FriendList; import org.linphone.core.tools.Log; @@ -70,19 +68,6 @@ public class FileUtils { return (extension != null && extension.matches("(png|jpg|jpeg|bmp|gif)")); } - public static void recursiveFileRemoval(File root) { - if (!root.delete()) { - if (root.isDirectory()) { - File[] files = root.listFiles(); - if (files != null) { - for (File f : files) { - recursiveFileRemoval(f); - } - } - } - } - } - public static String getFilePath(final Context context, final Uri uri) { if (uri == null) return null; @@ -99,7 +84,7 @@ public class FileUtils { remoteFile.close(); } catch (IOException e) { - Log.e("Enable to get sharing file", e); + Log.e("[File Utils] Enable to get sharing file", e); } return result; @@ -150,13 +135,18 @@ public class FileUtils { final File root; root = context.getExternalCacheDir(); - if (root != null && !root.exists()) root.mkdirs(); + if (root != null && !root.exists()) { + boolean result = root.mkdirs(); + if (!result) { + Log.e("[File Utils] Couldn't create directory " + root.getAbsolutePath()); + } + } return new File(root, fileName); } public static Uri getCVSPathFromLookupUri(String content) { String contactId = getNameFromFilePath(content); - FriendList[] friendList = LinphoneManager.getLc().getFriendsLists(); + FriendList[] friendList = LinphoneManager.getCore().getFriendsLists(); for (FriendList list : friendList) { for (Friend friend : list.getFriends()) { if (friend.getRefKey().equals(contactId)) { @@ -190,8 +180,14 @@ public class FileUtils { "app_name", "string", mContext.getPackageName())); File file = new File(storageDir); if (!file.isDirectory() || !file.exists()) { - Log.w("Directory " + file + " doesn't seem to exists yet, let's create it"); - file.mkdirs(); + Log.w( + "[File Utils] Directory " + + file + + " doesn't seem to exists yet, let's create it"); + boolean result = file.mkdirs(); + if (!result) { + Log.e("[File Utils] Couldn't create directory " + file.getAbsolutePath()); + } LinphoneManager.getInstance().getMediaScanner().scanFile(file, null); } return storageDir; @@ -208,8 +204,14 @@ public class FileUtils { + "/recordings"; File file = new File(recordingsDir); if (!file.isDirectory() || !file.exists()) { - Log.w("Directory " + file + " doesn't seem to exists yet, let's create it"); - file.mkdirs(); + Log.w( + "[File Utils] Directory " + + file + + " doesn't seem to exists yet, let's create it"); + boolean result = file.mkdirs(); + if (!result) { + Log.e("[File Utils] Couldn't create directory " + file.getAbsolutePath()); + } LinphoneManager.getInstance().getMediaScanner().scanFile(file, null); } return recordingsDir; @@ -229,18 +231,6 @@ public class FileUtils { return fileName; } - public static void scanFile(ChatMessage message) { - String appData = message.getAppdata(); - if (appData == null) { - for (Content c : message.getContents()) { - if (c.isFile()) { - appData = c.getFilePath(); - } - } - } - LinphoneManager.getInstance().getMediaScanner().scanFile(new File(appData), null); - } - private static Uri createCvsFromString(String vcardString) { String contactName = getContactNameFromVcard(vcardString); File vcfFile = new File(Environment.getExternalStorageDirectory(), contactName + ".cvs"); diff --git a/app/src/main/java/org/linphone/utils/IntentUtils.java b/app/src/main/java/org/linphone/utils/IntentUtils.java deleted file mode 100644 index 6bb9a661e..000000000 --- a/app/src/main/java/org/linphone/utils/IntentUtils.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.linphone.utils; - -/* -IntentUtils.java -Copyright (C) 2018 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import java.util.ArrayList; -import org.linphone.LinphoneActivity; -import org.linphone.LinphoneManager; -import org.linphone.contacts.ContactsManager; -import org.linphone.core.tools.Log; - -public class IntentUtils { - private static final String ACTION_CALL_LINPHONE = "org.linphone.intent.action.CallLaunched"; - - public static void handleIntent(Context context, Intent intent) { - if (intent == null) return; - - Intent newIntent = new Intent(context, LinphoneActivity.class); - String stringFileShared; - String stringUriFileShared; - Uri fileUri; - String addressToCall; - - String action = intent.getAction(); - String type = intent.getType(); - newIntent.setData(intent.getData()); - - if (Intent.ACTION_SEND.equals(action) && type != null) { - if (("text/plain").equals(type) && intent.getStringExtra(Intent.EXTRA_TEXT) != null) { - stringFileShared = intent.getStringExtra(Intent.EXTRA_TEXT); - newIntent.putExtra("msgShared", stringFileShared); - Log.i("[Intent Utils] ACTION_SEND with text/plain data: " + stringFileShared); - } else { - fileUri = intent.getParcelableExtra(Intent.EXTRA_STREAM); - stringUriFileShared = FileUtils.getFilePath(context, fileUri); - newIntent.putExtra("fileShared", stringUriFileShared); - Log.i("[Intent Utils] ACTION_SEND with file: " + stringUriFileShared); - } - } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) { - if (type.startsWith("image/")) { - ArrayList imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); - String filePaths = ""; - for (Uri uri : imageUris) { - filePaths += FileUtils.getFilePath(context, uri); - filePaths += ":"; - } - newIntent.putExtra("fileShared", filePaths); - Log.i("[Intent Utils] ACTION_SEND_MULTIPLE with files: " + filePaths); - } - } else if (ACTION_CALL_LINPHONE.equals(action) - && (intent.getStringExtra("NumberToCall") != null)) { - String numberToCall = intent.getStringExtra("NumberToCall"); - Log.i("[Intent Utils] ACTION_CALL_LINPHONE with number: " + numberToCall); - LinphoneManager.getInstance().newOutgoingCall(numberToCall, null); - } else if (Intent.ACTION_CALL.equals(action)) { - if (intent.getData() != null) { - addressToCall = intent.getData().toString(); - addressToCall = addressToCall.replace("%40", "@"); - addressToCall = addressToCall.replace("%3A", ":"); - if (addressToCall.startsWith("sip:")) { - addressToCall = addressToCall.substring("sip:".length()); - } else if (addressToCall.startsWith("tel:")) { - addressToCall = addressToCall.substring("tel:".length()); - } - Log.i("[Intent Utils] ACTION_CALL with number: " + addressToCall); - newIntent.putExtra("SipUriOrNumber", addressToCall); - } - } else if (Intent.ACTION_VIEW.equals(action)) { - addressToCall = - ContactsManager.getInstance() - .getAddressOrNumberForAndroidContact( - context.getContentResolver(), intent.getData()); - newIntent.putExtra("SipUriOrNumber", addressToCall); - Log.i("[Intent Utils] ACTION_VIEW with number: " + addressToCall); - } else { - Log.i("[Intent Utils] Unknown action [" + action + "], skipping"); - return; - } - - context.startActivity(newIntent); - } -} diff --git a/app/src/main/java/org/linphone/utils/LinphoneUtils.java b/app/src/main/java/org/linphone/utils/LinphoneUtils.java index 308d6efd9..4607148b3 100644 --- a/app/src/main/java/org/linphone/utils/LinphoneUtils.java +++ b/app/src/main/java/org/linphone/utils/LinphoneUtils.java @@ -2,7 +2,7 @@ package org.linphone.utils; /* LinphoneUtils.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 @@ -37,7 +37,10 @@ import android.view.KeyEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; -import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.core.content.ContextCompat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; @@ -58,12 +61,10 @@ import org.linphone.core.Core; import org.linphone.core.Factory; import org.linphone.core.LogCollectionState; import org.linphone.core.ProxyConfig; -import org.linphone.core.tools.Log; import org.linphone.settings.LinphonePreferences; /** Helpers. */ public final class LinphoneUtils { - private static Context sContext = null; private static final Handler sHandler = new Handler(Looper.getMainLooper()); private LinphoneUtils() {} @@ -96,18 +97,13 @@ public final class LinphoneUtils { sHandler.post(r); } - // private static final String sipAddressRegExp = - // "^(sip:)?(\\+)?[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\\.-][a-z0-9]+)*)+\\.[a-z]{2,}(:[0-9]{2,5})?$"; - // private static final String strictSipAddressRegExp = - // "^sip:(\\+)?[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\\.-][a-z0-9]+)*)+\\.[a-z]{2,}$"; - private static boolean isSipAddress(String numberOrAddress) { Factory.instance().createAddress(numberOrAddress); return true; } public static boolean isNumberAddress(String numberOrAddress) { - ProxyConfig proxy = LinphoneManager.getLc().createProxyConfig(); + ProxyConfig proxy = LinphoneManager.getCore().createProxyConfig(); return proxy.normalizePhoneNumber(numberOrAddress) != null; } @@ -138,14 +134,6 @@ public final class LinphoneUtils { return displayName; } - public static String getUsernameFromAddress(String address) { - if (address.contains("sip:")) address = address.replace("sip:", ""); - - if (address.contains("@")) address = address.split("@")[0]; - - return address; - } - public static boolean onKeyBackGoHome(Activity activity, int keyCode, KeyEvent event) { if (!(keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0)) { return false; // continue @@ -195,21 +183,9 @@ public final class LinphoneUtils { && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)); } - public static boolean onKeyVolumeAdjust(int keyCode) { - if (!LinphoneService.isReady()) { - Log.i("Couldn't change softvolume has service is not running"); - return true; - } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { - LinphoneManager.getInstance().adjustVolume(1); - } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { - LinphoneManager.getInstance().adjustVolume(-1); - } - return true; - } - - public static List getCallsInState(Core lc, Collection states) { + public static List getCallsInState(Core core, Collection states) { List foundCalls = new ArrayList<>(); - for (Call call : lc.getCalls()) { + for (Call call : core.getCalls()) { if (states.contains(call.getState())) { foundCalls.add(call); } @@ -268,8 +244,8 @@ public final class LinphoneUtils { public static String getDisplayableUsernameFromAddress(String sipAddress) { String username = sipAddress; - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc == null) return username; + Core core = LinphoneManager.getCore(); + if (core == null) return username; if (username.startsWith("sip:")) { username = username.substring(4); @@ -277,16 +253,13 @@ public final class LinphoneUtils { if (username.contains("@")) { String domain = username.split("@")[1]; - ProxyConfig lpc = lc.getDefaultProxyConfig(); + ProxyConfig lpc = core.getDefaultProxyConfig(); if (lpc != null) { if (domain.equals(lpc.getDomain())) { return username.split("@")[0]; } } else { - if (domain.equals( - LinphoneManager.getInstance() - .getContext() - .getString(R.string.default_domain))) { + if (domain.equals(LinphoneService.instance().getString(R.string.default_domain))) { return username.split("@")[0]; } } @@ -296,24 +269,22 @@ public final class LinphoneUtils { public static String getFullAddressFromUsername(String username) { String sipAddress = username; - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc == null || username == null) return sipAddress; + Core core = LinphoneManager.getCore(); + if (core == null || username == null) return sipAddress; if (!sipAddress.startsWith("sip:")) { sipAddress = "sip:" + sipAddress; } if (!sipAddress.contains("@")) { - ProxyConfig lpc = lc.getDefaultProxyConfig(); + ProxyConfig lpc = core.getDefaultProxyConfig(); if (lpc != null) { sipAddress = sipAddress + "@" + lpc.getDomain(); } else { sipAddress = sipAddress + "@" - + LinphoneManager.getInstance() - .getContext() - .getString(R.string.default_domain); + + LinphoneService.instance().getString(R.string.default_domain); } } return sipAddress; @@ -371,23 +342,12 @@ public final class LinphoneUtils { return Html.fromHtml(text); } - public static void hideKeyboard(Activity activity) { - InputMethodManager imm = - (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); - View view = activity.getCurrentFocus(); - if (view == null) { - view = new View(activity); - } - imm.hideSoftInputFromWindow(view.getWindowToken(), 0); - } - public static ArrayList removeEmptyOneToOneChatRooms(ChatRoom[] rooms) { ArrayList newRooms = new ArrayList<>(); for (ChatRoom room : rooms) { - if (room.hasCapability(ChatRoomCapabilities.OneToOne.toInt()) - && room.getHistorySize() == 0) { - // Hide 1-1 chat rooms without messages - } else { + // Hide 1-1 chat rooms without messages + if (!(room.hasCapability(ChatRoomCapabilities.OneToOne.toInt()) + && room.getHistorySize() == 0)) { newRooms.add(room); } } @@ -397,9 +357,6 @@ public final class LinphoneUtils { public static void showTrustDeniedDialog(Context context) { final Dialog dialog = new Dialog(context); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); - dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); - dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); - dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); Drawable d = new ColorDrawable(ContextCompat.getColor(context, R.color.dark_grey_color)); d.setAlpha(200); dialog.setContentView(R.layout.dialog); @@ -440,18 +397,34 @@ public final class LinphoneUtils { new View.OnClickListener() { @Override public void onClick(View view) { - CallLog[] logs = - LinphoneManager.getLcIfManagerNotDestroyedOrNull().getCallLogs(); + CallLog[] logs = LinphoneManager.getCore().getCallLogs(); CallLog lastLog = logs[0]; Address addressToCall = lastLog.getDir() == Call.Dir.Incoming ? lastLog.getFromAddress() : lastLog.getToAddress(); - LinphoneManager.getInstance() + LinphoneManager.getCallManager() .newOutgoingCall(addressToCall.asString(), null); dialog.dismiss(); } }); dialog.show(); } + + public static Dialog getDialog(Context context, String text) { + final Dialog dialog = new Dialog(context); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + Drawable d = new ColorDrawable(ContextCompat.getColor(context, R.color.dark_grey_color)); + d.setAlpha(200); + dialog.setContentView(R.layout.dialog); + dialog.getWindow() + .setLayout( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.MATCH_PARENT); + dialog.getWindow().setBackgroundDrawable(d); + + TextView customText = dialog.findViewById(R.id.dialog_message); + customText.setText(text); + return dialog; + } } diff --git a/app/src/main/java/org/linphone/utils/SelectableAdapter.java b/app/src/main/java/org/linphone/utils/SelectableAdapter.java index ebc0203c2..646a0f565 100644 --- a/app/src/main/java/org/linphone/utils/SelectableAdapter.java +++ b/app/src/main/java/org/linphone/utils/SelectableAdapter.java @@ -96,7 +96,7 @@ public abstract class SelectableAdapter } public void selectAll() { - for (Integer i = 0; i < getItemCount(); i++) { + for (int i = 0; i < getItemCount(); i++) { mSelectedItems.put(i, true); notifyDataSetChanged(); } diff --git a/app/src/main/java/org/linphone/utils/SelectableHelper.java b/app/src/main/java/org/linphone/utils/SelectableHelper.java index ad183ab2d..6208f010b 100644 --- a/app/src/main/java/org/linphone/utils/SelectableHelper.java +++ b/app/src/main/java/org/linphone/utils/SelectableHelper.java @@ -26,7 +26,6 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import androidx.recyclerview.widget.RecyclerView; -import org.linphone.LinphoneActivity; import org.linphone.R; public class SelectableHelper { @@ -34,7 +33,6 @@ public class SelectableHelper { private final ImageView mSelectAllButton; private final ImageView mDeselectAllButton; private final ImageView mDeleteSelectionButton; - private final ImageView mCancelButton; private final LinearLayout mEditTopBar; private final LinearLayout mTopBar; private SelectableAdapter mAdapter; @@ -49,8 +47,8 @@ public class SelectableHelper { mEditTopBar = view.findViewById(R.id.edit_list); mTopBar = view.findViewById(R.id.top_bar); - mCancelButton = view.findViewById(R.id.cancel); - mCancelButton.setOnClickListener( + ImageView cancelButton = view.findViewById(R.id.cancel); + cancelButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { @@ -99,9 +97,9 @@ public class SelectableHelper { @Override public void onClick(View v) { final Dialog dialog = - LinphoneActivity.instance() - .displayDialog( - mContext.getString(mDialogDeleteMessageResourceId)); + LinphoneUtils.getDialog( + mContext, + mContext.getString(mDialogDeleteMessageResourceId)); Button delete = dialog.findViewById(R.id.dialog_delete_button); Button cancel = dialog.findViewById(R.id.dialog_cancel_button); @@ -179,7 +177,7 @@ public class SelectableHelper { } private Object[] getSelectedObjects() { - Object objects[] = new Object[mAdapter.getSelectedItemCount()]; + Object[] objects = new Object[mAdapter.getSelectedItemCount()]; int index = 0; for (Integer i : mAdapter.getSelectedItems()) { objects[index] = mAdapter.getItem(i); diff --git a/app/src/main/java/org/linphone/views/AddressAware.java b/app/src/main/java/org/linphone/views/AddressAware.java index 15dc50094..95341a372 100644 --- a/app/src/main/java/org/linphone/views/AddressAware.java +++ b/app/src/main/java/org/linphone/views/AddressAware.java @@ -2,7 +2,7 @@ package org.linphone.views; /* AddressAwareWidget.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France +Copyright (C) 2017 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 diff --git a/app/src/main/java/org/linphone/views/AddressText.java b/app/src/main/java/org/linphone/views/AddressText.java index 8d932e406..f86ec448a 100644 --- a/app/src/main/java/org/linphone/views/AddressText.java +++ b/app/src/main/java/org/linphone/views/AddressText.java @@ -25,25 +25,23 @@ import android.graphics.Paint; import android.util.AttributeSet; import android.util.TypedValue; import android.widget.EditText; -import org.linphone.LinphoneManager.AddressType; import org.linphone.R; -import org.linphone.fragments.DialerFragment; @SuppressLint("AppCompatCustomView") public class AddressText extends EditText implements AddressType { - private String mDisplayedName; private final Paint mTestPaint; - private DialerFragment mDialer; + private AddressChangedListener mAddressListener; public AddressText(Context context, AttributeSet attrs) { super(context, attrs); mTestPaint = new Paint(); mTestPaint.set(this.getPaint()); + mAddressListener = null; } - public void clearDisplayedName() { + private void clearDisplayedName() { mDisplayedName = null; } @@ -69,8 +67,8 @@ public class AddressText extends EditText implements AddressType { refitText(getWidth(), getHeight()); - if (mDialer != null) { - mDialer.enableDisableAddContact(); + if (mAddressListener != null) { + mAddressListener.onAddressChanged(); } super.onTextChanged(text, start, before, after); @@ -125,7 +123,11 @@ public class AddressText extends EditText implements AddressType { setMeasuredDimension(parentWidth, height); } - public void setDialerFragment(DialerFragment dialerFragment) { - mDialer = dialerFragment; + public void setAddressListener(AddressChangedListener listener) { + mAddressListener = listener; + } + + public interface AddressChangedListener { + void onAddressChanged(); } } diff --git a/app/src/main/java/org/linphone/views/AddressType.java b/app/src/main/java/org/linphone/views/AddressType.java new file mode 100644 index 000000000..b32213c9c --- /dev/null +++ b/app/src/main/java/org/linphone/views/AddressType.java @@ -0,0 +1,26 @@ +package org.linphone.views; + +/* +AddressType.java +Copyright (C) 2017 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +public interface AddressType { + CharSequence getText(); + + String getDisplayedName(); +} diff --git a/app/src/main/java/org/linphone/views/AsyncBitmap.java b/app/src/main/java/org/linphone/views/AsyncBitmap.java index c043a11ea..baa2a7ae7 100644 --- a/app/src/main/java/org/linphone/views/AsyncBitmap.java +++ b/app/src/main/java/org/linphone/views/AsyncBitmap.java @@ -24,7 +24,7 @@ import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import java.lang.ref.WeakReference; -public class AsyncBitmap extends BitmapDrawable { +class AsyncBitmap extends BitmapDrawable { private final WeakReference mBitmapWorkerTaskReference; public AsyncBitmap(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { diff --git a/app/src/main/java/org/linphone/views/BitmapWorkerTask.java b/app/src/main/java/org/linphone/views/BitmapWorkerTask.java index 20930181e..7ddbc5f6c 100644 --- a/app/src/main/java/org/linphone/views/BitmapWorkerTask.java +++ b/app/src/main/java/org/linphone/views/BitmapWorkerTask.java @@ -33,20 +33,19 @@ import android.widget.ImageView; import android.widget.RelativeLayout; import java.io.IOException; import java.lang.ref.WeakReference; +import org.linphone.LinphoneService; import org.linphone.core.tools.Log; import org.linphone.utils.FileUtils; import org.linphone.utils.ImageUtils; public class BitmapWorkerTask extends AsyncTask { - public String path; + private String path; private final WeakReference mImageViewReference; - private final Context mContext; private final Bitmap mDefaultBitmap; private final int mImageViewHeight; - public BitmapWorkerTask(Context context, ImageView imageView, Bitmap defaultBitmap) { - mContext = context; + public BitmapWorkerTask(ImageView imageView, Bitmap defaultBitmap) { mDefaultBitmap = defaultBitmap; path = null; // Use a WeakReference to ensure the ImageView can be garbage collected @@ -54,7 +53,7 @@ public class BitmapWorkerTask extends AsyncTask { mImageViewHeight = imageView.getMeasuredHeight(); } - public static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { + private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { if (imageView != null) { final Drawable drawable = imageView.getDrawable(); if (drawable instanceof AsyncBitmap) { @@ -77,6 +76,7 @@ public class BitmapWorkerTask extends AsyncTask { // Decode image in background. @Override protected Bitmap doInBackground(String... params) { + Context context = LinphoneService.instance(); path = params[0]; Bitmap bm = null; Bitmap thumbnail = null; @@ -85,7 +85,7 @@ public class BitmapWorkerTask extends AsyncTask { try { bm = MediaStore.Images.Media.getBitmap( - mContext.getContentResolver(), Uri.parse(path)); + context.getContentResolver(), Uri.parse(path)); } catch (IOException e) { Log.e(e); } @@ -146,15 +146,16 @@ public class BitmapWorkerTask extends AsyncTask { bitmap = null; } if (mImageViewReference != null && bitmap != null) { + Context context = LinphoneService.instance(); final ImageView imageView = mImageViewReference.get(); final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); if (this == bitmapWorkerTask && imageView != null) { imageView.setImageBitmap(bitmap); - if (bitmap.getWidth() > ImageUtils.dpToPixels(mContext, 300)) { + if (bitmap.getWidth() > ImageUtils.dpToPixels(context, 300)) { RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( bitmap.getWidth(), ViewGroup.LayoutParams.WRAP_CONTENT); - int margin = (int) ImageUtils.dpToPixels(mContext, 5); + int margin = (int) ImageUtils.dpToPixels(context, 5); params.setMargins(margin, margin, margin, margin); imageView.setLayoutParams(params); imageView.invalidate(); diff --git a/app/src/main/java/org/linphone/views/CallButton.java b/app/src/main/java/org/linphone/views/CallButton.java index 3b0b59293..5c9eedcfb 100644 --- a/app/src/main/java/org/linphone/views/CallButton.java +++ b/app/src/main/java/org/linphone/views/CallButton.java @@ -28,6 +28,7 @@ import android.widget.ImageView; import org.linphone.LinphoneManager; import org.linphone.core.Call; import org.linphone.core.CallLog; +import org.linphone.core.Core; import org.linphone.core.ProxyConfig; import org.linphone.settings.LinphonePreferences; @@ -45,20 +46,13 @@ public class CallButton extends ImageView implements OnClickListener, AddressAwa mAddress = a; } - public void setExternalClickListener(OnClickListener e) { - setOnClickListener(e); - } - - public void resetClickListener() { - setOnClickListener(this); - } - public void onClick(View v) { if (mAddress.getText().length() > 0) { - LinphoneManager.getInstance().newOutgoingCall(mAddress); + LinphoneManager.getCallManager().newOutgoingCall(mAddress); } else { if (LinphonePreferences.instance().isBisFeatureEnabled()) { - CallLog[] logs = LinphoneManager.getLc().getCallLogs(); + Core core = LinphoneManager.getCore(); + CallLog[] logs = core.getCallLogs(); CallLog log = null; for (CallLog l : logs) { if (l.getDir() == Call.Dir.Outgoing) { @@ -70,7 +64,7 @@ public class CallButton extends ImageView implements OnClickListener, AddressAwa return; } - ProxyConfig lpc = LinphoneManager.getLc().getDefaultProxyConfig(); + ProxyConfig lpc = core.getDefaultProxyConfig(); if (lpc != null && log.getToAddress().getDomain().equals(lpc.getDomain())) { mAddress.setText(log.getToAddress().getUsername()); } else { diff --git a/app/src/main/java/org/linphone/views/CallIncomingDeclineButton.java b/app/src/main/java/org/linphone/views/CallIncomingDeclineButton.java index 6cf86cae6..d4fee8aca 100644 --- a/app/src/main/java/org/linphone/views/CallIncomingDeclineButton.java +++ b/app/src/main/java/org/linphone/views/CallIncomingDeclineButton.java @@ -29,7 +29,6 @@ import org.linphone.R; public class CallIncomingDeclineButton extends LinearLayout implements View.OnClickListener, View.OnTouchListener { - private LinearLayout mRoot; private boolean mUseSliderMode = false; private CallIncomingButtonListener mListener; private View mAnswerButton; @@ -68,9 +67,9 @@ public class CallIncomingDeclineButton extends LinearLayout private void init() { inflate(getContext(), R.layout.call_incoming_decline_button, this); - mRoot = findViewById(R.id.root); - mRoot.setOnClickListener(this); - mRoot.setOnTouchListener(this); + LinearLayout root = findViewById(R.id.root); + root.setOnClickListener(this); + root.setOnTouchListener(this); mScreenWidth = getResources().getDisplayMetrics().widthPixels; } diff --git a/app/src/main/java/org/linphone/views/ContactAvatar.java b/app/src/main/java/org/linphone/views/ContactAvatar.java index 04fdc8d36..705b6b10a 100644 --- a/app/src/main/java/org/linphone/views/ContactAvatar.java +++ b/app/src/main/java/org/linphone/views/ContactAvatar.java @@ -99,7 +99,7 @@ public class ContactAvatar { } } - public static void displayAvatar( + private static void displayAvatar( String displayName, View v, boolean showBorder, int maskResource) { if (displayName == null || v == null) return; @@ -145,7 +145,7 @@ public class ContactAvatar { setSecurityLevel(securityLevel, v); } - public static void displayAvatar( + private static void displayAvatar( LinphoneContact contact, View v, boolean showBorder, int maskResource) { if (contact == null || v == null) return; diff --git a/app/src/main/java/org/linphone/views/ContactSelectView.java b/app/src/main/java/org/linphone/views/ContactSelectView.java index 2a331db6f..d43e2e583 100644 --- a/app/src/main/java/org/linphone/views/ContactSelectView.java +++ b/app/src/main/java/org/linphone/views/ContactSelectView.java @@ -48,7 +48,7 @@ public class ContactSelectView extends View { if (ca.getContact() != null) { mContactName.setText(ca.getContact().getFirstName()); } else { - LinphoneManager.getLc() + LinphoneManager.getCore() .createFriendWithAddress(ca.getAddressAsDisplayableString()) .getName(); mContactName.setText(ca.getAddressAsDisplayableString()); diff --git a/app/src/main/java/org/linphone/views/Digit.java b/app/src/main/java/org/linphone/views/Digit.java index 5d092fedd..9701ad8a7 100644 --- a/app/src/main/java/org/linphone/views/Digit.java +++ b/app/src/main/java/org/linphone/views/Digit.java @@ -31,7 +31,6 @@ import android.widget.Toast; import org.linphone.LinphoneManager; import org.linphone.LinphoneService; import org.linphone.R; -import org.linphone.call.CallActivity; import org.linphone.core.Core; import org.linphone.core.tools.Log; import org.linphone.settings.LinphonePreferences; @@ -110,11 +109,11 @@ public class Digit extends Button implements AddressAware { public void onClick(View v) { if (mPlayDtmf) { if (!linphoneServiceReady()) return; - Core lc = LinphoneManager.getLc(); - lc.stopDtmf(); + Core core = LinphoneManager.getCore(); + core.stopDtmf(); mIsDtmfStarted = false; - if (lc.inCall()) { - lc.getCurrentCall().sendDtmf(mKeyCode); + if (core.inCall()) { + core.getCurrentCall().sendDtmf(mKeyCode); } } @@ -148,9 +147,9 @@ public class Digit extends Button implements AddressAware { LinphonePreferences.instance().setDebugEnabled(false); } if (which == 1) { - Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - lc.uploadLogCollection(); + Core core = LinphoneManager.getCore(); + if (core != null) { + core.uploadLogCollection(); } } } @@ -175,17 +174,16 @@ public class Digit extends Button implements AddressAware { if (!mPlayDtmf) return false; if (!linphoneServiceReady()) return true; - if (CallActivity.isInstanciated()) { - CallActivity.instance().resetControlsHidingCallBack(); - } + LinphoneManager.getCallManager().resetCallControlsHidingTimer(); - Core lc = LinphoneManager.getLc(); + Core core = LinphoneManager.getCore(); if (event.getAction() == MotionEvent.ACTION_DOWN && !mIsDtmfStarted) { - LinphoneManager.getInstance().playDtmf(getContext().getContentResolver(), mKeyCode); + LinphoneManager.getCallManager() + .playDtmf(getContext().getContentResolver(), mKeyCode); mIsDtmfStarted = true; } else { if (event.getAction() == MotionEvent.ACTION_UP) { - lc.stopDtmf(); + core.stopDtmf(); mIsDtmfStarted = false; } } @@ -194,20 +192,20 @@ public class Digit extends Button implements AddressAware { public boolean onLongClick(View v) { int id = v.getId(); - Core lc = LinphoneManager.getLc(); + Core core = LinphoneManager.getCore(); if (mPlayDtmf) { if (!linphoneServiceReady()) return true; // Called if "0+" dtmf - lc.stopDtmf(); + core.stopDtmf(); } - if (id == R.id.Digit1 && lc.getCalls().length == 0) { + if (id == R.id.Digit1 && core.getCalls().length == 0) { String voiceMail = LinphonePreferences.instance().getVoiceMailUri(); mAddress.getEditableText().clear(); if (voiceMail != null) { mAddress.getEditableText().append(voiceMail); - LinphoneManager.getInstance().newOutgoingCall(mAddress); + LinphoneManager.getCallManager().newOutgoingCall(mAddress); } return true; } diff --git a/app/src/main/java/org/linphone/views/LedPreference.java b/app/src/main/java/org/linphone/views/LedPreference.java deleted file mode 100644 index c234f76e1..000000000 --- a/app/src/main/java/org/linphone/views/LedPreference.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.linphone.views; - -/* -LedPreference.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -import android.content.Context; -import android.preference.Preference; -import android.view.View; -import android.widget.ImageView; -import org.linphone.R; - -public class LedPreference extends Preference { - private int mLedDrawable; - - public LedPreference(Context context) { - super(context); - mLedDrawable = R.drawable.led_disconnected; - setWidgetLayoutResource(R.layout.preference_led); - } - - @Override - protected void onBindView(final View view) { - super.onBindView(view); - - final ImageView imageView = view.findViewById(R.id.led); - if (imageView != null) { - imageView.setImageResource(mLedDrawable); - } - } - - public void setLed(int led) { - mLedDrawable = led; - notifyChanged(); - } -} diff --git a/app/src/main/java/org/linphone/views/LinphoneGL2JNIViewOverlay.java b/app/src/main/java/org/linphone/views/LinphoneGL2JNIViewOverlay.java index 156c21ed9..25eb250b8 100644 --- a/app/src/main/java/org/linphone/views/LinphoneGL2JNIViewOverlay.java +++ b/app/src/main/java/org/linphone/views/LinphoneGL2JNIViewOverlay.java @@ -30,11 +30,12 @@ import android.view.MotionEvent; import android.view.SurfaceView; import android.view.View; import android.view.WindowManager; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.LinphoneService; +import org.linphone.call.CallActivity; import org.linphone.core.Call; import org.linphone.core.CallParams; +import org.linphone.core.Core; import org.linphone.mediastream.Version; import org.linphone.mediastream.video.AndroidVideoWindowImpl; @@ -76,7 +77,7 @@ public class LinphoneGL2JNIViewOverlay extends org.linphone.mediastream.video.di new AndroidVideoWindowImpl.VideoWindowListener() { public void onVideoRenderingSurfaceReady( AndroidVideoWindowImpl vw, SurfaceView surface) { - LinphoneManager.getLc().setNativeVideoWindowId(vw); + LinphoneManager.getCore().setNativeVideoWindowId(vw); } public void onVideoRenderingSurfaceDestroyed( @@ -88,18 +89,19 @@ public class LinphoneGL2JNIViewOverlay extends org.linphone.mediastream.video.di public void onVideoPreviewSurfaceDestroyed(AndroidVideoWindowImpl vw) {} }); - Call call = LinphoneManager.getLc().getCurrentCall(); + Core core = LinphoneManager.getCore(); + Call call = core.getCurrentCall(); CallParams callParams = call.getCurrentParams(); mParams.width = callParams.getReceivedVideoDefinition().getWidth(); mParams.height = callParams.getReceivedVideoDefinition().getHeight(); - LinphoneManager.getLc().setNativeVideoWindowId(mAndroidVideoWindowImpl); + core.setNativeVideoWindowId(mAndroidVideoWindowImpl); setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { Context context = LinphoneService.instance(); - Intent intent = new Intent(context, LinphoneActivity.class); + Intent intent = new Intent(context, CallActivity.class); context.startActivity(intent); } }); diff --git a/app/src/main/java/org/linphone/views/LinphoneTextureViewOverlay.java b/app/src/main/java/org/linphone/views/LinphoneTextureViewOverlay.java index 74b653643..9ecc57649 100644 --- a/app/src/main/java/org/linphone/views/LinphoneTextureViewOverlay.java +++ b/app/src/main/java/org/linphone/views/LinphoneTextureViewOverlay.java @@ -32,9 +32,9 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.RelativeLayout; -import org.linphone.LinphoneActivity; import org.linphone.LinphoneManager; import org.linphone.LinphoneService; +import org.linphone.call.CallActivity; import org.linphone.core.Call; import org.linphone.core.CallParams; import org.linphone.core.Core; @@ -47,7 +47,6 @@ public class LinphoneTextureViewOverlay extends RelativeLayout implements Linpho private final DisplayMetrics mMetrics; private float mX, mY, mTouchX, mTouchY; private boolean mDragEnabled; - private TextureView mRemoteVideo, mLocalPreview; public LinphoneTextureViewOverlay(Context context, AttributeSet attrs, int defStyle) { super(context, attrs); @@ -71,20 +70,21 @@ public class LinphoneTextureViewOverlay extends RelativeLayout implements Linpho mMetrics = new DisplayMetrics(); mWindowManager.getDefaultDisplay().getMetrics(mMetrics); - Call call = LinphoneManager.getLc().getCurrentCall(); + Core core = LinphoneManager.getCore(); + Call call = core.getCurrentCall(); CallParams callParams = call.getCurrentParams(); mParams.width = callParams.getReceivedVideoDefinition().getWidth(); mParams.height = callParams.getReceivedVideoDefinition().getHeight(); - mRemoteVideo = new TextureView(context); - addView(mRemoteVideo); - mLocalPreview = new TextureView(context); - addView(mLocalPreview); + TextureView remoteVideo = new TextureView(context); + addView(remoteVideo); + TextureView localPreview = new TextureView(context); + addView(localPreview); RelativeLayout.LayoutParams remoteVideoParams = new RelativeLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - mRemoteVideo.setLayoutParams(remoteVideoParams); + remoteVideo.setLayoutParams(remoteVideoParams); VideoDefinition videoSize = call.getCurrentParams().getSentVideoDefinition(); int localPreviewWidth = videoSize.getWidth(); @@ -97,18 +97,17 @@ public class LinphoneTextureViewOverlay extends RelativeLayout implements Linpho new RelativeLayout.LayoutParams(localPreviewWidth, localPreviewHeight); localPreviewParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, TRUE); localPreviewParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE); - mLocalPreview.setLayoutParams(localPreviewParams); + localPreview.setLayoutParams(localPreviewParams); - Core lc = LinphoneManager.getLc(); - lc.setNativeVideoWindowId(mRemoteVideo); - lc.setNativePreviewWindowId(mLocalPreview); + core.setNativeVideoWindowId(remoteVideo); + core.setNativePreviewWindowId(localPreview); setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { Context context = LinphoneService.instance(); - Intent intent = new Intent(context, LinphoneActivity.class); + Intent intent = new Intent(context, CallActivity.class); context.startActivity(intent); } }); diff --git a/app/src/main/java/org/linphone/xmlrpc/XmlRpcHelper.java b/app/src/main/java/org/linphone/xmlrpc/XmlRpcHelper.java index 79bf8e734..23f7d46b7 100644 --- a/app/src/main/java/org/linphone/xmlrpc/XmlRpcHelper.java +++ b/app/src/main/java/org/linphone/xmlrpc/XmlRpcHelper.java @@ -48,7 +48,7 @@ public class XmlRpcHelper { public XmlRpcHelper() { mXmlRpcSession = - LinphoneManager.getLcIfManagerNotDestroyedOrNull() + LinphoneManager.getCore() .createXmlRpcSession( LinphonePreferences.instance() .getInAppPurchaseValidatingServerUrl()); diff --git a/app/src/main/java/org/linphone/xmlrpc/XmlRpcListenerBase.java b/app/src/main/java/org/linphone/xmlrpc/XmlRpcListenerBase.java index 5d49d601f..f5b3ca463 100644 --- a/app/src/main/java/org/linphone/xmlrpc/XmlRpcListenerBase.java +++ b/app/src/main/java/org/linphone/xmlrpc/XmlRpcListenerBase.java @@ -21,92 +21,47 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. public class XmlRpcListenerBase implements XmlRpcListener { @Override - public void onError() { - // TODO Auto-generated method stub - - } + public void onError() {} @Override - public void onAccountCreated() { - // TODO Auto-generated method stub - - } + public void onAccountCreated() {} @Override - public void onAccountExpireFetched(String result) { - // TODO Auto-generated method stub - - } + public void onAccountExpireFetched(String result) {} @Override - public void onAccountActivated() { - // TODO Auto-generated method stub - - } + public void onAccountActivated() {} @Override - public void onAccountActivatedFetched() { - // TODO Auto-generated method stub - - } + public void onAccountActivatedFetched() {} @Override - public void onTrialAccountFetched(boolean isTrial) { - // TODO Auto-generated method stub - - } + public void onTrialAccountFetched(boolean isTrial) {} @Override - public void onAccountFetched() { - // TODO Auto-generated method stub - - } + public void onAccountFetched() {} @Override - public void onAccountEmailChanged() { - // TODO Auto-generated method stub - - } + public void onAccountEmailChanged() {} @Override - public void onAccountPasswordChanged() { - // TODO Auto-generated method stub - - } + public void onAccountPasswordChanged() {} @Override - public void onRecoverPasswordLinkSent() { - // TODO Auto-generated method stub - - } + public void onRecoverPasswordLinkSent() {} @Override - public void onActivateAccountLinkSent() { - // TODO Auto-generated method stub - - } + public void onActivateAccountLinkSent() {} @Override - public void onAccountExpireUpdated() { - // TODO Auto-generated method stub - - } + public void onAccountExpireUpdated() {} @Override - public void onSignatureVerified(boolean success) { - // TODO Auto-generated method stub - - } + public void onSignatureVerified(boolean success) {} @Override - public void onUsernameSent() { - // TODO Auto-generated method stub - - } + public void onUsernameSent() {} @Override - public void onRemoteProvisioningFilenameSent(String result) { - // TODO Auto-generated method stub - - } + public void onRemoteProvisioningFilenameSent(String result) {} } diff --git a/app/src/main/res/drawable/launch_screen.xml b/app/src/main/res/drawable/launch_screen.xml new file mode 100644 index 000000000..3e0583649 --- /dev/null +++ b/app/src/main/res/drawable/launch_screen.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/about.xml b/app/src/main/res/layout-land/about.xml index 878d16e86..9f5fa2cab 100644 --- a/app/src/main/res/layout-land/about.xml +++ b/app/src/main/res/layout-land/about.xml @@ -1,172 +1,164 @@ - + android:layout_height="match_parent"> - + android:layout_height="match_parent" + android:orientation="vertical"> + android:layout_gravity="center" + android:layout_weight="1" + android:background="@color/dark_grey_color" + android:baselineAligned="false" + android:padding="20dp" + android:orientation="horizontal"> + android:gravity="center" + android:orientation="vertical"> - + + + android:paddingTop="5dp" + android:text="@string/app_name" + android:visibility="gone" /> - - - - - - - - - - - - - - + android:text="@string/app_description" /> + + + + + + + + + + + + + + + + + + + + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:paddingTop="20dp" + android:orientation="horizontal"> - - - - - + android:layout_margin="5dp" + android:background="@drawable/assistant_button" + android:textColor="@drawable/assistant_button_text_color" + style="@style/button_font" + android:text="@string/menu_send_log" /> - - - - -