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" /> - - - - -