API 35 update

This commit is contained in:
Christophe Deschamps 2025-10-21 11:52:25 +02:00
parent baa79d9982
commit 7ba3b7d78e
20 changed files with 1106 additions and 5 deletions

View file

@ -86,10 +86,10 @@ android {
jvmTarget = '17'
}
compileSdkVersion 34
compileSdk 35
defaultConfig {
minSdkVersion 23
targetSdkVersion 34
targetSdkVersion 35
versionCode appVersionCode
versionName "${project.version}"
applicationId packageName

View file

@ -31,6 +31,7 @@ import coil.decode.SvgDecoder
import coil.decode.VideoFrameDecoder
import coil.disk.DiskCache
import coil.memory.MemoryCache
import org.linphone.compatibility.Compatibility
import org.linphone.core.*
import org.linphone.core.tools.Log
import org.linphone.mediastream.Version
@ -83,6 +84,7 @@ class LinphoneApplication : Application(), ImageLoaderFactory {
Log.i("[Application] Core config & preferences created")
wakeLock.release()
Compatibility.setupAppStartupListener(context)
}
fun ensureCoreExists(

View file

@ -32,8 +32,10 @@ import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.annotation.StringRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.doOnAttach
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.FragmentContainerView
import androidx.lifecycle.MutableLiveData
@ -87,6 +89,7 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
private lateinit var tabsFragment: FragmentContainerView
private lateinit var statusFragment: FragmentContainerView
private var api35filler: View? = null
private var overlayX = 0f
private var overlayY = 0f
@ -185,6 +188,7 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
tabsFragment = findViewById(R.id.tabs_fragment)
statusFragment = findViewById(R.id.status_fragment)
api35filler = findViewById<View>(R.id.api35filler)
binding.root.doOnAttach {
Log.i("[Main Activity] Report UI has been fully drawn (TTFD)")
@ -314,6 +318,14 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
private fun updateTabsFragmentVisibility() {
tabsFragment.visibility = if (shouldTabsBeVisibleDependingOnDestination && shouldTabsBeVisibleDueToOrientationAndKeyboard) View.VISIBLE else View.GONE
api35filler?.background = if (tabsFragment.isVisible) {
AppCompatResources.getDrawable(
coreContext.context,
R.drawable.footer_button
)
} else {
null
}
}
private fun handleIntentParams(intent: Intent) {

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-android
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.linphone.compatibility
import android.app.ActivityManager
import android.app.ApplicationStartInfo
import android.content.Context
import android.os.Build
import androidx.annotation.RequiresApi
import java.util.concurrent.Executors
import org.linphone.core.tools.Log
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
class Api35Compatibility {
companion object {
private const val TAG = "[API 35 Compatibility]"
fun setupAppStartupListener(context: Context) {
try {
val activityManager = context.getSystemService(ActivityManager::class.java)
activityManager.addApplicationStartInfoCompletionListener(
Executors.newSingleThreadExecutor()
) { info ->
Log.i("==== Current startup information dump ====")
Log.i("TYPE = ${startupTypeToString(info.startType)}")
Log.i("STATE = ${startupStateToString(info.startupState)}")
Log.i("REASON = ${startupReasonToString(info.reason)}")
Log.i("FORCE STOPPED = ${if (info.wasForceStopped()) "yes" else "no"}")
Log.i("PROCESS NAME = ${info.processName}")
Log.i("=========================================")
}
} catch (iae: IllegalArgumentException) {
Log.e("$TAG Can't add application start info completion listener: $iae")
}
}
private fun startupTypeToString(type: Int): String {
return when (type) {
ApplicationStartInfo.START_TYPE_COLD -> "Cold"
ApplicationStartInfo.START_TYPE_HOT -> "Hot"
ApplicationStartInfo.START_TYPE_UNSET -> "Unset"
ApplicationStartInfo.START_TYPE_WARM -> "Warm"
else -> "Unexpected ($type)"
}
}
private fun startupStateToString(state: Int): String {
return when (state) {
ApplicationStartInfo.STARTUP_STATE_STARTED -> "Started"
ApplicationStartInfo.STARTUP_STATE_ERROR -> "Error"
ApplicationStartInfo.STARTUP_STATE_FIRST_FRAME_DRAWN -> "First frame drawn"
else -> "Unexpected ($state)"
}
}
private fun startupReasonToString(reason: Int): String {
return when (reason) {
ApplicationStartInfo.START_REASON_ALARM -> "Alarm"
ApplicationStartInfo.START_REASON_BACKUP -> "Backup"
ApplicationStartInfo.START_REASON_BOOT_COMPLETE -> "Boot complete"
ApplicationStartInfo.START_REASON_BROADCAST -> "Broadcast"
ApplicationStartInfo.START_REASON_CONTENT_PROVIDER -> "Content provider"
ApplicationStartInfo.START_REASON_JOB -> "Job"
ApplicationStartInfo.START_REASON_LAUNCHER -> "Launcher"
ApplicationStartInfo.START_REASON_LAUNCHER_RECENTS -> "Launcher (recents)"
ApplicationStartInfo.START_REASON_OTHER -> "Other"
ApplicationStartInfo.START_REASON_PUSH -> "Push"
ApplicationStartInfo.START_REASON_SERVICE -> "Service"
ApplicationStartInfo.START_REASON_START_ACTIVITY -> "Start Activity"
else -> "Unexpected ($reason)"
}
}
}
}

View file

@ -19,6 +19,7 @@
*/
package org.linphone.compatibility
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Notification
import android.app.PendingIntent
@ -48,8 +49,17 @@ import org.linphone.notifications.NotificationsManager
import org.linphone.telecom.NativeCallWrapper
@Suppress("DEPRECATION")
@SuppressLint("NewApi")
class Compatibility {
companion object {
const val BLUETOOTH_CONNECT = "android.permission.BLUETOOTH_CONNECT"
fun setupAppStartupListener(context: Context) {
if (Version.sdkAboveOrEqual(Version.API35_ANDROID_15_VANILLA_ICE_CREAM)) {
Api35Compatibility.setupAppStartupListener(context)
}
}
fun hasPermission(context: Context, permission: String): Boolean {
return Api23Compatibility.hasPermission(context, permission)
}

View file

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="org.linphone.activities.main.viewmodels.SharedMainViewModel" />
<variable
name="callOverlayViewModel"
type="org.linphone.activities.main.viewmodels.CallOverlayViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/root_coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/backgroundColor">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/status_fragment"
android:name="org.linphone.activities.main.fragments.StatusFragment"
android:layout_width="match_parent"
android:layout_height="90dp"
android:layout_alignParentTop="true"
tools:layout="@layout/status_fragment" />
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/side_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/status_fragment">
<include
android:id="@+id/content"
layout="@layout/main_activity_content"/>
<!-- Side Menu -->
<RelativeLayout
android:id="@+id/side_menu_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="left">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/side_menu_fragment"
android:name="org.linphone.activities.main.sidemenu.fragments.SideMenuFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="@layout/side_menu_fragment" />
</RelativeLayout>
</androidx.drawerlayout.widget.DrawerLayout>
<include
android:id="@+id/call_overlay"
layout="@layout/call_overlay"
android:layout_width="@dimen/call_overlay_size"
android:layout_height="@dimen/call_overlay_size"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
tools:visibility="@{callOverlayViewModel.displayCallOverlay}"/>
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- For proper snack bar placement -->
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/footer_button"
android:layout_toRightOf="@id/tabs_fragment">
<RelativeLayout
android:layout_width="match_parent"
android:background="@color/white_color"
android:layout_marginRight="48dp"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="true"
app:navGraph="@navigation/main_nav_graph"
tools:layout="@layout/dialer_fragment" />
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/tabs_fragment"
android:name="org.linphone.activities.main.fragments.TabsFragment"
android:layout_width="@dimen/main_activity_tabs_fragment_size"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
tools:layout="@layout/tabs_fragment"/>
</RelativeLayout>

View file

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View"/>
<variable
name="menuClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="refreshClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="viewModel"
type="org.linphone.activities.main.viewmodels.StatusViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:background="@drawable/footer_button"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:background="?attr/accentColor"
android:gravity="bottom"
android:layout_marginRight="48dp"
android:layout_height="90dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/status_fragment_size"
android:orientation="horizontal">
<ImageView
android:id="@+id/menu_button"
android:onClick="@{menuClickListener}"
android:contentDescription="@string/content_description_toggle_side_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerInParent="true"
android:padding="10dp"
android:src="@drawable/menu" />
<ImageView
android:id="@+id/status_led"
android:background="@drawable/status_led_background"
android:src="@{viewModel.registrationStatusDrawable, default=@drawable/led_not_registered}"
android:onClick="@{refreshClickListener}"
android:contentDescription="@{viewModel.registrationStatusText}"
android:layout_width="20dp"
android:layout_height="wrap_content"
android:padding="2dp"
android:layout_centerInParent="true"
android:layout_toRightOf="@id/menu_button"
android:adjustViewBounds="true" />
<TextView
android:text="@{viewModel.registrationStatusText, default=@string/status_not_connected}"
android:onClick="@{refreshClickListener}"
android:textColor="?attr/accentTextColor"
android:textSize="15sp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/status_led"
android:gravity="center_vertical"
android:paddingLeft="5dp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:contentDescription="@string/content_description_voice_mail"
android:layout_centerVertical="true"
android:layout_toLeftOf="@id/voice_mail_count"
android:gravity="center_vertical"
android:src="@drawable/voicemail"
android:visibility="@{viewModel.voiceMailCount > 0 ? View.VISIBLE : View.GONE, default=gone}" />
<TextView
android:id="@+id/voice_mail_count"
android:text="@{viewModel.voiceMailCount.toString()}"
android:visibility="@{viewModel.voiceMailCount > 0 ? View.VISIBLE : View.GONE, default=gone}"
android:textColor="?attr/secondaryTextColor"
android:textSize="21sp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:gravity="center_vertical"
android:paddingLeft="5dp"
android:paddingRight="10dp" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</layout>

View file

@ -0,0 +1,152 @@
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View"/>
<variable
name="historyClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="contactsClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="dialerClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="chatClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="viewModel"
type="org.linphone.activities.main.viewmodels.TabsViewModel" />
</data>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
android:layout_width="@dimen/main_activity_tabs_fragment_size"
android:layout_height="match_parent"
app:layoutDescription="@xml/motion_main_activity_tabs_selector_land">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
layout_constraintGuide_percent="@{viewModel.leftAnchor, default=0.25}" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineMiddle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
layout_constraintGuide_percent="@{viewModel.middleAnchor, default=0.5}" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineBottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
layout_constraintGuide_percent="@{viewModel.rightAnchor, default=0.75}" />
<ImageView
android:id="@+id/history"
android:onClick="@{historyClickListener}"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_centerInParent="true"
android:contentDescription="@string/content_description_menu_history"
android:padding="15dp"
android:background="@drawable/footer_button"
android:src="@drawable/footer_history"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/guidelineTop" />
<TextView
android:id="@+id/history_unread_count"
style="@style/unread_count_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_marginTop="5dp"
android:gravity="center"
android:translationY="@{viewModel.historyMissedCountTranslateY}"
android:background="@{viewModel.missedCallsCount == 0 ? @drawable/hidden_unread_message_count_bg : @drawable/unread_message_count_bg}"
android:text="@{viewModel.missedCallsCount == 0 ? `` : String.valueOf(viewModel.missedCallsCount)}"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<RelativeLayout
android:id="@+id/contacts"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/footer_button"
android:onClick="@{contactsClickListener}"
app:layout_constraintTop_toTopOf="@id/guidelineTop"
app:layout_constraintBottom_toTopOf="@id/guidelineMiddle">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:contentDescription="@string/content_description_menu_contacts"
android:padding="15dp"
android:src="@drawable/footer_contacts" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/dialer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/footer_button"
android:onClick="@{dialerClickListener}"
app:layout_constraintTop_toTopOf="@id/guidelineMiddle"
app:layout_constraintBottom_toTopOf="@id/guidelineBottom">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:contentDescription="@string/content_description_menu_dialer"
android:padding="15dp"
android:src="@drawable/footer_dialer" />
</RelativeLayout>
<ImageView
android:id="@+id/chat"
android:onClick="@{chatClickListener}"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_centerInParent="true"
android:contentDescription="@string/content_description_menu_chat"
android:padding="15dp"
android:src="@drawable/footer_chat"
android:background="@drawable/footer_button"
app:layout_constraintTop_toTopOf="@id/guidelineBottom"
app:layout_constraintBottom_toBottomOf="parent" />
<TextView
android:id="@+id/chat_unread_count"
style="@style/unread_count_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_marginTop="5dp"
android:gravity="center"
android:translationY="@{viewModel.chatUnreadCountTranslateY}"
android:background="@{viewModel.unreadMessagesCount == 0 ? @drawable/hidden_unread_message_count_bg : @drawable/unread_message_count_bg}"
android:text="@{viewModel.unreadMessagesCount == 0 ? `` : String.valueOf(viewModel.unreadMessagesCount)}"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/guidelineBottom" />
<View
android:id="@+id/selector"
android:layout_width="@dimen/tabs_fragment_selector_size"
android:layout_height="0dp"
android:background="?attr/accentColor" />
</androidx.constraintlayout.motion.widget.MotionLayout>
</layout>

View file

@ -131,7 +131,7 @@
android:layout_height="match_parent"
android:layout_below="@id/address_bar"
android:layout_above="@id/controls"
android:padding="30dp"
android:padding="80dp"
android:layout_centerHorizontal="true"
android:contentDescription="@null"
android:src="@drawable/dialer_background" />

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/backgroundColor">
<View
android:layout_width="match_parent"
android:background="@color/primary_color"
android:layout_height="40dp">
</View>
<androidx.fragment.app.FragmentContainerView
android:layout_marginTop="40dp"
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/assistant_nav_graph" />
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="org.linphone.activities.main.viewmodels.SharedMainViewModel" />
<variable
name="callOverlayViewModel"
type="org.linphone.activities.main.viewmodels.CallOverlayViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/root_coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/backgroundColor">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/status_fragment"
android:name="org.linphone.activities.main.fragments.StatusFragment"
android:layout_width="match_parent"
android:layout_height="90dp"
android:layout_alignParentTop="true"
tools:layout="@layout/status_fragment" />
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/side_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/status_fragment">
<include
android:id="@+id/content"
layout="@layout/main_activity_content"/>
<!-- Side Menu -->
<RelativeLayout
android:id="@+id/side_menu_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="left">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/side_menu_fragment"
android:name="org.linphone.activities.main.sidemenu.fragments.SideMenuFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="48dp"
tools:layout="@layout/side_menu_fragment" />
</RelativeLayout>
</androidx.drawerlayout.widget.DrawerLayout>
<include
android:id="@+id/call_overlay"
layout="@layout/call_overlay"
android:layout_width="@dimen/call_overlay_size"
android:layout_height="@dimen/call_overlay_size"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
tools:visibility="@{callOverlayViewModel.displayCallOverlay}"/>
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- For proper snack bar placement -->
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/tabs_fragment">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="true"
app:navGraph="@navigation/main_nav_graph"
tools:layout="@layout/dialer_fragment" />
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/tabs_fragment"
android:name="org.linphone.activities.main.fragments.TabsFragment"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_above="@+id/api35filler"
tools:layout="@layout/tabs_fragment"/>
<View
android:id="@+id/api35filler"
android:layout_width="match_parent"
android:layout_alignParentBottom="true"
android:background="@drawable/footer_button"
android:layout_height="48dp">
</View>
</RelativeLayout>

View file

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View"/>
<variable
name="menuClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="refreshClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="viewModel"
type="org.linphone.activities.main.viewmodels.StatusViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:background="?attr/accentColor"
android:gravity="bottom"
android:layout_height="90dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/status_fragment_size"
android:orientation="horizontal">
<ImageView
android:id="@+id/menu_button"
android:onClick="@{menuClickListener}"
android:contentDescription="@string/content_description_toggle_side_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerInParent="true"
android:padding="10dp"
android:src="@drawable/menu" />
<ImageView
android:id="@+id/status_led"
android:background="@drawable/status_led_background"
android:src="@{viewModel.registrationStatusDrawable, default=@drawable/led_not_registered}"
android:onClick="@{refreshClickListener}"
android:contentDescription="@{viewModel.registrationStatusText}"
android:layout_width="20dp"
android:layout_height="wrap_content"
android:padding="2dp"
android:layout_centerInParent="true"
android:layout_toRightOf="@id/menu_button"
android:adjustViewBounds="true" />
<TextView
android:text="@{viewModel.registrationStatusText, default=@string/status_not_connected}"
android:onClick="@{refreshClickListener}"
android:textColor="?attr/accentTextColor"
android:textSize="15sp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/status_led"
android:gravity="center_vertical"
android:paddingLeft="5dp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:contentDescription="@string/content_description_voice_mail"
android:layout_centerVertical="true"
android:layout_toLeftOf="@id/voice_mail_count"
android:gravity="center_vertical"
android:src="@drawable/voicemail"
android:visibility="@{viewModel.voiceMailCount > 0 ? View.VISIBLE : View.GONE, default=gone}" />
<TextView
android:id="@+id/voice_mail_count"
android:text="@{viewModel.voiceMailCount.toString()}"
android:visibility="@{viewModel.voiceMailCount > 0 ? View.VISIBLE : View.GONE, default=gone}"
android:textColor="?attr/secondaryTextColor"
android:textSize="21sp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:gravity="center_vertical"
android:paddingLeft="5dp"
android:paddingRight="10dp" />
</RelativeLayout>
</LinearLayout>
</layout>

View file

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View"/>
<variable
name="historyClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="contactsClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="dialerClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="chatClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="viewModel"
type="org.linphone.activities.main.viewmodels.TabsViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="108dp"
android:background="@drawable/footer_button"
android:gravity="top">
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
android:layout_width="match_parent"
android:layout_height="@dimen/main_activity_tabs_fragment_size"
app:layoutDescription="@xml/motion_main_activity_tabs_selector">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineLeft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
layout_constraintGuide_percent="@{viewModel.leftAnchor, default=0.25}" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineMiddle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
layout_constraintGuide_percent="@{viewModel.middleAnchor, default=0.5}" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineRight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
layout_constraintGuide_percent="@{viewModel.rightAnchor, default=0.75}" />
<ImageView
android:id="@+id/history"
android:onClick="@{historyClickListener}"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:padding="15dp"
android:contentDescription="@string/content_description_menu_history"
android:src="@drawable/footer_history"
android:background="@drawable/footer_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="@id/guidelineLeft" />
<TextView
android:id="@+id/history_unread_count"
style="@style/unread_count_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="25dp"
android:layout_marginTop="5dp"
android:gravity="center"
android:translationY="@{viewModel.historyMissedCountTranslateY}"
android:background="@{viewModel.missedCallsCount == 0 ? @drawable/hidden_unread_message_count_bg : @drawable/unread_message_count_bg}"
android:text="@{viewModel.missedCallsCount == 0 ? `` : String.valueOf(viewModel.missedCallsCount)}"
app:layout_constraintRight_toLeftOf="@id/guidelineLeft"
app:layout_constraintTop_toTopOf="parent" />
<RelativeLayout
android:id="@+id/contacts"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@drawable/footer_button"
android:onClick="@{contactsClickListener}"
app:layout_constraintStart_toStartOf="@id/guidelineLeft"
app:layout_constraintEnd_toEndOf="@id/guidelineMiddle">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="15dp"
android:contentDescription="@string/content_description_menu_contacts"
android:src="@drawable/footer_contacts" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/dialer"
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="@drawable/footer_button"
android:onClick="@{dialerClickListener}"
app:layout_constraintStart_toStartOf="@id/guidelineMiddle"
app:layout_constraintEnd_toEndOf="@id/guidelineRight">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="15dp"
android:contentDescription="@string/content_description_menu_dialer"
android:src="@drawable/footer_dialer" />
</RelativeLayout>
<ImageView
android:id="@+id/chat"
android:onClick="@{chatClickListener}"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:contentDescription="@string/content_description_menu_chat"
android:padding="15dp"
android:src="@drawable/footer_chat"
android:background="@drawable/footer_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/guidelineRight" />
<TextView
android:id="@+id/chat_unread_count"
style="@style/unread_count_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="25dp"
android:layout_marginTop="5dp"
android:gravity="center"
android:translationY="@{viewModel.chatUnreadCountTranslateY}"
android:background="@{viewModel.unreadMessagesCount == 0 ? @drawable/hidden_unread_message_count_bg : @drawable/unread_message_count_bg}"
android:text="@{viewModel.unreadMessagesCount == 0 ? `` : String.valueOf(viewModel.unreadMessagesCount)}"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<View
android:id="@+id/selector"
android:layout_width="0dp"
android:layout_height="@dimen/tabs_fragment_selector_size"
android:background="?attr/accentColor" />
</androidx.constraintlayout.motion.widget.MotionLayout>
</LinearLayout>
</layout>

View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View" />
<variable
name="controlsViewModel"
type="org.linphone.activities.voip.viewmodels.ControlsViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/status_fragment"
android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}"
android:name="org.linphone.activities.voip.fragments.StatusFragment"
android:layout_width="match_parent"
android:layout_height="90dp"
app:layout_constraintTop_toTopOf="parent"
tools:layout="@layout/voip_status_fragment" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="48dp"
app:layout_constraintTop_toBottomOf="@id/status_fragment"
app:navGraph="@navigation/call_nav_graph"
tools:layout="@layout/voip_single_call_fragment" />
<View
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="match_parent"
android:background="?attr/voipBackgroundColor"
android:layout_height="48dp">
</View>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View"/>
<variable
name="refreshClickListener"
type="android.view.View.OnClickListener"/>
<variable
name="viewModel"
type="org.linphone.activities.voip.viewmodels.StatusViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:background="?attr/accentColor"
android:gravity="bottom"
android:layout_height="90dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/status_fragment_size"
android:orientation="horizontal">
<ImageView
android:id="@+id/stats_button"
android:onClick="@{() -> viewModel.showCallStats()}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerInParent="true"
android:contentDescription="@{viewModel.callQualityContentDescription}"
android:padding="10dp"
android:src="@{viewModel.callQualityIcon, default=@drawable/call_quality_indicator_0}" />
<ImageView
android:id="@+id/status_led"
android:background="@drawable/status_led_background"
android:src="@{viewModel.registrationStatusDrawable, default=@drawable/led_not_registered}"
android:onClick="@{refreshClickListener}"
android:contentDescription="@{viewModel.registrationStatusText}"
android:layout_width="20dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_toEndOf="@id/stats_button"
android:adjustViewBounds="true"
android:padding="2dp" />
<TextView
android:text="@{viewModel.registrationStatusText, default=@string/status_not_connected}"
android:onClick="@{refreshClickListener}"
android:textColor="?attr/accentTextColor"
android:textSize="15sp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/status_led"
android:gravity="center_vertical"
android:paddingStart="5dp"
android:paddingEnd="5dp" />
<ImageView
android:onClick="@{() -> viewModel.showZrtpDialog()}"
android:visibility="@{viewModel.encryptionIconVisible ? View.VISIBLE : View.GONE, default=gone}"
android:src="@{viewModel.encryptionIcon, default=@drawable/security_ko}"
android:contentDescription="@{viewModel.encryptionContentDescription}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:adjustViewBounds="true"
android:padding="10dp" />
</RelativeLayout>
</LinearLayout>
</layout>

View file

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="edit_chat_message_bubble_left_margin">10dp</dimen>
<dimen name="incoming_chat_message_bubble_left_margin">0dp</dimen>
<dimen name="outgoing_chat_message_bubble_left_margin">45dp</dimen>
<dimen name="incoming_chat_message_bubble_right_margin">10dp</dimen>
<dimen name="outgoing_chat_message_bubble_right_margin">3dp</dimen>
<dimen name="chat_message_bubble_image_height_big">200dp</dimen>
<dimen name="chat_message_bubble_image_height_small">100dp</dimen>
<dimen name="chat_message_bubble_file_size">120dp</dimen>
<dimen name="chat_message_small_bubble_file_size">50dp</dimen>
<dimen name="chat_message_bubble_desired_height">600dp</dimen>
<dimen name="video_preview_max_size">200dp</dimen>
<dimen name="video_preview_pip_max_size">45dp</dimen>
<dimen name="main_activity_tabs_fragment_size">60dp</dimen>
<dimen name="main_activity_top_bar_size">60dp</dimen>
<dimen name="status_fragment_size">60dp</dimen>
<dimen name="tabs_fragment_selector_size">5dp</dimen>
<dimen name="tabs_fragment_unread_count_bounce_offset">5dp</dimen>
<dimen name="contact_avatar_size">35dp</dimen>
<dimen name="contact_avatar_text_size">21sp</dimen>
<dimen name="contact_avatar_big_size">100dp</dimen>
<dimen name="contact_avatar_text_big_size">60sp</dimen>
<dimen name="field_button_size">20dp</dimen>
<dimen name="field_shape_margin">3dp</dimen>
<dimen name="call_overlay_size">60dp</dimen>
<dimen name="chat_message_popup_width">250dp</dimen>
<dimen name="chat_room_popup_width">250dp</dimen>
<dimen name="chat_message_popup_item_height">50dp</dimen>
<dimen name="chat_room_popup_item_height">50dp</dimen>
<dimen name="chat_message_round_corner_radius">6.7dp</dimen>
<dimen name="play_pause_button_size">30dp</dimen>
<dimen name="progress_bar_height">40dp</dimen>
<dimen name="settings_margin">10dp</dimen>
<dimen name="setting_title_min_size">10sp</dimen>
<dimen name="setting_title_max_size">18sp</dimen>
<dimen name="setting_subtitle_min_size">8sp</dimen>
<dimen name="setting_subtitle_max_size">14sp</dimen>
<dimen name="settings_granularity_step">1sp</dimen>
<dimen name="voip_buttons_fragment_size">50dp</dimen>
<dimen name="voip_buttons_fragment_margin_size">55dp</dimen>
<dimen name="voip_remote_margin">10dp</dimen>
<dimen name="voip_top_bar_size">60dp</dimen>
<dimen name="voip_call_list_size">80dp</dimen>
<dimen name="voip_call_context_menu_item_height">50dp</dimen>
<dimen name="voip_call_context_menu_width">250dp</dimen>
<dimen name="voip_floating_button_size">60dp</dimen>
<dimen name="voip_call_extra_buttons_height">200dp</dimen>
<dimen name="voip_call_extra_buttons_translate_y">210dp</dimen>
<dimen name="conference_scheduling_participant_cell_height">60dp</dimen>
<dimen name="voip_call_button_size">50dp</dimen>
<dimen name="voip_audio_routes_menu_translate_y">260dp</dimen>
<dimen name="voip_buttons_max_width">350dp</dimen>
<dimen name="voip_views_max_width">400dp</dimen>
<dimen name="voip_extra_menu_max_width">390dp</dimen>
<dimen name="voip_round_corners_texture_view_radius">20dp</dimen>
<dimen name="voip_counter_bounce_offset">5dp</dimen>
<dimen name="voip_active_speaker_miniature_size">100dp</dimen>
<dimen name="voip_active_speaker_miniature_margin">10dp</dimen>
<dimen name="voip_conference_active_speaker_miniature_avatar_size">50dp</dimen>
<dimen name="voip_conference_participant_mic_muted_icon_size_grid">30dp</dimen>
<dimen name="voip_conference_participant_joining_icon_size_grid">30dp</dimen>
<dimen name="voip_conference_participant_mic_muted_icon_size_active_speaker">30dp</dimen>
<dimen name="voip_conference_participant_joining_icon_size_active_speaker">35dp</dimen>
<dimen name="voip_dialog_button_max_width">137dp</dimen>
<dimen name="voip_contact_avatar_max_size">180dp</dimen>
<dimen name="voip_contact_avatar_text_size">80sp</dimen>
<dimen name="voip_numpad_button_max_size">60dp</dimen>
<dimen name="voip_conference_audio_only_participant_cell_height">80dp</dimen>
<dimen name="voip_conference_audio_only_participant_avatar_size">40dp</dimen>
<dimen name="conference_schedule_form_field_border_thickness">1dp</dimen>
<dimen name="master_fragment_width">280dp</dimen>
<dimen name="voip_active_speaker_top_margin">5dp</dimen>
<dimen name="margin_0dp">0dp</dimen>
<dimen name="voip_single_call_header_size">50dp</dimen>
<dimen name="voip_single_call_header_size_with_record_info">85dp</dimen>
<dimen name="voip_conference_header_folded_top_margin">30dp</dimen>
<dimen name="chat_message_content_preview_max_width">120dp</dimen>
<dimen name="voip_conference_active_speaker_dots_margin">5dp</dimen>
<dimen name="conference_waiting_room_buttons_max_width">250dp</dimen>
<dimen name="mute_mic_miniature_margin">5dp</dimen>
<dimen name="mute_mic_grid_margin">10dp</dimen>
<dimen name="chat_message_sending_icons_size">35dp</dimen>
<dimen name="chat_message_sending_icons_margin">5dp</dimen>
<dimen name="contact_presence_badge_size">12dp</dimen>
<dimen name="contact_presence_big_badge_size">25dp</dimen>
<dimen name="contact_presence_badge_padding">1dp</dimen>
<dimen name="contact_presence_big_badge_padding">2dp</dimen>
<dimen name="chat_room_emoji_picker_height">290dp</dimen>
<dimen name="chat_message_text_font_size">15sp</dimen>
<dimen name="chat_message_emoji_font_size">45sp</dimen>
</resources>

View file

@ -14,7 +14,7 @@
<dimen name="video_preview_pip_max_size">45dp</dimen>
<dimen name="main_activity_tabs_fragment_size">60dp</dimen>
<dimen name="main_activity_top_bar_size">60dp</dimen>
<dimen name="status_fragment_size">40dp</dimen>
<dimen name="status_fragment_size">60dp</dimen>
<dimen name="tabs_fragment_selector_size">5dp</dimen>
<dimen name="tabs_fragment_unread_count_bounce_offset">5dp</dimen>
<dimen name="contact_avatar_size">35dp</dimen>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="AppSplashScreenTheme" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/dark_grey_color</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/vector_linphone_logo</item>