Merge branch 'dev_phonenumber'

This commit is contained in:
Simon Morlat 2016-09-23 13:04:18 +02:00
commit fdb63fb119
59 changed files with 3583 additions and 838 deletions

View file

@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.linphone"
android:versionCode="3100" android:installLocation="auto">
android:versionCode="3120" android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23"/>
<!-- Permissions for Push Notification -->

View file

@ -1,4 +1,4 @@
source.dir=src:submodules/linphone/mediastreamer2/java/src:submodules/linphone/java/j2se:submodules/linphone/java/common:submodules/linphone/java/impl:submodules/linphone/coreapi/help/java
key.store=bc-android.keystore
key.alias=nw8000
version.name=2.5.0
version.name=3.1.2

72
doc/CustomsParameters.txt Normal file
View file

@ -0,0 +1,72 @@
**********************************
* LINPHONE customs parameters *
**********************************
In res/values/non_localizable_custom.xml (filled with linphone default options):
1. Global
* Set the default domain used by the application:
<string name="default_domain">sip.linphone.org</string
2. Assistant
* Server xmlrpc url for accounts
<string name="wizard_url">https://sip3.linphone.org:444/inapp.php</string>
* In CreateAccount, allow username instead of phone number for creating a new account
<bool name="assistant_allow_username">true</bool>
* Hide buttons in assistant menu
<bool name="hide_linphone_accounts_in_assistant">false</bool>
<bool name="hide_generic_accounts_in_assistant">false</bool>
<bool name="hide_remote_provisioning_in_assistant">false</bool>
3. Inapp
* Enabled inapp purchase
<bool name="enable_in_app_purchase">true</bool>
* Days before end of trial period that launch daily notification to remind user to buy an account
<integer name="days_notification_shown">5</integer>
* Time between two inapp notifications in seconds
<integer name="time_between_inapp_notification">86400</integer>
* Hide username field in purchase view (automatically get from default account)
<bool name="hide_username_in_inapp">true</bool>
In res/raw/linphonerc_factory sections:
[in-app-purchase]
* Server xmlrpc url for inapp
server_url=https://sip3.linphone.org:444/inapp.php
* Item ids from the google play store
purchasable_items_ids=test_account_subscription
[app]
* Numbers of digits to enter for validation/recover account
activation_code_length=4
[assistant]
* Set the default domain used for account creation :
domain=sip.linphone.org
* Set the default password length (min-max) :
password_max_length=-1
password_min_length=1
* Set the default username length (min-max) :
username_length=-1
username_max_length=64
username_min_length=1
username_regex=^[a-z0-9_.\-]*$
* Server xmlrpc url for accounts
xmlrpc_url=https://sip3.linphone.org:444/inapp.php

BIN
res/drawable-xhdpi/info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -25,11 +25,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:orientation="horizontal">
android:orientation="vertical">
<TableRow
android:layout_weight="1"
@ -38,44 +39,153 @@
android:layout_marginRight="10dp">
<LinearLayout
android:id="@+id/phone_number_layout"
android:visibility="visible"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">
<TextView
android:id="@+id/username_label"
android:text="@string/username"
style="@style/font13"
android:textAllCaps="true"
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content">
<EditText
android:id="@+id/username"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="text|textNoSuggestions"
android:contentDescription="@string/content_description_username_field"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
<TextView
android:id="@+id/phone_number_label"
android:text="@string/phone_number"
style="@style/font13"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/username_error"
android:text="@string/error"
style="@style/font20"
<ImageView
android:id="@+id/info_phone_number"
android:src="@drawable/info"
android:layout_alignParentRight="true"
android:layout_width="20dp"
android:layout_height="20dp"/>
</RelativeLayout>
<LinearLayout
android:visibility="visible"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
android:layout_marginTop="5dp"
android:layout_weight="1"
android:layout_height="wrap_content">
<Button
android:id="@+id/select_country"
style="@style/font8"
android:text="@string/select_your_country"
android:background="@drawable/resizable_assistant_button"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="40dp"/>
<LinearLayout
android:orientation="vertical"
android:layout_marginLeft="30dp"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/dial_code"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="phone"
android:text="+"
android:layout_marginRight="10dp"
android:gravity="center"
android:layout_width="65dp"
android:layout_height="40dp"
android:singleLine="true"/>
<EditText
android:id="@+id/phone_number"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:contentDescription="@string/content_description_phone_number_field"
android:inputType="phone"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
</LinearLayout>
<TextView
android:id="@+id/phone_number_error"
android:text="@string/error"
style="@style/font20"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<TextView
android:id="@+id/sip_uri"
style="@style/font9"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="left"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<CheckBox
android:id="@+id/use_username"
android:visibility="visible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/use_username_instead_or_phone_number"
android:checked="false" android:layout_column="1"/>
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="left"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<CheckBox
android:id="@+id/use_email"
android:visibility="visible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/use_email_for_validation" android:layout_column="1"
android:checked="false"/>
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<LinearLayout
android:id="@+id/password_layout"
android:orientation="vertical"
android:visibility="visible"
android:paddingLeft="30dp"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">
android:layout_height="wrap_content" android:layout_column="0">
<TextView
android:id="@+id/password_label"
@ -106,7 +216,41 @@
android:visibility="invisible"/>
</LinearLayout>
</TableRow>
<LinearLayout
android:id="@+id/username_layout"
android:orientation="vertical"
android:visibility="gone"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" android:layout_column="1">
<TextView
android:id="@+id/username_label"
android:text="@string/username"
style="@style/font13"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/username"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="text|textNoSuggestions"
android:contentDescription="@string/content_description_username_field"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
<TextView
android:id="@+id/username_error"
android:text="@string/error"
style="@style/font20"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
</LinearLayout>
</TableRow>
<TableRow
android:layout_weight="1"
@ -115,48 +259,13 @@
android:layout_marginRight="10dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">
<TextView
android:id="@+id/confirm_password_label"
android:text="@string/confirm_password"
style="@style/font13"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/confirm_password"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="textPassword"
android:contentDescription="@string/content_description_confirm_password_field"
android:textCursorDrawable="@null"
android:layout_width="match_parent"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:singleLine="true"/>
<TextView
android:id="@+id/confirm_password_error"
android:text="@string/error"
style="@style/font20"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
</LinearLayout>
<LinearLayout
android:id="@+id/email_layout"
android:visibility="gone"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_weight="1"
android:paddingLeft="30dp"
android:layout_height="wrap_content">
android:layout_height="wrap_content" android:layout_column="0">
<TextView
android:id="@+id/email_label"
@ -188,6 +297,44 @@
android:visibility="invisible"/>
</LinearLayout>
<LinearLayout
android:id="@+id/password_confirm_layout"
android:visibility="gone"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" android:layout_column="1">
<TextView
android:id="@+id/confirm_password_label"
android:text="@string/confirm_password"
style="@style/font13"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/confirm_password"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="textPassword"
android:contentDescription="@string/content_description_confirm_password_field"
android:textCursorDrawable="@null"
android:layout_width="match_parent"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:singleLine="true"/>
<TextView
android:id="@+id/confirm_password_error"
android:text="@string/error"
style="@style/font20"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
</LinearLayout>
</TableRow>
</TableLayout>

View file

@ -21,18 +21,123 @@
android:paddingTop="10dp"
android:layout_gravity="center"/>
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:orientation="horizontal">
<TableRow
android:layout_weight="1"
android:gravity="left"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<LinearLayout
android:id="@+id/phone_number_layout"
android:visibility="visible"
android:orientation="horizontal"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">
<Button
android:id="@+id/select_country"
style="@style/font8"
android:text="@string/select_your_country"
android:layout_marginTop="15dp"
android:background="@drawable/resizable_assistant_button"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="40dp"/>
<LinearLayout
android:orientation="vertical"
android:layout_marginLeft="30dp"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/phone_number_label"
android:text="@string/phone_number"
style="@style/font13"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/info_phone_number"
android:src="@drawable/info"
android:layout_alignParentRight="true"
android:layout_width="15dp"
android:layout_height="15dp"/>
</RelativeLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/dial_code"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="phone"
android:text="+"
android:layout_marginRight="10dp"
android:gravity="center"
android:layout_width="65dp"
android:layout_height="40dp"
android:singleLine="true"/>
<EditText
android:id="@+id/phone_number"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:contentDescription="@string/content_description_phone_number_field"
android:inputType="phone"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="left"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp">
<CheckBox
android:id="@+id/use_username"
android:visibility="visible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/login_with_username"/>
</TableRow>
<TableRow
android:layout_weight="1"
android:gravity="center"
android:layout_margin="10dp">
<LinearLayout
android:id="@+id/username_layout"
android:layout_gravity="top"
android:visibility="gone"
android:orientation="vertical"
android:layout_width="0dp"
android:layout_weight="1"
@ -57,7 +162,10 @@
</LinearLayout>
<LinearLayout
android:id="@+id/password_layout"
android:visibility="gone"
android:orientation="vertical"
android:layout_gravity="top"
android:paddingLeft="30dp"
android:layout_width="0dp"
android:layout_weight="1"
@ -94,7 +202,9 @@
android:layout_margin="10dp">
<LinearLayout
android:id="@+id/display_layout"
android:orientation="vertical"
android:visibility="gone"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">

View file

@ -10,6 +10,7 @@
android:orientation="vertical">
<TextView
android:id="@+id/assistant_title"
android:text="@string/assistant_create_account"
style="@style/font6"
android:textAllCaps="true"
@ -21,7 +22,7 @@
android:text="@string/assistant_create_account_part_1"
style="@style/font11"
android:paddingTop="10dp"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
@ -33,6 +34,111 @@
android:orientation="vertical">
<LinearLayout
android:id="@+id/phone_number_layout"
android:visibility="gone"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_marginBottom="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/phone_number_label"
android:text="@string/phone_number"
style="@style/font13"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/info_phone_number"
android:src="@drawable/info"
android:layout_alignParentRight="true"
android:layout_width="20dp"
android:layout_height="20dp"/>
</RelativeLayout>
<Button
android:id="@+id/select_country"
style="@style/font8"
android:text="@string/select_your_country"
android:background="@drawable/resizable_assistant_button"
android:layout_width="match_parent"
android:layout_height="40dp"/>
<LinearLayout
android:orientation="vertical"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/dial_code"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="phone"
android:text="+"
android:layout_marginRight="10dp"
android:gravity="center"
android:layout_width="65dp"
android:layout_height="42dp"
android:singleLine="true"/>
<EditText
android:id="@+id/phone_number"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:contentDescription="@string/content_description_phone_number_field"
android:inputType="phone"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
</LinearLayout>
<TextView
android:id="@+id/phone_number_error"
android:text="@string/error"
style="@style/font20"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<TextView
android:id="@+id/sip_uri"
style="@style/font9"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
<CheckBox
android:id="@+id/use_username"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/use_username_instead_or_phone_number"/>
<CheckBox
android:id="@+id/use_email"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/use_email_for_validation"/>
<LinearLayout
android:id="@+id/username_layout"
android:visibility="gone"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@ -66,109 +172,129 @@
</LinearLayout>
<LinearLayout
android:id="@+id/password_layout"
android:visibility="gone"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/password_label"
style="@style/font13"
android:text="@string/password"
android:textAllCaps="true"
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content">
<EditText
android:id="@+id/password"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="textPassword"
android:textCursorDrawable="@null"
android:layout_width="match_parent"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:singleLine="true"/>
<TextView
android:id="@+id/password_label"
style="@style/font13"
android:text="@string/password"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/password_error"
android:text="@string/error"
style="@style/font20"
<EditText
android:id="@+id/password"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="textPassword"
android:textCursorDrawable="@null"
android:layout_width="match_parent"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:singleLine="true"/>
<TextView
android:id="@+id/password_error"
android:text="@string/error"
style="@style/font20"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
</LinearLayout>
<LinearLayout
android:id="@+id/password_confirm_layout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
android:layout_height="wrap_content">
<TextView
android:id="@+id/confirm_password_label"
android:text="@string/confirm_password"
style="@style/font13"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/confirm_password"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="textPassword"
android:contentDescription="@string/content_description_confirm_password_field"
android:textCursorDrawable="@null"
android:layout_width="match_parent"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:singleLine="true"/>
<TextView
android:id="@+id/confirm_password_error"
android:text="@string/error"
style="@style/font20"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/email_layout"
android:visibility="gone"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/confirm_password_label"
android:text="@string/confirm_password"
style="@style/font13"
android:textAllCaps="true"
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content">
<EditText
android:id="@+id/confirm_password"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="textPassword"
android:contentDescription="@string/content_description_confirm_password_field"
android:textCursorDrawable="@null"
android:layout_width="match_parent"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:singleLine="true"/>
<TextView
android:id="@+id/email_label"
android:text="@string/email"
style="@style/font13"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/confirm_password_error"
android:text="@string/error"
style="@style/font20"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<EditText
android:id="@+id/email"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="textEmailAddress"
android:contentDescription="@string/content_description_email_field"
android:textCursorDrawable="@null"
android:layout_width="match_parent"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:singleLine="true"/>
</LinearLayout>
<TextView
android:id="@+id/email_error"
android:text="@string/error"
style="@style/font20"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/email_label"
android:text="@string/email"
style="@style/font13"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/email"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="textEmailAddress"
android:contentDescription="@string/content_description_email_field"
android:textCursorDrawable="@null"
android:layout_width="match_parent"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:singleLine="true"/>
<TextView
android:id="@+id/email_error"
android:text="@string/error"
style="@style/font20"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
</LinearLayout>
</LinearLayout>
@ -184,6 +310,18 @@
android:paddingRight="10dp"
android:layout_marginTop="20dp"/>
<TextView
android:id="@+id/assistant_skip"
android:visibility="gone"
android:text="@string/maybe_later"
android:textColor="@drawable/assistant_button_text_color"
style="@style/font10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_marginTop="20dp"/>
</LinearLayout>
</LinearLayout>
</ScrollView>

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="30dp"
android:gravity="center_horizontal"
android:orientation="vertical" >
<TextView
android:text="@string/assistant_create_account"
style="@style/font6"
android:textAllCaps="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="@string/assistant_create_account_part_2"
style="@style/font11"
android:paddingTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/assistant_code"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:contentDescription="@string/content_description_activation_code_field"
android:inputType="number"
android:gravity="center_vertical|center_horizontal"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
<Button
android:id="@+id/assistant_check"
android:text="@string/assistant_activate"
android:background="@drawable/assistant_button"
android:textColor="@drawable/assistant_button_text_color"
style="@style/font8"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_marginTop="20dp"/>
</LinearLayout>
</ScrollView>

View file

@ -17,13 +17,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="@string/assistant_create_account_part_2"
style="@style/font11"
android:paddingTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="@string/assistant_validate_account"
style="@style/font11"

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/assistant_choose_country"
style="@style/font6"
android:singleLine="true"
android:gravity="center_vertical|center" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<EditText
android:id="@+id/search_country"
android:textCursorDrawable="@null"
android:layout_width="match_parent"
android:layout_height="40dp"
android:textColor="@android:color/black"
android:background="@drawable/resizable_textfield"
android:gravity="center"
android:inputType="textPersonName"/>
<ImageView
android:id="@+id/clearSearchField"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/clean_field_default"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:paddingLeft="5dp"
android:paddingRight="5dp"/>
</RelativeLayout>
<ListView
android:id="@+id/countryList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/colorE"
android:cacheColorHint="@color/transparent"
android:dividerHeight="1dp" />
</LinearLayout>

View file

@ -19,7 +19,7 @@
android:layout_gravity="center"/>
<TextView
android:text="@string/assistant_linphone_login_desc"
android:text="@string/assistant_create_account_part_1"
style="@style/font11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -34,64 +34,131 @@
android:layout_marginTop="30dp"
android:orientation="vertical">
<TextView
android:text="@string/username"
style="@style/font13"
android:textAllCaps="true"
<LinearLayout
android:id="@+id/phone_number_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<EditText
android:id="@+id/assistant_username"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="text|textNoSuggestions"
android:contentDescription="@string/content_description_username_field"
<Button
android:id="@+id/select_country"
style="@style/font8"
android:text="@string/select_your_country"
android:background="@drawable/resizable_assistant_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:orientation="vertical"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/phone_number_label"
android:text="@string/phone_number"
style="@style/font13"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/dial_code"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="phone"
android:text="+"
android:layout_marginRight="10dp"
android:gravity="center"
android:layout_width="65dp"
android:layout_height="42dp"
android:singleLine="true"/>
<EditText
android:id="@+id/phone_number"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:contentDescription="@string/content_description_phone_number_field"
android:inputType="phone"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<CheckBox
android:id="@+id/use_username"
android:visibility="visible"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
<TextView
android:text="@string/password"
style="@style/font13"
android:textAllCaps="true"
android:paddingTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/assistant_password"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="textPassword"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
<TextView
android:id="@+id/forgot_password"
android:layout_gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"/>
android:text="@string/login_with_username"/>
<TextView
android:text="@string/assistant_display_name_optional"
style="@style/font13"
android:textAllCaps="true"
android:paddingTop="15dp"
<LinearLayout
android:id="@+id/username_layout"
android:visibility="gone"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content">
<EditText
android:id="@+id/assistant_display_name"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="textPersonName"
android:contentDescription="@string/content_description_username_field"
<TextView
android:text="@string/username"
style="@style/font13"
android:textAllCaps="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/assistant_username"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="text|textNoSuggestions"
android:contentDescription="@string/content_description_username_field"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
</LinearLayout>
<LinearLayout
android:id="@+id/password_layout"
android:visibility="gone"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
android:layout_height="wrap_content">
<TextView
android:text="@string/password"
style="@style/font13"
android:textAllCaps="true"
android:paddingTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/assistant_password"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"
android:inputType="textPassword"
android:layout_width="match_parent"
android:layout_height="40dp"
android:singleLine="true"/>
<TextView
android:id="@+id/forgot_password"
android:layout_gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"/>
</LinearLayout>
<Button
android:id="@+id/assistant_apply"

View file

@ -87,6 +87,7 @@
android:singleLine="true"/>
<TextView
android:visibility="gone"
android:text="@string/assistant_display_name_optional"
style="@style/font13"
android:textAllCaps="true"
@ -95,6 +96,7 @@
android:layout_height="wrap_content"/>
<EditText
android:visibility="gone"
android:id="@+id/assistant_display_name"
android:background="@drawable/resizable_textfield"
android:textColor="@color/colorB"

View file

@ -17,14 +17,33 @@
android:layout_marginRight="10dp"
android:background="@color/colorE"/>
<TextView
android:id="@+id/address_label"
android:layout_marginTop="10dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="true"
android:textColor="@color/colorE" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/address_label"
android:layout_marginTop="10dp"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="true"
android:textColor="@color/colorE" />
<ImageView
android:id="@+id/friendLinphone"
android:visibility="gone"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:layout_marginRight="10dp"
android:scaleType="centerInside"
android:src="@drawable/linphone_user" />
</RelativeLayout>
<TextView
android:id="@+id/numeroOrAddress"

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_gravity="center"
android:layout_height="40dp"
android:padding="5dp">
<TextView
android:id="@+id/country_name"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/font6"/>
<TextView
android:id="@+id/country_prefix"
style="@style/font6"
android:paddingLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</LinearLayout>

View file

@ -9,7 +9,6 @@
android:background="@color/colorF"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginBottom="10dp"
android:layout_alignParentTop="true">
<org.linphone.ui.EraseButton

70
res/layout/in_app.xml Normal file
View file

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:background="@color/colorH"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<fragment
android:id="@+id/status"
android:name="org.linphone.StatusFragment"
android:layout_width="match_parent"
android:layout_height="40dp"
tools:layout="@layout/status"/>
<LinearLayout
android:id="@+id/topbar"
android:layout_below="@+id/status"
android:background="@color/colorF"
android:orientation="horizontal"
android:layout_gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="60dp">
<ImageView
android:id="@+id/back"
android:src="@drawable/back"
android:background="@drawable/toolbar_button"
android:contentDescription="@string/content_description_back"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.2"
android:padding="18dp"/>
<TextView
android:text="@string/inapp"
style="@style/font1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.6"
android:gravity="center"/>
<ImageView
android:id="@+id/cancel"
android:src="@drawable/dialer_back"
android:background="@drawable/toolbar_button"
android:contentDescription="@string/content_description_dialer_back"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.2"
android:padding="15dp"/>
</LinearLayout>
<ProgressBar
android:id="@+id/purchaseItemsFetchInProgress"
style="?android:attr/progressBarStyle"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_below="@+id/topbar"/>
</RelativeLayout>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/inapp_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/colorE"
android:cacheColorHint="@color/transparent"
android:dividerHeight="1dp" />
</LinearLayout>

View file

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical" >
<Button
android:id="@+id/inapp_button"
android:text="@string/assistant_create_account"
android:background="@drawable/assistant_button"
style="@style/font8"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_width="match_parent"
android:layout_height="40dp"/>
</LinearLayout>

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/inapp_purchase"
android:background="@color/colorH"
android:layout_width="match_parent"
android:layout_height="60dp">
<ImageView
android:id="@+id/inapp_icon"
android:src="@drawable/linphone_logo"
android:layout_alignParentLeft="true"
android:layout_centerInParent="true"
android:layout_margin="5dp"
android:layout_width="40dp"
android:layout_height="40dp"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/inapp_icon">
<TextView
android:id="@+id/purchase_title"
style="@style/font7"
android:textSize="15sp"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<TextView
android:id="@+id/purchase_description"
style="@style/font11"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
<TextView
android:id="@+id/purchase_price"
android:layout_margin="5dp"
android:layout_alignParentRight="true"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>

View file

@ -5,32 +5,15 @@
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/topbar"
android:background="@color/colorF"
android:orientation="horizontal"
android:layout_gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:text="@string/assistant"
style="@style/font1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:padding="30dp"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:id="@+id/username_layout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
@ -90,21 +73,17 @@
android:singleLine="true"/>
</LinearLayout>
<LinearLayout
android:id="@+id/purchasable_items"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="40dp"
android:gravity="center"
android:orientation="vertical"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
</LinearLayout>
<Button
android:id="@+id/inapp_button"
android:text="@string/assistant_create_account"
android:background="@drawable/assistant_button"
style="@style/font8"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="40dp"/>
</LinearLayout>

246
res/raw/countries.json Executable file
View file

@ -0,0 +1,246 @@
[
{"name":"Afghanistan","dial_code":"+93","code":"AF","maxNum":"9"},
{"name":"Albania","dial_code":"+355","code":"AL","maxNum":"9"},
{"name":"Algeria","dial_code":"+213","code":"DZ","maxNum":"9"},
{"name":"AmericanSamoa","dial_code":"+1 684","code":"AS","maxNum":"10"},
{"name":"Andorra","dial_code":"+376","code":"AD","maxNum":"6"},
{"name":"Angola","dial_code":"+244","code":"AO","maxNum":"9"},
{"name":"Anguilla","dial_code":"+1 264","code":"AI","maxNum":"10"},
{"name":"Antigua and Barbuda","dial_code":"+1268","code":"AG","maxNum":"10"},
{"name":"Argentina","dial_code":"+54","code":"AR","maxNum":"10"},
{"name":"Armenia","dial_code":"+374","code":"AM","maxNum":"8"},
{"name":"Aruba","dial_code":"+297","code":"AW","maxNum":"7"},
{"name":"Australia","dial_code":"+61","code":"AU","maxNum":"9"},
{"name":"Austria","dial_code":"+43","code":"AT","maxNum":"10"},
{"name":"Azerbaijan","dial_code":"+994","code":"AZ","maxNum":"9"},
{"name":"Bahamas","dial_code":"+1 242","code":"BS","maxNum":"10"},
{"name":"Bahrain","dial_code":"+973","code":"BH","maxNum":"8"},
{"name":"Bangladesh","dial_code":"+880","code":"BD","maxNum":"10"},
{"name":"Barbados","dial_code":"+1 246","code":"BB","maxNum":"10"},
{"name":"Belarus","dial_code":"+375","code":"BY","maxNum":"9"},
{"name":"Belgium","dial_code":"+32","code":"BE","maxNum":"9"},
{"name":"Belize","dial_code":"+501","code":"BZ","maxNum":"7"},
{"name":"Benin","dial_code":"+229","code":"BJ","maxNum":"8"},
{"name":"Bermuda","dial_code":"+1 441","code":"BM","maxNum":"10"},
{"name":"Bhutan","dial_code":"+975","code":"BT","maxNum":"8"},
{"name":"Bolivia","dial_code":"+591","code":"BO","maxNum":"8"},
{"name":"Bosnia and Herzegovina","dial_code":"+387","code":"BA","maxNum":"8"},
{"name":"Botswana","dial_code":"+267","code":"BW","maxNum":"8"},
{"name":"Brazil","dial_code":"+55","code":"BR","maxNum":"10"},
{"name":"Brunei Darussalam","dial_code":"+673","code":"BN","maxNum":"7"},
{"name":"British Indian Ocean Territory","dial_code":"+246","code":"IO","maxNum":"0"},
{"name":"Bulgaria","dial_code":"+359","code":"BG","maxNum":"9"},
{"name":"Burkina Faso","dial_code":"+226","code":"BF","maxNum":"8"},
{"name":"Burundi","dial_code":"+257","code":"BI","maxNum":"8"},
{"name":"Cambodia","dial_code":"+855","code":"KH","maxNum":"9"},
{"name":"Cameroon","dial_code":"+237","code":"CM","maxNum":"8"},
{"name":"Canada","dial_code":"+1","code":"CA","maxNum":"10"},
{"name":"Cape Verde","dial_code":"+238","code":"CV","maxNum":"7"},
{"name":"Cayman Islands","dial_code":"+ 345","code":"KY","maxNum":"10"},
{"name":"Central African Republic","dial_code":"+236","code":"CF","maxNum":"8"},
{"name":"Chad","dial_code":"+235","code":"TD","maxNum":"8"},
{"name":"Chile","dial_code":"+56","code":"CL","maxNum":"9"},
{"name":"China","dial_code":"+86","code":"CN","maxNum":"11"},
{"name":"Christmas Island","dial_code":"+61","code":"CX","maxNum":"0"},
{"name":"Colombia","dial_code":"+57","code":"CO","maxNum":"10"},
{"name":"Comoros","dial_code":"+269","code":"KM","maxNum":"7"},
{"name":"Congo","dial_code":"+242","code":"CG","maxNum":"9"},
{"name":"Congo,Democratic Republic","dial_code":"+243","code":"CD","maxNum":"9"},
{"name":"Cook Islands","dial_code":"+682","code":"CK","maxNum":"5"},
{"name":"Costa Rica","dial_code":"+506","code":"CR","maxNum":"8"},
{"name":"Cote d'Ivoire","dial_code":"+225","code":"CI","maxNum":"8"},
{"name":"Croatia","dial_code":"+385","code":"HR","maxNum":"9"},
{"name":"Cuba","dial_code":"+53","code":"CU","maxNum":"8"},
{"name":"Cyprus","dial_code":"+537","code":"CY","maxNum":"8"},
{"name":"Czech Republic","dial_code":"+420","code":"CZ","maxNum":"9"},
{"name":"Denmark","dial_code":"+45","code":"DK","maxNum":"8"},
{"name":"Djibouti","dial_code":"+253","code":"DJ","maxNum":"8"},
{"name":"Dominica","dial_code":"+1 767","code":"DM","maxNum":"10"},
{"name":"Dominican Republic","dial_code":"+1 849","code":"DO","maxNum":"10"},
{"name":"Ecuador","dial_code":"+593","code":"EC","maxNum":"9"},
{"name":"Egypt","dial_code":"+20","code":"EG","maxNum":"10"},
{"name":"El Salvador","dial_code":"+503","code":"SV","maxNum":"8"},
{"name":"Equatorial Guinea","dial_code":"+240","code":"GQ","maxNum":"9"},
{"name":"Eritrea","dial_code":"+291","code":"ER","maxNum":"7"},
{"name":"Estonia","dial_code":"+372","code":"EE","maxNum":"8"},
{"name":"Ethiopia","dial_code":"+251","code":"ET","maxNum":"9"},
{"name":"Falkland Islands","dial_code":"+500","code":"FK","maxNum":"5"},
{"name":"Faroe Islands","dial_code":"+298","code":"FO","maxNum":"6"},
{"name":"Fiji","dial_code":"+679","code":"FJ","maxNum":"7"},
{"name":"Finland","dial_code":"+358","code":"FI","maxNum":"9"},
{"name":"France","dial_code":"+33","code":"FR","maxNum":"9"},
{"name":"French Guiana","dial_code":"+594","code":"GF","maxNum":"9"},
{"name":"French Polynesia","dial_code":"+689","code":"PF","maxNum":"6"},
{"name":"Gabon","dial_code":"+241","code":"GA","maxNum":"8"},
{"name":"Gambia","dial_code":"+220","code":"GM","maxNum":"7"},
{"name":"Georgia","dial_code":"+995","code":"GE","maxNum":"9"},
{"name":"Germany","dial_code":"+49","code":"DE","maxNum":"11"},
{"name":"Ghana","dial_code":"+233","code":"GH","maxNum":"9"},
{"name":"Gibraltar","dial_code":"+350","code":"GI","maxNum":"8"},
{"name":"Greece","dial_code":"+30","code":"GR","maxNum":"10"},
{"name":"Greenland","dial_code":"+299","code":"GL","maxNum":"6"},
{"name":"Grenada","dial_code":"+1 473","code":"GD","maxNum":"10"},
{"name":"Guadeloupe","dial_code":"+590","code":"GP","maxNum":"9"},
{"name":"Guam","dial_code":"+1 671","code":"GU","maxNum":"10"},
{"name":"Guatemala","dial_code":"+502","code":"GT","maxNum":"8"},
{"name":"Guinea","dial_code":"+224","code":"GN","maxNum":"8"},
{"name":"Guinea-Bissau","dial_code":"+245","code":"GW","maxNum":"7"},
{"name":"Guyana","dial_code":"+595","code":"GY","maxNum":"7"},
{"name":"Haiti","dial_code":"+509","code":"HT","maxNum":"8"},
{"name":"Honduras","dial_code":"+504","code":"HN","maxNum":"8"},
{"name":"Hong Kong","dial_code":"+852","code":"HK","maxNum":"8"},
{"name":"Hungary","dial_code":"+36","code":"HU","maxNum":"9"},
{"name":"Iceland","dial_code":"+354","code":"IS","maxNum":"9"},
{"name":"India","dial_code":"+91","code":"IN","maxNum":"10"},
{"name":"Indonesia","dial_code":"+62","code":"ID","maxNum":"10"},
{"name":"Iran, Islamic Republic of","dial_code":"+98","code":"IR","maxNum":"10"},
{"name":"Iraq","dial_code":"+964","code":"IQ","maxNum":"10"},
{"name":"Ireland","dial_code":"+353","code":"IE","maxNum":"9"},
{"name":"Israel","dial_code":"+972","code":"IL","maxNum":"9"},
{"name":"Italy","dial_code":"+39","code":"IT","maxNum":"10"},
{"name":"Jamaica","dial_code":"+1 876","code":"JM","maxNum":"10"},
{"name":"Japan","dial_code":"+81","code":"JP","maxNum":"10"},
{"name":"Jordan","dial_code":"+962","code":"JO","maxNum":"9"},
{"name":"Kazakhstan","dial_code":"+7 7","code":"KZ","maxNum":"10"},
{"name":"Kenya","dial_code":"+254","code":"KE","maxNum":"9"},
{"name":"Kiribati","dial_code":"+686","code":"KI","maxNum":"5"},
{"name":"Korea, People's Rep.","dial_code":"+850","code":"KP","maxNum":"12"},
{"name":"Korea, Republic of","dial_code":"+82","code":"KR","maxNum":"12"},
{"name":"Kuwait","dial_code":"+965","code":"KW","maxNum":"8"},
{"name":"Kyrgyzstan","dial_code":"+996","code":"KG","maxNum":"9"},
{"name":"Lao People's Democratic Rep.","dial_code":"+856","code":"LA","maxNum":"10"},
{"name":"Latvia","dial_code":"+371","code":"LV","maxNum":"8"},
{"name":"Lebanon","dial_code":"+961","code":"LB","maxNum":"7"},
{"name":"Lesotho","dial_code":"+266","code":"LS","maxNum":"8"},
{"name":"Libyan Arab Jamahiriya","dial_code":"+218","code":"LY","maxNum":"8"},
{"name":"Liberia","dial_code":"+231","code":"LR","maxNum":"8"},
{"name":"Liechtenstein","dial_code":"+423","code":"LI","maxNum":"7"},
{"name":"Lithuania","dial_code":"+370","code":"LT","maxNum":"8"},
{"name":"Luxembourg","dial_code":"+352","code":"LU","maxNum":"9"},
{"name":"Macao","dial_code":"+853","code":"MO","maxNum":"8"},
{"name":"Macedonia","dial_code":"+389","code":"MK","maxNum":"8"},
{"name":"Micronesia","dial_code":"+691","code":"FM","maxNum":"7"},
{"name":"Madagascar","dial_code":"+261","code":"MG","maxNum":"9"},
{"name":"Malawi","dial_code":"+265","code":"MW","maxNum":"9"},
{"name":"Malaysia","dial_code":"+60","code":"MY","maxNum":"9"},
{"name":"Maldives","dial_code":"+960","code":"MV","maxNum":"7"},
{"name":"Mali","dial_code":"+223","code":"ML","maxNum":"8"},
{"name":"Malta","dial_code":"+356","code":"MT","maxNum":"8"},
{"name":"Marshall Islands","dial_code":"+692","code":"MH","maxNum":"7"},
{"name":"Martinique","dial_code":"+596","code":"MQ","maxNum":"9"},
{"name":"Mauritania","dial_code":"+222","code":"MR","maxNum":"8"},
{"name":"Mauritius","dial_code":"+230","code":"MU","maxNum":"7"},
{"name":"Mayotte","dial_code":"+262","code":"YT","maxNum":"9"},
{"name":"Mexico","dial_code":"+52","code":"MX","maxNum":"10"},
{"name":"Moldova, Republic of","dial_code":"+373","code":"MD","maxNum":"8"},
{"name":"Monaco","dial_code":"+377","code":"MC","maxNum":"8"},
{"name":"Mongolia","dial_code":"+976","code":"MN","maxNum":"8"},
{"name":"Montenegro","dial_code":"+382","code":"ME","maxNum":"8"},
{"name":"Montserrat","dial_code":"+1664","code":"MS","maxNum":"10"},
{"name":"Morocco","dial_code":"+212","code":"MA","maxNum":"9"},
{"name":"Mozambique","dial_code":"+258","code":"MZ","maxNum":"9"},
{"name":"Myanmar","dial_code":"+95","code":"MM","maxNum":"8"},
{"name":"Namibia","dial_code":"+264","code":"NA","maxNum":"9"},
{"name":"Nauru","dial_code":"+674","code":"NR","maxNum":"7"},
{"name":"Nepal","dial_code":"+977","code":"NP","maxNum":"10"},
{"name":"Netherlands","dial_code":"+31","code":"NL","maxNum":"9"},
{"name":"Netherlands Antilles","dial_code":"+599","code":"AN","maxNum":"0"},
{"name":"New Caledonia","dial_code":"+687","code":"NC","maxNum":"6"},
{"name":"New Zealand","dial_code":"+64","code":"NZ","maxNum":"10"},
{"name":"Nicaragua","dial_code":"+505","code":"NI","maxNum":"8"},
{"name":"Niger","dial_code":"+227","code":"NE","maxNum":"8"},
{"name":"Nigeria","dial_code":"+234","code":"NG","maxNum":"10"},
{"name":"Niue","dial_code":"+683","code":"NU","maxNum":"4"},
{"name":"Norfolk Island","dial_code":"+672","code":"NF","maxNum":"5"},
{"name":"Northern Mariana Islands","dial_code":"+1 670","code":"MP","maxNum":"10"},
{"name":"Norway","dial_code":"+47","code":"NO","maxNum":"8"},
{"name":"Oman","dial_code":"+968","code":"OM","maxNum":"8"},
{"name":"Pakistan","dial_code":"+92","code":"PK","maxNum":"10"},
{"name":"Palau","dial_code":"+680","code":"PW","maxNum":"7"},
{"name":"Palestine","dial_code":"+970","code":"PS","maxNum":"9"},
{"name":"Panama","dial_code":"+507","code":"PA","maxNum":"8"},
{"name":"Papua New Guinea","dial_code":"+675","code":"PG","maxNum":"8"},
{"name":"Paraguay","dial_code":"+595","code":"PY","maxNum":"9"},
{"name":"Peru","dial_code":"+51","code":"PE","maxNum":"9"},
{"name":"Philippines","dial_code":"+63","code":"PH","maxNum":"10"},
{"name":"Poland","dial_code":"+48","code":"PL","maxNum":"9"},
{"name":"Portugal","dial_code":"+351","code":"PT","maxNum":"9"},
{"name":"Puerto Rico","dial_code":"+1 939","code":"PR","maxNum":"10"},
{"name":"Qatar","dial_code":"+974","code":"QA","maxNum":"8"},
{"name":"Romania","dial_code":"+40","code":"RO","maxNum":"9"},
{"name":"Russian Federation","dial_code":"+7","code":"RU","maxNum":"10"},
{"name":"Rwanda","dial_code":"+250","code":"RW","maxNum":"9"},
{"name":"Réunion Island","dial_code":"+262","code":"RE","maxNum":"9"},
{"name":"Saint Barthélemy","dial_code":"+590","code":"BL","maxNum":"0"},
{"name":"Saint Helena","dial_code":"+290","code":"SH","maxNum":"4"},
{"name":"Saint Kitts and Nevis","dial_code":"+1 869","code":"KN","maxNum":"10"},
{"name":"Saint Lucia","dial_code":"+1 758","code":"LC","maxNum":"10"},
{"name":"Saint Martin","dial_code":"+590","code":"MF","maxNum":"0"},
{"name":"Saint Pierre and Miquelon","dial_code":"+508","code":"PM","maxNum":"6"},
{"name":"Saint Vincent","dial_code":"+1 784","code":"VC","maxNum":"10"},
{"name":"Sao Tome and Principe","dial_code":"+239","code":"ST","maxNum":"7"},
{"name":"Somalia","dial_code":"+252","code":"SO","maxNum":"8"},
{"name":"Svalbard and Jan Mayen","dial_code":"+47","code":"SJ","maxNum":"0"},
{"name":"Syrian Arab Republic","dial_code":"+963","code":"SY","maxNum":"9"},
{"name":"Samoa","dial_code":"+685","code":"WS","maxNum":"7"},
{"name":"San Marino","dial_code":"+378","code":"SM","maxNum":"10"},
{"name":"Saudi Arabia","dial_code":"+966","code":"SA","maxNum":"9"},
{"name":"Senegal","dial_code":"+221","code":"SN","maxNum":"9"},
{"name":"Serbia","dial_code":"+381","code":"RS","maxNum":"9"},
{"name":"Seychelles","dial_code":"+248","code":"SC","maxNum":"7"},
{"name":"Sierra Leone","dial_code":"+232","code":"SL","maxNum":"8"},
{"name":"Singapore","dial_code":"+65","code":"SG","maxNum":"8"},
{"name":"Slovakia","dial_code":"+421","code":"SK","maxNum":"9"},
{"name":"Slovenia","dial_code":"+386","code":"SI","maxNum":"8"},
{"name":"Solomon Islands","dial_code":"+677","code":"SB","maxNum":"7"},
{"name":"South Africa","dial_code":"+27","code":"ZA","maxNum":"9"},
{"name":"South Georgia Islands","dial_code":"+500","code":"GS","maxNum":"0"},
{"name":"Spain","dial_code":"+34","code":"ES","maxNum":"9"},
{"name":"Sri Lanka","dial_code":"+94","code":"LK","maxNum":"9"},
{"name":"Sudan","dial_code":"+249","code":"SD","maxNum":"9"},
{"name":"Suriname","dial_code":"+597","code":"SR","maxNum":"7"},
{"name":"Swaziland","dial_code":"+268","code":"SZ","maxNum":"8"},
{"name":"Sweden","dial_code":"+46","code":"SE","maxNum":"9"},
{"name":"Switzerland","dial_code":"+41","code":"CH","maxNum":"9"},
{"name":"Taiwan","dial_code":"+886","code":"TW","maxNum":"9"},
{"name":"Tajikistan","dial_code":"+992","code":"TJ","maxNum":"9"},
{"name":"Tanzania, United Republic of","dial_code":"+255","code":"TZ","maxNum":"9"},
{"name":"Thailand","dial_code":"+66","code":"TH","maxNum":"9"},
{"name":"Togo","dial_code":"+228","code":"TG","maxNum":"8"},
{"name":"Tokelau","dial_code":"+690","code":"TK","maxNum":"4"},
{"name":"Tonga","dial_code":"+676","code":"TO","maxNum":"5"},
{"name":"Trinidad and Tobago","dial_code":"+1 868","code":"TT","maxNum":"10"},
{"name":"Tunisia","dial_code":"+216","code":"TN","maxNum":"8"},
{"name":"Turkey","dial_code":"+90","code":"TR","maxNum":"10"},
{"name":"Turkmenistan","dial_code":"+993","code":"TM","maxNum":"8"},
{"name":"Turks and Caicos Islands","dial_code":"+1 649","code":"TC","maxNum":"7"},
{"name":"Tuvalu","dial_code":"+688","code":"TV","maxNum":"5"},
{"name":"Uganda","dial_code":"+256","code":"UG","maxNum":"9"},
{"name":"Ukraine","dial_code":"+380","code":"UA","maxNum":"9"},
{"name":"United Arab Emirates","dial_code":"+971","code":"AE","maxNum":"9"},
{"name":"United Kingdom","dial_code":"+44","code":"GB","maxNum":"10"},
{"name":"United States","dial_code":"+1","code":"US","maxNum":"10"},
{"name":"Uruguay","dial_code":"+598","code":"UY","maxNum":"8"},
{"name":"Uzbekistan","dial_code":"+998","code":"UZ","maxNum":"9"},
{"name":"Vanuatu","dial_code":"+678","code":"VU","maxNum":"7"},
{"name":"Venezuela","dial_code":"+58","code":"VE","maxNum":"10"},
{"name":"VietNam","dial_code":"+84","code":"VN","maxNum":"9"},
{"name":"Wallis and Futuna","dial_code":"+681","code":"WF","maxNum":"5"},
{"name":"Yemen","dial_code":"+967","code":"YE","maxNum":"9"},
{"name":"Zambia","dial_code":"+260","code":"ZM","maxNum":"9"},
{"name":"Zimbabwe","dial_code":"+263","code":"ZW","maxNum":"9"},
{"name":"Cocos (Keeling) Islands","dial_code":"+61","code":"CC","maxNum":"0"},
{"name":"Guernsey","dial_code":"+44","code":"GG","maxNum":"0"},
{"name":"Holy See (Vatican City State)","dial_code":"+379","code":"VA","maxNum":"0"},
{"name":"Isle of Man","dial_code":"+44","code":"IM","maxNum":"0"},
{"name":"Jersey","dial_code":"+44","code":"JE","maxNum":"0"},
{"name":"Pitcairn","dial_code":"+872","code":"PN","maxNum":"0"},
{"name":"Timor-Leste","dial_code":"+670","code":"TL","maxNum":"0"},
{"name":"Virgin Islands, British","dial_code":"+1 284","code":"VG","maxNum":"0"},
{"name":"Virgin Islands, U.S.","dial_code":"+1 340","code":"VI","maxNum":"0"}]

View file

@ -7,8 +7,7 @@ contact="Linphone Android" <sip:linphone.android@unknown-host>
use_info=0
use_ipv6=0
keepalive_period=30000
rls_uri=sip:rls@sip1.linphone.org
use_rls_presence=1
[video]
size=qvga

View file

@ -12,6 +12,9 @@ register_only_when_network_is_up=1
auto_net_state_mon=0
auto_answer_replacing_calls=1
ping_with_options=0
rls_uri=sip:rls@sip.linphone.org
use_rls_presence=1
[rtp]
audio_rtp_port=7076
@ -33,6 +36,19 @@ ec_calibrator_cool_tones=1
[misc]
max_calls=10
[app]
activation_code_length=4
[in-app-purchase]
server_url=https://www.linphone.org/xmlrpc.php
server_url=https://sip3.linphone.org:444/inapp.php
purchasable_items_ids=test_account_subscription
[assistant]
domain=sip.linphone.org
password_max_length=-1
password_min_length=1
username_length=-1
username_max_length=64
username_min_length=1
username_regex=^[a-z0-9_.\-]*$
xmlrpc_url=https://sip3.linphone.org:444/wizard.php

View file

@ -1,77 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- New settings -->
<string name="default_domain">sip.linphone.org</string>
<string name="default_stun">stun.linphone.org</string>
<!-- Global -->
<string name="default_domain">sip.linphone.org</string><!-- Set the default domain used for account creation/addresses -->
<string name="sync_account_type">org.linphone</string> <!-- Change package ! -->
<string name="sync_mimetype">vnd.android.cursor.item/org.linphone.profile</string> <!-- Change package, leave .profile at the end. Also change res/xml/contacts.xml ! -->
<bool name="assistant_use_linphone_login_as_first_fragment">false</bool>
<bool name="hide_in_call_stats">false</bool>
<bool name="orientation_portrait_only">false</bool>
<bool name="show_statusbar_only_on_dialer">false</bool>
<bool name="replace_assistant_with_old_interface">false</bool>
<bool name="force_use_of_linphone_friends">false</bool>
<bool name="in_app_purchase_in_settings">false</bool>
<bool name="use_linphone_tag">true</bool>
<string name="wizard_url">https://www.linphone.org/wizard.php</string>
<!-- Phone numbers -->
<bool name="use_phone_number_validation">true</bool><!-- Use phone number for validation -->
<integer name="popup_time_interval">86400</integer><!-- Time between two inapp notifications in seconds -->
<!-- Assistant -->
<bool name="assistant_allow_username">true</bool> <!-- Allow to use an username instead of the phone number for account creation -->
<bool name="assistant_use_linphone_login_as_first_fragment">false</bool><!-- Start assistant in loginFragment view instead of menu -->
<bool name="replace_assistant_with_old_interface">false</bool>
<bool name="hide_assistant">false</bool>
<bool name="assistant_cancel_move_to_back">false</bool>
<bool name="pre_fill_email_in_assistant">true</bool> <!-- Set the email field of the wizard with one of the gmail account registered on the device -->
<bool name="assistant_account_validation_mandatory">false</bool>
<bool name="allow_only_phone_numbers_in_assistant">false</bool>
<bool name="hide_linphone_accounts_in_assistant">false</bool>
<bool name="hide_generic_accounts_in_assistant">false</bool>
<bool name="hide_remote_provisioning_in_assistant">false</bool>
<bool name="display_account_assistant_at_first_start">true</bool>
<!-- Remote provisioning -->
<bool name="display_sms_remote_provisioning_activity">false</bool>
<bool name="forbid_app_usage_until_remote_provisioning_completed">false</bool>
<bool name="display_confirmation_popup_after_first_configuration">false</bool>
<bool name="allow_cancel_remote_provisioning_login_activity">true</bool>
<!-- Inapp -->
<bool name="enable_in_app_purchase">false</bool>
<integer name="days_notification_shown">5</integer><!-- Notification shown before end of trial version in days -->
<integer name="time_between_inapp_notification">86400</integer><!-- Time between two inapp notifications in seconds -->
<bool name="hide_username_in_inapp">true</bool>
<!-- Push notification settings -->
<bool name="enable_push_id">true</bool>
<string name="push_sender_id">622464153529</string>
<bool name="hide_camera_settings">false</bool>
<bool name="hide_wizard">false</bool>
<bool name="disable_chat">false</bool>
<bool name="disable_chat_message_notification">false</bool>
<bool name="disable_chat_send_file">false</bool>
<bool name="setup_account_validation_mandatory">false</bool>
<bool name="hide_linphone_accounts_wizard">false</bool>
<bool name="hide_generic_accounts_wizard">false</bool>
<bool name="hide_remote_provisioning_in_wizard">false</bool>
<bool name="allow_cancel_remote_provisioning_login_activity">true</bool>
<bool name="hide_accounts">false</bool>
<bool name="display_account_wizard_at_first_start">true</bool>
<bool name="allow_only_phone_numbers_in_wizard">false</bool>
<bool name="use_linphone_tag">true</bool>
<bool name="pre_fill_email_in_wizard">true</bool> <!-- Set the email field of the wizard with one of the gmail account registered on the device -->
<!-- Call -->
<bool name="forbid_self_call">false</bool>
<bool name="allow_ringing_while_early_media">true</bool>
<bool name="allow_transfers">true</bool>
<bool name="disable_options_in_call">false</bool>
<bool name="automatically_start_intercepted_outgoing_gsm_call">true</bool><!-- This settings handle the behavior of the view waiting for the remote provisioning configuration to be done -->
<bool name="hide_camera_settings">false</bool>
<bool name="hide_in_call_stats">false</bool>
<bool name="automatically_start_intercepted_outgoing_gsm_call">true</bool>
<!-- This settings handle the behavior of the view waiting for the remote provisioning configuration to be done -->
<bool name="display_sms_remote_provisioning_activity">false</bool>
<bool name="forbid_app_usage_until_remote_provisioning_completed">false</bool>
<bool name="display_confirmation_popup_after_first_configuration">false</bool>
<!-- Settings -->
<bool name="disable_every_log">false</bool>
<bool name="disable_all_security_features_for_markets">false</bool> <!-- Disable TLS/SRTP/ZRTP -->
<bool name="disable_all_patented_codecs_for_markets">false</bool> <!-- Disable MPEG4/H264 -->
<string name="about_bugreport_email">linphone-android@belledonne-communications.com</string>
<bool name="use_friendlist_subscription">true</bool>
<string name="default_stun">stun.linphone.org</string>
<bool name="hide_accounts">false</bool>
<!-- Chat -->
<bool name="disable_chat">false</bool>
<bool name="disable_chat_message_notification">false</bool>
<bool name="disable_chat_send_file">false</bool>
<string name="temp_photo_name">linphone-android-photo-temp</string>
<string name="temp_photo_name_with_date">linphone-android-photo-%s</string>
<bool name="hide_phone_numbers_in_editor">false</bool>
<bool name="hide_sip_addresses_in_editor">false</bool>
<!-- Contacts -->
<bool name="hide_contact_phone_numbers">false</bool>
<bool name="hide_contact_sip_addresses">false</bool>
<bool name="hide_phone_numbers_in_editor">false</bool>
<bool name="hide_sip_addresses_in_editor">false</bool>
<bool name="allow_only_one_phone_number">false</bool>
<bool name="allow_only_one_sip_address">false</bool>
<bool name="display_contact_organization">true</bool>
<bool name="setup_cancel_move_to_back">false</bool>
<!-- Others Parameters-->
<string name="about_bugreport_email">linphone-android@belledonne-communications.com</string>
<bool name="enable_call_notification">true</bool>
<bool name="kill_service_with_task_manager">true</bool>

View file

@ -75,6 +75,7 @@
<string name="pref_service_notification_key">pref_service_notification_key</string>
<string name="pref_escape_plus_key">pref_escape_plus_key</string>
<string name="pref_friendlist_subscribe_key">pref_friendlist_subscribe_key</string>
<string name="pref_link_account_key">pref_link_account_key</string>
<string name="pref_echo_cancellation_key">pref_echo_cancellation_key</string>
<string name="pref_autostart_key">pref_autostart_key</string>
<string name="pref_enable_outbound_proxy_key">Outbound proxy</string>

View file

@ -17,12 +17,15 @@
<string name="sync_account_name">linphone contacts</string>
<string name="history_date_format">EEE, d MMM</string>
<string name="history_detail_date_format">yyyy/MM/dd - HH:mm - </string>
<string name="inapp_popup_date_format">yyyy/MM/dd</string>
<string name="inapp_popup_date_day">dd</string>
<string name="messages_date_format">dd/MM, HH:mm</string>
<string name="messages_list_date_format">dd/MM</string>
<string name="today_date_format">HH:mm</string>
<!-- Common -->
<string name="username">Username</string>
<string name="phone_number">Phone number</string>
<string name="display_name">Display name</string>
<string name="password">Password</string>
<string name="confirm_password">Password confirmation</string>
@ -46,6 +49,14 @@
<string name="connect">Connection</string>
<string name="decline">Decline</string>
<string name="conference">Conference</string>
<string name="link">Link</string>
<string name="link_account_popup">Do you want to link the account %s with your phone number ?</string>
<string name="maybe_later">Maybe later</string>
<string name="later">Later</string>
<string name="no">No</string>
<string name="ok">Ok</string>
<string name="yes">Yes</string>
<string name="link_account">Link account</string>
<!-- Launch screen -->
<string name="app_description">the <i>libre</i> SIP client</string>
@ -54,9 +65,11 @@
<string name="welcome">Welcome</string>
<string name="assistant">Assistant</string>
<string name="assistant_create_account">Create account</string>
<string name="assistant_continue">Continue</string>
<string name="assistant_activate">Activate account</string>
<string name="assistant_finish">Finish configuration</string>
<string name="assistant_validate_account">Your account is created. Please check your mails to validate your account. Once it is done, come back here and click on the button.</string>
<string name="assistant_welcome_desc">This assistant will help you to use a SIP account for your calls.</string>
<string name="assistant_welcome_desc">This assistant will help you configure and use your SIP account.</string>
<string name="assistant_linphone_login_desc">Enter your username and password of Linphone account</string>
<string name="assistant_login_desc">Enter your username and password with your SIP domain</string>
<string name="assistant_remote_provisioning_desc">Please provide your provisioning URL</string>
@ -64,10 +77,10 @@
<string name="assistant_login_linphone">Use Linphone account</string>
<string name="assistant_login_generic">Use SIP account</string>
<string name="assistant_remote_provisioning">Fetch remote configuration</string>
<string name="assistant_create_account_part_1">1/2</string>
<string name="assistant_create_account_part_2">2/2</string>
<string name="assistant_create_account_part_1">Please confirm your country code and enter your phone number</string>
<string name="assistant_create_account_part_2">We have sent you a SMS with a validation code.\n\nTo complete your phone number verification, please enter the 4 digit code below:\n</string>
<string name="assistant_display_name_optional">Display name (optional)</string>
<string name="assistant_linphone_account">Configure Linphone account</string>
<string name="assistant_linphone_account">Use your Linphone account</string>
<string name="assistant_generic_account">Configure SIP account</string>
<string name="assistant_remote_provisioning_title">Fetch remote configuration</string>
<string name="assistant_fetch_apply">Fetch and apply</string>
@ -75,6 +88,7 @@
<string name="assistant_ec_calibration">Echo canceler calibration in progress</string>
<string name="assistant_remote_provisioning_login">Enter your login</string>
<string name="assistant_account_not_validated">Your account has not been validated yet.</string>
<string name="assistant_error_confirmation_code"></string>
<string name="assistant_account_validated">Your account has been validated.</string>
<string name="assistant_error_bad_credentials">Incorrect username or password</string>
<string name="assistant_codec_down_question">Do you agree to download OpenH264 Video Codec provided by Cisco Systems, Inc.?</string>
@ -83,13 +97,47 @@
<string name="wizard_failed">An error occurred, try again later.</string>
<string name="wizard_server_unavailable">Server unreachable, verify your network connection.</string>
<string name="wizard_username_unavailable">This username is already in use.</string>
<string name="assistant_phone_number_unavailable">This phone number is already in use.</string>
<string name="wizard_username_incorrect">Your username is invalid.</string>
<string name="assistant_phone_number_incorrect">Your phone number is invalid.</string>
<string name="wizard_email_incorrect">Your email is invalid.</string>
<string name="wizard_password_incorrect">Your password is invalid</string>
<string name="wizard_passwords_unmatched">Passwords do not match.</string>
<string name="setup_confirm_username">Your username will be %s.\r\n\r\nIt may differ from your input to match requirements.\r\nDo you accept?</string>
<string name="first_launch_no_login_password">Please enter your login and password</string>
<string name="forgot_password">Forgot password ?</string>
<string name="assistant_choose_country">Choose a country</string>
<string name="select_your_country">Select your Country</string>
<string name="country_code">(%s)</string>
<string name="use_username_instead_or_phone_number">Use a username (optional)</string>
<string name="use_email_for_validation">Use email address for account validation</string>
<string name="login_with_username">Use your username and password instead of your phone number</string>
<string name="phone_number_info_title">What will my phone number be used for?</string>
<string name="phone_number_info_content">\nThanks to your phone number, your friends will find you more easily.\n\nYou will see in your addressbook who is using Linphone and your friends will know that they can rach you on Linphone as well.\n</string>
<string name="phone_number_link_info_content">\nYour friends will find your more easily if you link your account to your phone number\n\nYou will see in your addressbook who is using Linphone and your friends will know that they can rach you on Linphone as well.\n</string>
<!-- Status -->
<string name="invalid_email">Invalid email</string>
<string name="account_already_exist">Account already exist</string>
<string name="invalid_username">Invalid username</string>
<string name="invalid_domain">Invalid domain</string>
<string name="invalid_route">Invalid route</string>
<string name="username_too_short">Username too short</string>
<string name="username_too_long">Username too long</string>
<string name="username_invalid_size">Username length invalid</string>
<string name="phone_number_too_long">Phone number too long</string>
<string name="phone_number_too_short">Phone number too short</string>
<string name="phone_number_invalid">Invalid phone number</string>
<string name="password_too_short">Password too short</string>
<string name="password_too_long">Password too long</string>
<string name="request_failed">Failed to query the server. Please try again later</string>
<string name="transport_unsupported">Unsupported transport</string>
<!-- In-app -->
<string name="inapp">In-app</string>
<string name="inapp_notification_title">In-app purchase</string>
<string name="inapp_notification_trial_expire">The trail period expires on %s</string>
<string name="inapp_notification_account_expire">The subscription period expires on %s</string>
<!-- Dailer -->
<string name="address_bar_hint">Enter a number or an address</string>
@ -107,7 +155,6 @@
<string name="delete_contacts">Do you want to delete selected contacts?</string>
<string name="delete_contact">Do you want to delete selected contact?</string>
<string name="sip_address">SIP address</string>
<string name="phone_number">Phone number</string>
<string name="contact_first_name">First name</string>
<string name="contact_last_name">Last name</string>
<string name="contact_organization">Organization</string>
@ -211,6 +258,7 @@
<string name="pref_avpf_rr_interval"> AVPF regular RTCP interval in seconds (between 1 and 5)</string>
<string name="pref_escape_plus">Replace + by 00</string>
<string name="pref_friendlist_subscribe">Friendlist subscribe</string>
<string name="pref_link_account">Link account</string>
<string name="pref_auth_userid">Auth userid</string>
<string name="pref_help_auth_userid">Enter authentication userid (optional)</string>
<string name="pref_display_name">Display name</string>
@ -357,6 +405,7 @@
<string name="content_description_new_discussion">New discussion</string>
<string name="content_description_search">Search</string>
<string name="content_description_search_contact">Search contact</string>
<string name="content_description_search_country">Search country</string>
<string name="content_description_all_contacts">All contacts</string>
<string name="content_description_linphone_contacts">Linphone contacts</string>
<string name="content_description_call_direction">Call direction</string>
@ -376,6 +425,8 @@
<string name="content_description_message_status">Message status</string>
<string name="content_description_conference">Conference</string>
<string name="content_description_username_field">Username field</string>
<string name="content_description_activation_code_field">Username field</string>
<string name="content_description_phone_number_field">Phone number field</string>
<string name="content_description_display_field">Display name field</string>
<string name="content_description_domain_field">Domain field</string>
<string name="content_description_url_field">Remote provisioning field</string>

View file

@ -92,6 +92,11 @@
android:key="@string/pref_friendlist_subscribe_key"
android:persistent="false"/>
<Preference
android:title="@string/pref_link_account"
android:key="@string/pref_link_account_key"
android:persistent="false"/>
</PreferenceCategory>
<PreferenceCategory

View file

@ -14,11 +14,6 @@
android:key="@string/pref_add_account_key"
android:persistent="false"/>
<Preference
android:title="@string/pref_in_app_store"
android:key="@string/pref_in_app_store_key"
android:persistent="false"/>
<PreferenceCategory
android:title="@string/pref_preferences_title">

View file

@ -236,10 +236,18 @@ public class AccountPreferencesFragment extends PreferencesListFragment {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean value = (Boolean) newValue;
mPrefs.enabledFriendlistSubscription(value);
LinphoneManager.getInstance().subscribeFriendList(value);
return true;
}
};
OnPreferenceClickListener linkAccountListener = new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
LinphoneActivity.instance().displayLinkPhoneNumber();
return true;
}
};
OnPreferenceChangeListener disableChangedListener = new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
@ -369,9 +377,12 @@ public class AccountPreferencesFragment extends PreferencesListFragment {
CheckBoxPreference friendlistSubscribe = (CheckBoxPreference) advanced.getPreference(8);
friendlistSubscribe.setOnPreferenceChangeListener(friendlistSubscribeListener);
if(!isNewAccount){
escape.setChecked(mPrefs.getReplacePlusByZeroZero(n));
friendlistSubscribe.setChecked(mPrefs.isFriendlistsubscriptionEnabled());
}
Preference linkAccount = advanced.getPreference(9);
linkAccount.setOnPreferenceClickListener(linkAccountListener);
PreferenceCategory manage = (PreferenceCategory) getPreferenceScreen().findPreference(getString(R.string.pref_manage_key));
final CheckBoxPreference disable = (CheckBoxPreference) manage.getPreference(0);
disable.setEnabled(true);

View file

@ -124,8 +124,6 @@ public class CallOutgoingActivity extends Activity implements OnClickListener{
}
}
};
super.onCreate(savedInstanceState);
instance = this;
}

View file

@ -134,9 +134,18 @@ public class ContactDetailsFragment extends Fragment implements OnClickListener
tv.setText(displayednumberOrAddress);
tv.setSelected(true);
String contactAddress = contact.getPresenceModelForUri(noa.getValue());
if(contactAddress != null) {
v.findViewById(R.id.friendLinphone).setVisibility(View.VISIBLE);
}
if (!displayChatAddressOnly) {
v.findViewById(R.id.contact_call).setOnClickListener(dialListener);
v.findViewById(R.id.contact_call).setTag(displayednumberOrAddress);
if(contactAddress != null){
v.findViewById(R.id.contact_call).setTag(contact.getPresenceModelForUri(noa.getValue()));
} else {
v.findViewById(R.id.contact_call).setTag(displayednumberOrAddress);
}
} else {
v.findViewById(R.id.contact_call).setVisibility(View.GONE);
}
@ -146,9 +155,18 @@ public class ContactDetailsFragment extends Fragment implements OnClickListener
if (lpc != null) {
String username = lpc.normalizePhoneNumber(LinphoneUtils.getUsernameFromAddress(noa.getValue()));
String tag = LinphoneUtils.getFullAddressFromUsername(username);
v.findViewById(R.id.contact_chat).setTag(tag);
if(contactAddress != null){
v.findViewById(R.id.contact_chat).setTag(contact.getPresenceModelForUri(noa.getValue()));
} else {
v.findViewById(R.id.contact_chat).setTag(tag);
}
} else {
v.findViewById(R.id.contact_chat).setTag(noa.getValue());
if(contactAddress != null){
v.findViewById(R.id.contact_chat).setTag(contact.getPresenceModelForUri(noa.getValue()));
} else {
v.findViewById(R.id.contact_chat).setTag(noa.getValue());
}
}
if (getResources().getBoolean(R.bool.disable_chat)) {

View file

@ -217,7 +217,7 @@ public class ContactsManager extends ContentObserver {
contacts = c;
sipContacts = new ArrayList<LinphoneContact>();
for (LinphoneContact contact : contacts) {
if (contact.hasAddress()) {
if (contact.hasAddress() || contact.isInLinphoneFriendList()) {
sipContacts.add(contact);
}
}

View file

@ -32,6 +32,8 @@ import org.linphone.assistant.AssistantActivity;
import org.linphone.assistant.RemoteProvisioningLoginActivity;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.CallDirection;
import org.linphone.core.LinphoneAccountCreator;
import org.linphone.core.LinphoneAccountCreatorImpl;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneAuthInfo;
import org.linphone.core.LinphoneCall;
@ -48,7 +50,10 @@ import org.linphone.core.LinphoneCoreListenerBase;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.core.Reason;
import org.linphone.mediastream.Log;
import org.linphone.purchase.InAppPurchaseActivity;
import org.linphone.ui.AddressText;
import org.linphone.xmlrpc.XmlRpcHelper;
import org.linphone.xmlrpc.XmlRpcListenerBase;
import android.Manifest;
import android.annotation.SuppressLint;
@ -58,6 +63,7 @@ import android.app.Dialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@ -68,6 +74,7 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
@ -97,7 +104,7 @@ import android.widget.Toast;
/**
* @author Sylvain Berfini
*/
public class LinphoneActivity extends Activity implements OnClickListener, ContactPicked, ActivityCompat.OnRequestPermissionsResultCallback {
public class LinphoneActivity extends Activity implements OnClickListener, ContactPicked, ActivityCompat.OnRequestPermissionsResultCallback, LinphoneAccountCreator.LinphoneAccountCreatorListener {
public static final String PREF_FIRST_LAUNCH = "pref_first_launch";
private static final int SETTINGS_ACTIVITY = 123;
private static final int CALL_ACTIVITY = 19;
@ -122,17 +129,18 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
private Fragment.SavedState dialerSavedState;
private boolean newProxyConfig;
private boolean emptyFragment = false;
private boolean isTrialAccount = false;
private OrientationEventListener mOrientationHelper;
private LinphoneCoreListenerBase mListener;
private LinearLayout mTabBar;
private DrawerLayout sideMenu;
private String[] sideMenuItems;
private RelativeLayout sideMenuContent, quitLayout, defaultAccount;
private ListView accountsList, sideMenuItemList;
private ImageView menu;
private boolean fetchedContactsOnce = false;
private boolean doNotGoToCallActivity = false;
private List<String> sideMenuItems;
private boolean callTransfer = false;
static final boolean isInstanciated() {
@ -147,6 +155,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
@Override
protected void onCreate(Bundle savedInstanceState) {
//This must be done before calling super.onCreate().
super.onCreate(savedInstanceState);
if (getResources().getBoolean(R.bool.orientation_portrait_only)) {
@ -159,7 +168,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
return;
}
boolean useFirstLoginActivity = getResources().getBoolean(R.bool.display_account_wizard_at_first_start);
boolean useFirstLoginActivity = getResources().getBoolean(R.bool.display_account_assistant_at_first_start);
if (LinphonePreferences.instance().isProvisioningLoginViewEnabled()) {
Intent wizard = new Intent();
wizard.setClass(this, RemoteProvisioningLoginActivity.class);
@ -224,6 +233,14 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
refreshAccounts();
if(state.equals(RegistrationState.RegistrationOk) && LinphonePreferences.instance().getLinkPopupTime() != ""){
if(getResources().getBoolean(R.bool.use_phone_number_validation)) {
if (LinphonePreferences.instance().getLinkPopupTime() == null || (LinphonePreferences.instance().getLinkPopupTime() != null)){
isAccountWithAlias();
}
}
}
if(state.equals(RegistrationState.RegistrationFailed) && newProxyConfig) {
newProxyConfig = false;
if (proxy.getError() == Reason.BadCredentials) {
@ -414,7 +431,6 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
}
private void changeFragment(Fragment newFragment, FragmentsAvailable newFragmentType, boolean withoutAnimation) {
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
@ -615,6 +631,17 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
startActivity(new Intent(LinphoneActivity.this, AssistantActivity.class));
}
public void displayLinkPhoneNumber() {
Intent assistant = new Intent();
assistant.setClass(this, AssistantActivity.class);
assistant.putExtra("LinkPhoneNumber", true);
startActivity(assistant);
}
public void displayInapp() {
startActivity(new Intent(LinphoneActivity.this, InAppPurchaseActivity.class));
}
public int getUnreadMessageCount() {
int count = 0;
LinphoneChatRoom[] chats = LinphoneManager.getLc().getChatRooms();
@ -1107,41 +1134,15 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
protected void onPause() {
getIntent().putExtra("PreviousActivity", 0);
if(LinphonePreferences.instance().isFriendlistsubscriptionEnabled()){
LinphoneManager.getInstance().subscribeFriendList(!isApplicationBroughtToBackground(this));
}
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.removeListener(mListener);
}
callTransfer = false;
super.onPause();
}
@SuppressWarnings("deprecation")
public static boolean isApplicationBroughtToBackground(final Activity activity) {
ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);
// Check the top Activity against the list of Activities contained in the Application's package.
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
try {
PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
for (ActivityInfo activityInfo : pi.activities) {
if(topActivity.getClassName().equals(activityInfo.name)) {
return false;
}
}
} catch( PackageManager.NameNotFoundException e) {
return false; // Never happens.
}
}
return true;
}
public boolean checkAndRequestOverlayPermission() {
Log.i("[Permission] Draw overlays permission is " + (Compatibility.canDrawOverlays(this) ? "granted" : "denied"));
if (!Compatibility.canDrawOverlays(this)) {
@ -1173,6 +1174,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
checkAndRequestPermission(Manifest.permission.READ_CONTACTS, PERMISSIONS_REQUEST_CONTACTS);
}
public void checkAndRequestInappPermission() {
checkAndRequestPermission(Manifest.permission.GET_ACCOUNTS, PERMISSIONS_REQUEST_CONTACTS);
}
private boolean willContactsPermissionBeAsked() {
return LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.READ_CONTACTS, false) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS);
}
@ -1199,6 +1204,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
int readExternalStorage = getPackageManager().checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE, getPackageName());
Log.i("[Permission] Read external storage permission is " + (readExternalStorage == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
int camera = getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName());
int accounts = getPackageManager().checkPermission(Manifest.permission.GET_ACCOUNTS, getPackageName());
Log.i("[Permission] Camera permission is " + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (readExternalStorage != PackageManager.PERMISSION_GRANTED) {
@ -1322,7 +1328,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
protected void onResume() {
super.onResume();
if (!LinphoneService.isReady()) {
if (!LinphoneService.isReady()) {
startService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class));
}
@ -1344,9 +1350,15 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
refreshAccounts();
if(getResources().getBoolean(R.bool.enable_in_app_purchase)){
isTrialAccount();
}
updateMissedChatCount();
if(LinphonePreferences.instance().isFriendlistsubscriptionEnabled()){
if(LinphonePreferences.instance().isFriendlistsubscriptionEnabled() && LinphoneManager.getLc().getDefaultProxyConfig() != null){
LinphoneManager.getInstance().subscribeFriendList(true);
} else {
LinphoneManager.getInstance().subscribeFriendList(false);
}
displayMissedCalls(LinphoneManager.getLc().getMissedCallsCount());
@ -1409,6 +1421,10 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
} else if (extras != null && extras.getBoolean("GoToHistory", false)) {
doNotGoToCallActivity = true;
changeCurrentFragment(FragmentsAvailable.HISTORY_LIST, null);
} else if (extras != null && extras.getBoolean("GoToInapp", false)) {
LinphoneService.instance().removeMessageNotification();
doNotGoToCallActivity = true;
displayInapp();
} else if (extras != null && extras.getBoolean("Notification", false)) {
if (LinphoneManager.getLc().getCallsNb() > 0) {
LinphoneCall call = LinphoneManager.getLc().getCalls()[0];
@ -1471,7 +1487,13 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
public void initSideMenu() {
sideMenu = (DrawerLayout) findViewById(R.id.side_menu);
sideMenuItems = new String[]{getResources().getString(R.string.menu_assistant),getResources().getString(R.string.menu_settings),getResources().getString(R.string.menu_about)};
sideMenuItems = new ArrayList<String>();
sideMenuItems.add(getResources().getString(R.string.menu_assistant));
sideMenuItems.add(getResources().getString(R.string.menu_settings));
if(getResources().getBoolean(R.bool.enable_in_app_purchase)){
sideMenuItems.add(getResources().getString(R.string.inapp));
}
sideMenuItems.add(getResources().getString(R.string.menu_about));
sideMenuContent = (RelativeLayout) findViewById(R.id.side_menu_content);
sideMenuItemList = (ListView)findViewById(R.id.item_list);
menu = (ImageView) findViewById(R.id.side_menu_button);
@ -1480,15 +1502,20 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
sideMenuItemList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if(sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_settings))){
if (sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_settings))) {
LinphoneActivity.instance().displaySettings();
}
if(sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_about))){
if (sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_about))) {
LinphoneActivity.instance().displayAbout();
}
if(sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_assistant))){
if (sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_assistant))) {
LinphoneActivity.instance().displayAssistant();
}
if(getResources().getBoolean(R.bool.enable_in_app_purchase)){
if (sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.inapp))) {
LinphoneActivity.instance().displayInapp();
}
}
openOrCloseSideMenu(false);
}
});
@ -1546,6 +1573,7 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
status.setVisibility(View.GONE);
address.setText("");
statusFragment.resetAccountStatus();
LinphoneManager.getInstance().subscribeFriendList(false);
defaultAccount.setOnClickListener(new OnClickListener() {
@Override
@ -1660,6 +1688,153 @@ public class LinphoneActivity extends Activity implements OnClickListener, Conta
return view;
}
}
private void isAccountWithAlias(){
if(LinphoneManager.getLc().getDefaultProxyConfig() != null) {
LinphoneAccountCreator accountCreator;
accountCreator = new LinphoneAccountCreatorImpl(LinphoneManager.getLc(), LinphonePreferences.instance().getXmlrpcUrl());
accountCreator.setDomain(getResources().getString(R.string.default_domain));
accountCreator.setListener(this);
accountCreator.setUsername(LinphonePreferences.instance().getAccountUsername(LinphonePreferences.instance().getDefaultAccountIndex()));
accountCreator.isAccountUsed();
} else {
LinphonePreferences.instance().setLinkPopupTime(null);
}
}
//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) {
isTrialAccount = isTrial;
getExpirationAccount();
}
@Override
public void onError(String error) {
}
}, 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(String error) {
}
}, LinphonePreferences.instance().getAccountUsername(LinphonePreferences.instance().getDefaultAccountIndex()), LinphonePreferences.instance().getAccountHa1(LinphonePreferences.instance().getDefaultAccountIndex()));
}
}
public void displayInappNotification(String date) {
long now = Calendar.getInstance().getTimeInMillis();
if (LinphonePreferences.instance().getInappPopupTime() != null && Long.parseLong(LinphonePreferences.instance().getInappPopupTime()) < now) {
return;
} else {
long newDate = now + (getResources().getInteger(R.integer.time_between_inapp_notification)*60);
LinphonePreferences.instance().setInappPopupTime(String.valueOf(newDate));
}
if(isTrialAccount){
LinphoneService.instance().displayInappNotification(String.format(getString(R.string.inapp_notification_trial_expire), date));
} else {
LinphoneService.instance().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 void askLinkWithPhoneNumber(){
long now = Calendar.getInstance().getTimeInMillis();
long newDate = now + (getResources().getInteger(R.integer.popup_time_interval)*60);
if (LinphonePreferences.instance().getLinkPopupTime() != null && Long.parseLong(LinphonePreferences.instance().getLinkPopupTime()) > now) {
return;
} else {
LinphonePreferences.instance().setLinkPopupTime(String.valueOf(newDate));
}
final Dialog dialog = displayDialog(String.format(getResources().getString(R.string.link_account_popup), LinphoneManager.getLc().getDefaultProxyConfig().getAddress().asStringUriOnly()));
Button delete = (Button) dialog.findViewById(R.id.delete_button);
delete.setText(getResources().getString(R.string.link));
Button cancel = (Button) dialog.findViewById(R.id.cancel);
cancel.setText(getResources().getString(R.string.maybe_later));
delete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
displayLinkPhoneNumber();
dialog.dismiss();
}
});
LinphonePreferences.instance().setLinkPopupTime(String.valueOf(newDate));
cancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
dialog.dismiss();
}
});
dialog.show();
}
@Override
public void onAccountCreatorIsAccountUsed(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
if(status.equals(LinphoneAccountCreator.Status.AccountExist)){
askLinkWithPhoneNumber();
}
}
@Override
public void onAccountCreatorAccountCreated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {}
@Override
public void onAccountCreatorAccountActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {}
@Override
public void onAccountCreatorAccountLinkedWithPhoneNumber(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {}
@Override
public void onAccountCreatorPhoneNumberLinkActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {}
@Override
public void onAccountCreatorIsAccountActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {}
@Override
public void onAccountCreatorPhoneAccountRecovered(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {}
}
interface ContactPicked {

View file

@ -635,6 +635,13 @@ public class LinphoneContact implements Serializable, Comparable<LinphoneContact
return (friend != null && friend.getPresenceModel() != null && friend.getPresenceModel().getBasicStatus().equals(PresenceBasicStatus.Open));
}
public String getPresenceModelForUri(String uri) {
if (friend != null && friend.getPresenceModelForUri(uri) != null){
return friend.getPresenceModelForUri(uri).getContact();
}
return null;
}
public void setFriend(LinphoneFriend f) {
friend = f;
}

View file

@ -435,6 +435,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
LinphoneCore lc = getLcIfManagerNotDestroyedOrNull();
if(lc != null ) {
LinphoneFriendList mFriendList = (lc.getFriendLists())[0];
Log.i("Presence list subscription is " + (enabled ? "enabled" : "disabled"));
mFriendList.enableSubscriptions(enabled);
}
}
@ -717,6 +718,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
PreferencesMigrator prefMigrator = new PreferencesMigrator(mServiceContext);
prefMigrator.migrateRemoteProvisioningUriIfNeeded();
prefMigrator.migrateSharingServerUrlIfNeeded();
prefMigrator.doPresenceMigrationIfNeeded();
if (prefMigrator.isMigrationNeeded()) {
prefMigrator.doMigration();
@ -750,7 +752,7 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
mLc.setCallLogsDatabasePath(mCallLogDatabaseFile);
mLc.setFriendsDatabasePath(mFriendsDatabaseFile);
mLc.setUserCertificatesPath(mUserCertificatePath);
subscribeFriendList(mPrefs.isFriendlistsubscriptionEnabled());
//subscribeFriendList(mPrefs.isFriendlistsubscriptionEnabled());
//mLc.setCallErrorTone(Reason.NotFound, mErrorToneFile);
enableDeviceRingtone(mPrefs.isDeviceRingtoneEnabled());
@ -985,6 +987,9 @@ public class LinphoneManager implements LinphoneCoreListener, LinphoneChatMessag
public void registrationState(final LinphoneCore lc, final LinphoneProxyConfig proxy,final RegistrationState state,final String message) {
Log.i("New registration state ["+state+"]");
if(LinphoneManager.getLc().getDefaultProxyConfig() == null){
subscribeFriendList(false);
}
}
private int savedMaxCallWhileGsmIncall;

View file

@ -26,6 +26,8 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import org.linphone.core.LinphoneAccountCreator;
import org.linphone.core.LinphoneAccountCreatorImpl;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneAddress.TransportType;
import org.linphone.core.LinphoneAuthInfo;
@ -192,15 +194,22 @@ public class LinphonePreferences {
getLc().addAuthInfo(authInfo);
}
public LinphoneAccountCreator AccountCreator(LinphoneCore lc, String server_url) {
return new LinphoneAccountCreatorImpl(lc, server_url);
}
public static class AccountBuilder {
private LinphoneCore lc;
private String tempUsername;
private String tempDisplayName;
private String tempUserId;
private String tempPassword;
private String tempHa1;
private String tempDomain;
private String tempProxy;
private String tempRealm;
private String tempPrefix;
private boolean tempOutboundProxy;
private String tempContactsParams;
private String tempExpire;
@ -238,6 +247,11 @@ public class LinphonePreferences {
return this;
}
public AccountBuilder setHa1(String ha1) {
tempHa1 = ha1;
return this;
}
public AccountBuilder setDomain(String domain) {
tempDomain = domain;
return this;
@ -288,6 +302,11 @@ public class LinphonePreferences {
return this;
}
public AccountBuilder setPrefix(String prefix) {
tempPrefix = prefix;
return this;
}
public AccountBuilder setQualityReportingEnabled(boolean enable) {
tempQualityReportingEnabled = enable;
return this;
@ -360,10 +379,15 @@ public class LinphonePreferences {
prxCfg.setQualityReportingCollector(tempQualityReportingCollector);
prxCfg.setQualityReportingInterval(tempQualityReportingInterval);
if(tempPrefix != null){
prxCfg.setDialPrefix(tempPrefix);
}
if(tempRealm != null)
prxCfg.setRealm(tempRealm);
LinphoneAuthInfo authInfo = LinphoneCoreFactory.instance().createAuthInfo(tempUsername, tempUserId, tempPassword, null, null, tempDomain);
LinphoneAuthInfo authInfo = LinphoneCoreFactory.instance().createAuthInfo(tempUsername, tempUserId, tempPassword, tempHa1, tempRealm, tempDomain);
lc.addProxyConfig(prxCfg);
lc.addAuthInfo(authInfo);
@ -520,10 +544,23 @@ public class LinphonePreferences {
}
}
public void setAccountHa1(int n, String ha1) {
if(getAccountDomain(n) != null && getAccountUsername(n) != null) {
LinphoneAuthInfo authInfo = LinphoneCoreFactory.instance().createAuthInfo(getAccountUsername(n), null, null, ha1, null, getAccountDomain(n));
LinphoneManager.getLc().addAuthInfo(authInfo);
}
}
public String getAccountPassword(int n) {
LinphoneAuthInfo authInfo = getAuthInfo(n);
return authInfo == null ? null : authInfo.getPassword();
}
public String getAccountHa1(int n) {
LinphoneAuthInfo authInfo = getAuthInfo(n);
return authInfo == null ? null : authInfo.getHa1();
}
public void setAccountDomain(int n, String domain) {
String identity = "sip:" + getAccountUsername(n) + "@" + domain;
LinphoneAuthInfo old_info = getAuthInfo(n);
@ -1324,6 +1361,30 @@ public class LinphonePreferences {
return purchasables;
}
public String getXmlrpcUrl(){
return getConfig().getString("assistant", "xmlrpc_url", null);
}
public void setXmlrpcUrl(String url){
getConfig().setString("assistant", "xmlrpc_url", url);
}
public String getInappPopupTime(){
return getConfig().getString("app", "inapp_popup_time", null);
}
public void setInappPopupTime(String date){
getConfig().setString("app", "inapp_popup_time", date);
}
public void setLinkPopupTime(String date){
getConfig().setString("app", "link_popup_time", date);
}
public String getLinkPopupTime(){
return getConfig().getString("app", "link_popup_time", null);
}
public String getXmlRpcServerUrl() {
return getConfig().getString("app", "server_url", null);
}
@ -1404,4 +1465,8 @@ public class LinphonePreferences {
public void enableAutoAnswer(boolean enable) {
getConfig().setBool("app", "auto_answer", enable);
}
public int getCodeLength(){
return getConfig().getInt("app", "activation_code_length", 0);
}
}

View file

@ -20,6 +20,7 @@ package org.linphone;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.LinphoneAddress;
@ -41,6 +42,7 @@ import org.linphone.ui.LinphoneOverlay;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Application;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@ -53,6 +55,7 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
@ -123,6 +126,131 @@ public final class LinphoneService extends Service {
public static int notifcationsPriority = (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41) ? Notification.PRIORITY_MIN : 0);
private WindowManager mWindowManager;
private LinphoneOverlay mOverlay;
private Application.ActivityLifecycleCallbacks activityCallbacks;
/*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 ArrayList<Activity> activities = new ArrayList<Activity>();
private boolean mActive = false;
private int mRunningActivities = 0;
class InactivityChecker implements Runnable {
private boolean isCanceled;
public 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 InactivityChecker mLastChecker;
@Override
public synchronized void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("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 resumed:" + activity);
if (activities.contains(activity)) {
mRunningActivities++;
Log.i("runningActivities=" + mRunningActivities);
checkActivity();
}
}
@Override
public synchronized void onActivityPaused(Activity activity) {
Log.i("Activity paused:" + activity);
if (activities.contains(activity)) {
mRunningActivities--;
Log.i("runningActivities=" + mRunningActivities);
checkActivity();
}
}
@Override
public void onActivityStopped(Activity activity) {
Log.i("Activity stopped:" + activity);
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public synchronized void onActivityDestroyed(Activity activity) {
Log.i("Activity destroyed:" + activity);
if (activities.contains(activity)) {
activities.remove(activity);
}
}
void startInactivityChecker() {
if (mLastChecker != null) mLastChecker.cancel();
LinphoneService.this.mHandler.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;
}
}
}
}
protected void onBackgroundMode(){
Log.i("App has entered background mode");
if (LinphonePreferences.instance() != null && LinphonePreferences.instance().isFriendlistsubscriptionEnabled()) {
if (LinphoneManager.isInstanciated())
LinphoneManager.getInstance().subscribeFriendList(false);
}
}
protected void onForegroundMode() {
Log.i("App has left background mode");
}
private void setupActivityMonitor(){
if (activityCallbacks != null) return;
getApplication().registerActivityLifecycleCallbacks(activityCallbacks = new ActivityMonitor());
}
public int getMessageNotifCount() {
return mMsgNotifCount;
@ -162,6 +290,7 @@ public final class LinphoneService extends Service {
public void onCreate() {
super.onCreate();
setupActivityMonitor();
// In case restart after a crash. Main in LinphoneActivity
mNotificationTitle = getString(R.string.service_name);
@ -483,6 +612,16 @@ public final class LinphoneService extends Service {
notifyWrapper(MESSAGE_NOTIF_ID, mMsgNotif);
}
public void displayInappNotification(String message) {
Intent notifIntent = new Intent(this, LinphoneActivity.class);
notifIntent.putExtra("GoToInapp", true);
PendingIntent notifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mNotif = Compatibility.createSimpleNotification(getApplicationContext(), getString(R.string.inapp_notification_title), message, notifContentIntent);
notifyWrapper(NOTIF_ID, mNotif);
}
public void removeMessageNotification() {
mNM.cancel(MESSAGE_NOTIF_ID);
resetIntentLaunchedOnNotificationClick();
@ -644,6 +783,12 @@ public final class LinphoneService extends Service {
@Override
public synchronized void onDestroy() {
if (activityCallbacks != null){
getApplication().unregisterActivityLifecycleCallbacks(activityCallbacks);
activityCallbacks = null;
}
destroyOverlay();
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {

View file

@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import org.linphone.LinphonePreferences.AccountBuilder;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.core.LpConfig;
import org.linphone.mediastream.Log;
import android.content.Context;
@ -163,6 +165,20 @@ public class PreferencesMigrator {
}
}
public void doPresenceMigrationIfNeeded() {
LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
LpConfig cfg = lc.getConfig();
if (cfg.getString("app", "friendlist_subscription_enabled", null) == null){
LinphoneProxyConfig proxy = lc.getDefaultProxyConfig();
if (proxy != null) {
String domain = proxy.getDomain();
if (domain!=null && domain.equals(getString(R.string.default_domain))) {
cfg.setBool("app", "friendlist_subscription_enabled", true);
}
}
}
}
private void deleteAllOldPreferences() {
Editor editor = mOldPrefs.edit();
editor.clear();

View file

@ -35,7 +35,6 @@ import org.linphone.core.PayloadType;
import org.linphone.mediastream.Log;
import org.linphone.mediastream.Version;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
import org.linphone.purchase.InAppPurchaseActivity;
import org.linphone.tools.OpenH264DownloadHelper;
import org.linphone.ui.LedPreference;
import org.linphone.ui.PreferencesListFragment;
@ -65,7 +64,6 @@ import android.provider.Settings;
* @author Sylvain Berfini
*/
public class SettingsFragment extends PreferencesListFragment {
private static final int STORE_INTENT = 2;
private LinphonePreferences mPrefs;
private Handler mHandler = new Handler();
private LinphoneCoreListenerBase mListener;
@ -143,14 +141,6 @@ public class SettingsFragment extends PreferencesListFragment {
return true;
}
});
findPreference(getString(R.string.pref_in_app_store_key)).setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent intent = new Intent(LinphoneService.instance(), InAppPurchaseActivity.class);
startActivityForResult(intent, STORE_INTENT);
return true;
}
});
}
// Sets listener for each preference to update the matching value in linphonecore
@ -174,10 +164,6 @@ public class SettingsFragment extends PreferencesListFragment {
hidePreference(R.string.pref_add_account_key);
}
if(!getResources().getBoolean(R.bool.in_app_purchase_in_settings)){
hidePreference(R.string.pref_in_app_store_key);
}
if (getResources().getBoolean(R.bool.disable_chat)) {
findPreference(getString(R.string.pref_image_sharing_server_key)).setLayoutResource(R.layout.hidden);
}

View file

@ -17,6 +17,7 @@ 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 org.linphone.LinphoneActivity;
import org.linphone.LinphoneManager;
import org.linphone.LinphonePreferences;
@ -24,6 +25,8 @@ import org.linphone.LinphoneUtils;
import org.linphone.LinphonePreferences.AccountBuilder;
import org.linphone.R;
import org.linphone.StatusFragment;
import org.linphone.core.LinphoneAccountCreator;
import org.linphone.core.LinphoneAccountCreatorImpl;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneAddress.TransportType;
import org.linphone.core.LinphoneCore;
@ -60,17 +63,19 @@ import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import android.widget.Toast;
/**
* @author Sylvain Berfini
*/
public class AssistantActivity extends Activity implements OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback {
public class AssistantActivity extends Activity implements OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback, LinphoneAccountCreator.LinphoneAccountCreatorListener {
private static AssistantActivity instance;
private ImageView back, cancel;
private AssistantFragmentsEnum currentFragment;
private AssistantFragmentsEnum lastFragment;
private AssistantFragmentsEnum firstFragment;
private Fragment fragment;
private LinphonePreferences mPrefs;
private boolean accountCreated = false, newAccount = false;
private boolean accountCreated = false, newAccount = false, isLink = false;
private LinphoneCoreListenerBase mListener;
private LinphoneAddress address;
private StatusFragment status;
@ -79,6 +84,12 @@ private static AssistantActivity instance;
private boolean remoteProvisioningInProgress;
private boolean echoCancellerAlreadyDone;
private static final int PERMISSIONS_REQUEST_RECORD_AUDIO = 201;
private LinphoneAccountCreator accountCreator;
public CountryListFragment.Country country;
public String phone_number;
public String email;
public String activation_code;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -90,23 +101,30 @@ private static AssistantActivity instance;
setContentView(R.layout.assistant);
initUI();
firstFragment = getResources().getBoolean(R.bool.assistant_use_linphone_login_as_first_fragment) ? AssistantFragmentsEnum.LINPHONE_LOGIN : AssistantFragmentsEnum.WELCOME;
if (findViewById(R.id.fragment_container) != null) {
if (savedInstanceState == null) {
display(firstFragment);
} else {
currentFragment = (AssistantFragmentsEnum) savedInstanceState.getSerializable("CurrentFragment");
}
}
if(getIntent().getBooleanExtra("LinkPhoneNumber",false)){
isLink = true;
displayCreateAccount();
} else {
firstFragment = getResources().getBoolean(R.bool.assistant_use_linphone_login_as_first_fragment) ? AssistantFragmentsEnum.LINPHONE_LOGIN : AssistantFragmentsEnum.WELCOME;
if (findViewById(R.id.fragment_container) != null) {
if (savedInstanceState == null) {
display(firstFragment);
} else {
currentFragment = (AssistantFragmentsEnum) savedInstanceState.getSerializable("CurrentFragment");
}
}
}
if (savedInstanceState != null && savedInstanceState.containsKey("echoCanceller")) {
echoCancellerAlreadyDone = savedInstanceState.getBoolean("echoCanceller");
} else {
echoCancellerAlreadyDone = false;
}
mPrefs = LinphonePreferences.instance();
//if(mPrefs.isFirstLaunch()) {
status.enableSideMenu(false);
//}
status.enableSideMenu(false);
accountCreator = new LinphoneAccountCreatorImpl(LinphoneManager.getLc(), LinphonePreferences.instance().getXmlrpcUrl());
accountCreator.setDomain(getResources().getString(R.string.default_domain));
accountCreator.setListener(this);
mListener = new LinphoneCoreListenerBase() {
@Override
@ -122,7 +140,7 @@ private static AssistantActivity instance;
if (state == RegistrationState.RegistrationOk) {
if (progress != null) progress.dismiss();
if (LinphoneManager.getLc().getDefaultProxyConfig() != null) {
success();
accountCreator.isAccountUsed();
}
} else if (state == RegistrationState.RegistrationFailed) {
if (progress != null) progress.dismiss();
@ -189,10 +207,6 @@ private static AssistantActivity instance;
transaction.commitAllowingStateLoss();
}
public AssistantFragmentsEnum getCurrentFragment() {
return currentFragment;
}
@Override
public void onClick(View v) {
int id = v.getId();
@ -200,7 +214,7 @@ private static AssistantActivity instance;
if (id == R.id.assistant_cancel) {
hideKeyboard();
LinphonePreferences.instance().firstLaunchSuccessful();
if (getResources().getBoolean(R.bool.setup_cancel_move_to_back)) {
if (getResources().getBoolean(R.bool.assistant_cancel_move_to_back)) {
moveTaskToBack(true);
} else {
LinphonePreferences.instance().firstLaunchSuccessful();
@ -215,9 +229,12 @@ private static AssistantActivity instance;
@Override
public void onBackPressed() {
if(isLink){
return;
}
if (currentFragment == firstFragment) {
LinphonePreferences.instance().firstLaunchSuccessful();
if (getResources().getBoolean(R.bool.setup_cancel_move_to_back)) {
if (getResources().getBoolean(R.bool.assistant_cancel_move_to_back)) {
moveTaskToBack(true);
} else {
LinphonePreferences.instance().firstLaunchSuccessful();
@ -228,12 +245,15 @@ private static AssistantActivity instance;
|| currentFragment == AssistantFragmentsEnum.LINPHONE_LOGIN
|| currentFragment == AssistantFragmentsEnum.CREATE_ACCOUNT
|| currentFragment == AssistantFragmentsEnum.REMOTE_PROVISIONING) {
WelcomeFragment fragment = new WelcomeFragment();
changeFragment(fragment);
currentFragment = AssistantFragmentsEnum.WELCOME;
back.setVisibility(View.INVISIBLE);
displayMenu();
} else if (currentFragment == AssistantFragmentsEnum.WELCOME) {
finish();
} else if (currentFragment == AssistantFragmentsEnum.COUNTRY_CHOOSER){
if(lastFragment.equals(AssistantFragmentsEnum.LINPHONE_LOGIN)){
displayLoginLinphone();
} else {
displayCreateAccount();
}
}
}
@ -246,13 +266,17 @@ private static AssistantActivity instance;
}
public void checkAndRequestAudioPermission() {
int recordAudio = getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO, getPackageName());
Log.i("[Permission] Record audio permission is " + (recordAudio == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
checkAndRequestPermission(Manifest.permission.RECORD_AUDIO, 0);
}
if (recordAudio != PackageManager.PERMISSION_GRANTED) {
if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.RECORD_AUDIO) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
Log.i("[Permission] Asking for record audio");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, PERMISSIONS_REQUEST_RECORD_AUDIO);
public void checkAndRequestPermission(String permission, int result) {
int permissionGranted = getPackageManager().checkPermission(permission, getPackageName());
Log.i("[Permission] " + permission + " is " + (permissionGranted == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
if (permissionGranted != PackageManager.PERMISSION_GRANTED) {
if (LinphonePreferences.instance().firstTimeAskingForPermission(permission) || ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
Log.i("[Permission] Asking for " + permission);
ActivityCompat.requestPermissions(this, new String[]{permission}, result);
}
}
}
@ -269,8 +293,6 @@ private static AssistantActivity instance;
} else {
isEchoCalibrationFinished();
}
} else {
isEchoCalibrationFinished();
}
}
@ -290,31 +312,31 @@ private static AssistantActivity instance;
}
}
private void logIn(String username, String password, String displayName, String domain, TransportType transport, boolean sendEcCalibrationResult) {
saveCreatedAccount(username, password, displayName, domain, transport);
private void logIn(String username, String password, String ha1, String prefix, String domain, TransportType transport, boolean sendEcCalibrationResult) {
saveCreatedAccount(username, password, ha1, prefix, domain, transport);
}
public void checkAccount(String username, String password, String displayName, String domain) {
saveCreatedAccount(username, password, displayName, domain, null);
public void checkAccount(String username, String password, String prefix, String domain) {
saveCreatedAccount(username, password, null, prefix, domain, null);
}
public void linphoneLogIn(String username, String password, String displayName, boolean validate) {
public void linphoneLogIn(String username, String password, String ha1, String prefix, boolean validate) {
if (validate) {
checkAccount(username, password, displayName, getString(R.string.default_domain));
checkAccount(username, password, prefix, getString(R.string.default_domain));
} else {
if(accountCreated) {
retryLogin(username, password, displayName, getString(R.string.default_domain), null);
retryLogin(username, password, prefix, getString(R.string.default_domain), null);
} else {
logIn(username, password, displayName, getString(R.string.default_domain), null, true);
logIn(username, password, ha1, prefix, getString(R.string.default_domain), null, true);
}
}
}
public void genericLogIn(String username, String password, String displayName, String domain, TransportType transport) {
if(accountCreated) {
retryLogin(username, password, displayName, domain, transport);
public void genericLogIn(String username, String password, String prefix, String domain, TransportType transport) {
if (accountCreated) {
retryLogin(username, password, prefix, domain, transport);
} else {
logIn(username, password, displayName, domain, transport, false);
logIn(username, password, null, prefix, domain, transport, false);
}
}
@ -334,6 +356,7 @@ private static AssistantActivity instance;
public void displayMenu() {
fragment = new WelcomeFragment();
changeFragment(fragment);
country = null;
currentFragment = AssistantFragmentsEnum.WELCOME;
back.setVisibility(View.INVISIBLE);
}
@ -354,6 +377,9 @@ private static AssistantActivity instance;
public void displayCreateAccount() {
fragment = new CreateAccountFragment();
Bundle extra = new Bundle();
extra.putBoolean("LinkPhoneNumber", isLink);
fragment.setArguments(extra);
changeFragment(fragment);
currentFragment = AssistantFragmentsEnum.CREATE_ACCOUNT;
back.setVisibility(View.VISIBLE);
@ -366,14 +392,17 @@ private static AssistantActivity instance;
back.setVisibility(View.VISIBLE);
}
public void retryLogin(String username, String password, String displayName, String domain, TransportType transport) {
accountCreated = false;
saveCreatedAccount(username, password, displayName, domain, transport);
public void displayCountryChooser() {
fragment = new CountryListFragment();
changeFragment(fragment);
lastFragment = currentFragment;
currentFragment = AssistantFragmentsEnum.COUNTRY_CHOOSER;
back.setVisibility(View.VISIBLE);
}
public void loadLinphoneConfig(){
//LinphoneManager.getInstance().loadConfig();
//LinphoneManager.getInstance().restartLinphoneCore();
public void retryLogin(String username, String password, String prefix, String domain, TransportType transport) {
accountCreated = false;
saveCreatedAccount(username, password, null, prefix, domain, transport);
}
private void launchDownloadCodec() {
@ -396,7 +425,13 @@ private static AssistantActivity instance;
goToLinphoneActivity();
}
public void saveCreatedAccount(String username, String password, String displayName, String domain, TransportType transport) {
public String getPhoneWithCountry() {
if(country == null || phone_number == null) return "";
String phoneNumberWithCountry = country.dial_code + phone_number.replace("\\D", "");
return phoneNumberWithCountry;
}
public void saveCreatedAccount(String username, String password, String prefix, String ha1, String domain, TransportType transport) {
if (accountCreated)
return;
@ -410,17 +445,17 @@ private static AssistantActivity instance;
Log.e(e);
}
if(address != null && displayName != null && !displayName.equals("")){
address.setDisplayName(displayName);
}
boolean isMainAccountLinphoneDotOrg = domain.equals(getString(R.string.default_domain));
AccountBuilder builder = new AccountBuilder(LinphoneManager.getLc())
.setUsername(username)
.setDomain(domain)
.setDisplayName(displayName)
.setHa1(ha1)
.setPassword(password);
if(prefix != null){
builder.setPrefix(prefix);
}
if (isMainAccountLinphoneDotOrg) {
if (getResources().getBoolean(R.bool.disable_all_security_features_for_markets)) {
builder.setProxy(domain)
@ -440,9 +475,14 @@ private static AssistantActivity instance;
.setRealm("sip.linphone.org")
.setNoDefault(false);
mPrefs.enabledFriendlistSubscription(getResources().getBoolean(R.bool.use_friendlist_subscription));
mPrefs.setStunServer(getString(R.string.default_stun));
mPrefs.setIceEnabled(true);
accountCreator.setPassword(password);
accountCreator.setHa1(ha1);
accountCreator.setUsername(username);
} else {
String forcedProxy = "";
if (!TextUtils.isEmpty(forcedProxy)) {
@ -465,6 +505,8 @@ private static AssistantActivity instance;
}
}
try {
builder.saveNewAccount();
if(!newAccount) {
@ -513,6 +555,22 @@ private static AssistantActivity instance;
back.setVisibility(View.INVISIBLE);
}
public void displayAssistantCodeConfirm(String username, String phone, String dialcode, boolean recoverAccount) {
CreateAccountCodeActivationFragment fragment = new CreateAccountCodeActivationFragment();
newAccount = true;
Bundle extras = new Bundle();
extras.putString("Username", username);
extras.putString("Phone", phone);
extras.putString("Dialcode", dialcode);
extras.putBoolean("RecoverAccount", recoverAccount);
extras.putBoolean("LinkAccount", isLink);
fragment.setArguments(extras);
changeFragment(fragment);
currentFragment = AssistantFragmentsEnum.CREATE_ACCOUNT_CODE_ACTIVATION;
back.setVisibility(View.INVISIBLE);
}
public void isAccountVerified(String username) {
Toast.makeText(this, getString(R.string.assistant_account_validated), Toast.LENGTH_LONG).show();
launchEchoCancellerCalibration(true);
@ -569,4 +627,45 @@ private static AssistantActivity instance;
status.setLinphoneCoreListener();
}
}
@Override
public void onAccountCreatorIsAccountUsed(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
if(status.equals(LinphoneAccountCreator.Status.AccountExistWithAlias)){
success();
} else {
isLink = true;
displayCreateAccount();
}
}
@Override
public void onAccountCreatorAccountCreated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorAccountActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorAccountLinkedWithPhoneNumber(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorPhoneNumberLinkActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorIsAccountActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorPhoneAccountRecovered(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
}

View file

@ -24,7 +24,9 @@ public enum AssistantFragmentsEnum {
WELCOME,
CREATE_ACCOUNT,
CREATE_ACCOUNT_ACTIVATION,
CREATE_ACCOUNT_CODE_ACTIVATION,
LINPHONE_LOGIN,
COUNTRY_CHOOSER,
LOGIN,
REMOTE_PROVISIONING,
ECHO_CANCELLER_CALIBRATION,

View file

@ -0,0 +1,213 @@
package org.linphone.assistant;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.linphone.R;
import org.linphone.mediastream.Log;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class CountryListFragment extends Fragment implements AdapterView.OnItemClickListener, View.OnClickListener {
private LayoutInflater mInflater;
private ListView list;
private EditText search;
private ImageView clearSearchField;
private CountryListAdapter adapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mInflater = inflater;
View view = inflater.inflate(R.layout.assistant_country_list, container, false);
adapter = new CountryListAdapter(R.raw.countries, getActivity().getApplicationContext());
search = (EditText)view.findViewById(R.id.search_country);
clearSearchField = (ImageView) view.findViewById(R.id.clearSearchField);
clearSearchField.setOnClickListener(this);
list = (ListView)view.findViewById(R.id.countryList);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
search.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.getFilter().filter(s);
}
@Override
public void afterTextChanged(Editable s) {
}
});
return view;
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Country c = (Country)view.getTag();
AssistantActivity.instance().country = c;
AssistantActivity.instance().onBackPressed();
}
@Override
public void onClick(View v) {
if(v.getId() == R.id.clearSearchField) {
search.setText("");
}
}
/**
* This class represents a Country. There's a name, dial_code, code and max number of digits.
* It is constructed from a JSON object containing all these parameters.
*/
public class Country {
public String name;
public String dial_code;
public String code;
public int maxNum;
public Country(JSONObject obj ){
try {
name = obj.getString("name");
dial_code = obj.getString("dial_code");
code = obj.getString("code");
maxNum = obj.getInt("maxNum");
} catch (JSONException e){
e.printStackTrace();
}
}
}
/**
* This class reads a JSON file containing Country-specific phone number description,
* and allows to present them into a ListView
*/
private class CountryListAdapter extends BaseAdapter implements Filterable {
private List<Country> allCountries;
private List<Country> filteredCountries;
private Context context;
public CountryListAdapter(int jsonId, Context ctx) {
context = ctx;
allCountries = new ArrayList<Country>();
String jsonString = loadJSONFromAsset(R.raw.countries);
try {
JSONArray c = new JSONArray(jsonString);
for( int i = 0; i < c.length(); i++) {
allCountries.add(new Country(c.getJSONObject(i)));
}
filteredCountries = allCountries;
} catch (JSONException e){
e.printStackTrace();
}
}
public String loadJSONFromAsset(int id) {
String json = null;
try {
InputStream is = getResources().openRawResource(id);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
json = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return json;
}
@Override
public int getCount() {
return filteredCountries.size();
}
@Override
public Country getItem(int position) {
return filteredCountries.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent){
View view = null;
if (convertView != null) {
view = convertView;
} else {
view = mInflater.inflate(R.layout.country_cell, parent, false);
}
Country c = filteredCountries.get(position);
TextView name = (TextView) view.findViewById(R.id.country_name);
name.setText(c.name);
TextView dial_code = (TextView) view.findViewById(R.id.country_prefix);
dial_code.setText(String.format(getString(R.string.country_code),c.dial_code));
view.setTag(c);
return view;
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
ArrayList<Country> filteredCountries = new ArrayList<Country>();
for (Country c : allCountries) {
if (c.name.toLowerCase().contains(constraint) || c.dial_code.contains(constraint)){
filteredCountries.add(c);
}
}
FilterResults filterResults = new FilterResults();
filterResults.values = filteredCountries;
return filterResults;
}
@Override
@SuppressWarnings("unchecked")
protected void publishResults(CharSequence constraint, FilterResults results) {
filteredCountries = (List<Country>) results.values;
CountryListAdapter.this.notifyDataSetChanged();
}
};
}
}
}

View file

@ -18,6 +18,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import org.linphone.LinphoneManager;
import org.linphone.LinphonePreferences;
import org.linphone.R;
import org.linphone.core.LinphoneXmlRpcRequest;
import org.linphone.core.LinphoneXmlRpcRequest.LinphoneXmlRpcRequestListener;
@ -48,7 +49,7 @@ public class CreateAccountActivationFragment extends Fragment implements Linphon
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.assistant_account_creation_activation, container, false);
View view = inflater.inflate(R.layout.assistant_account_creation_email_activation, container, false);
username = getArguments().getString("Username");
password = getArguments().getString("Password");
@ -71,7 +72,7 @@ public class CreateAccountActivationFragment extends Fragment implements Linphon
runOk = new Runnable() {
public void run() {
checkAccount.setEnabled(true);
AssistantActivity.instance().saveCreatedAccount(username,password,null, getString(R.string.default_domain),null);
AssistantActivity.instance().saveCreatedAccount(username, password, null, null, getString(R.string.default_domain),null);
AssistantActivity.instance().isAccountVerified(username);
}
};
@ -81,7 +82,7 @@ public class CreateAccountActivationFragment extends Fragment implements Linphon
}
};
xmlRpcSession = new LinphoneXmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), getString(R.string.wizard_url));
xmlRpcSession = new LinphoneXmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), LinphonePreferences.instance().getXmlrpcUrl());
xmlRpcRequest = new LinphoneXmlRpcRequestImpl("check_account_validated", LinphoneXmlRpcRequest.ArgType.Int);
xmlRpcRequest.setListener(this);

View file

@ -0,0 +1,175 @@
package org.linphone.assistant;
/*
CreateAccountCodeActivationFragment.java
Copyright (C) 2015 Belledonne Communications, Grenoble, France
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
import android.app.Fragment;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import org.linphone.LinphoneManager;
import org.linphone.LinphonePreferences;
import org.linphone.R;
import org.linphone.core.LinphoneAccountCreator;
import org.linphone.mediastream.Log;
import org.linphone.core.LinphoneAccountCreatorImpl;
import static org.linphone.core.LinphoneAccountCreator.*;
public class CreateAccountCodeActivationFragment extends Fragment implements LinphoneAccountCreatorListener {
private String username, phone, dialcode, ha1;
private EditText code;
private boolean recoverAccount = false, linkAccount = false;
private int code_length;
private Button checkAccount;
private LinphoneAccountCreator accountCreator;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.assistant_account_creation_code_activation, container, false);
username = getArguments().getString("Username");
phone = getArguments().getString("Phone");
dialcode = getArguments().getString("Dialcode");
recoverAccount = getArguments().getBoolean("RecoverAccount");
linkAccount = getArguments().getBoolean("LinkAccount");
code_length = LinphonePreferences.instance().getCodeLength();
accountCreator = new LinphoneAccountCreatorImpl(LinphoneManager.getLc(), LinphonePreferences.instance().getXmlrpcUrl());
accountCreator.setDomain(getResources().getString(R.string.default_domain));
accountCreator.setListener(this);
accountCreator.setUsername(username);
accountCreator.setPhoneNumber(phone, dialcode);
code = (EditText) view.findViewById(R.id.assistant_code);
code.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
if(s.length() == code_length){
checkAccount.setEnabled(true);
} else {
checkAccount.setEnabled(false);
}
}
});
checkAccount = (Button) view.findViewById(R.id.assistant_check);
checkAccount.setEnabled(false);
checkAccount.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
checkAccount.setEnabled(false);
accountCreator.setActivationCode(code.getText().toString());
if(linkAccount){
linkAccount();
} else {
activateAccount();
}
}
});
return view;
}
private void linkAccount(){
accountCreator.setUsername(LinphonePreferences.instance().getAccountUsername(LinphonePreferences.instance().getDefaultAccountIndex()));
accountCreator.setHa1(LinphonePreferences.instance().getAccountHa1(LinphonePreferences.instance().getDefaultAccountIndex()));
accountCreator.activatePhoneNumberLink();
}
private void activateAccount() {
if(accountCreator.getUsername() == null){
accountCreator.setUsername(accountCreator.getPhoneNumber());
}
accountCreator.activateAccount();
}
@Override
public void onAccountCreatorIsAccountUsed(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorAccountCreated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorAccountActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
if (status.equals(Status.AccountActivated)) {
checkAccount.setEnabled(true);
if (accountCreator.getUsername() != null) {
AssistantActivity.instance().saveCreatedAccount(accountCreator.getUsername(), null , dialcode, accountCreator.getHa1(), getString(R.string.default_domain), null);
if(!recoverAccount){
AssistantActivity.instance().isAccountVerified(accountCreator.getUsername());
} else {
AssistantActivity.instance().finish();
}
} else {
AssistantActivity.instance().saveCreatedAccount(accountCreator.getPhoneNumber(), null, dialcode, accountCreator.getHa1(), getString(R.string.default_domain), null);
if(!recoverAccount) {
AssistantActivity.instance().isAccountVerified(accountCreator.getPhoneNumber());
} else {
AssistantActivity.instance().finish();
}
}
} else if (status.equals(LinphoneAccountCreator.Status.Failed)) {
Toast.makeText(getActivity(), getString(R.string.wizard_server_unavailable), Toast.LENGTH_LONG).show();
}else {
Toast.makeText(getActivity(), getString(R.string.assistant_error_confirmation_code), Toast.LENGTH_LONG).show();
}
}
@Override
public void onAccountCreatorAccountLinkedWithPhoneNumber(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorPhoneNumberLinkActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
if(status.equals(LinphoneAccountCreator.Status.Ok)){
LinphonePreferences.instance().setLinkPopupTime("");
AssistantActivity.instance().hideKeyboard();
AssistantActivity.instance().success();
}
}
@Override
public void onAccountCreatorIsAccountActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorPhoneAccountRecovered(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
}

View file

@ -17,26 +17,26 @@ 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 java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.linphone.LinphoneManager;
import org.linphone.LinphonePreferences;
import org.linphone.R;
import org.linphone.core.LinphoneAccountCreator;
import org.linphone.core.LinphoneAccountCreatorImpl;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.core.LinphoneXmlRpcRequest;
import org.linphone.core.LinphoneXmlRpcRequest.LinphoneXmlRpcRequestListener;
import org.linphone.core.LinphoneXmlRpcRequestImpl;
import org.linphone.core.LinphoneXmlRpcSession;
import org.linphone.core.LinphoneXmlRpcSessionImpl;
import org.linphone.mediastream.Log;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.AlertDialog;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Handler;
import android.telephony.TelephonyManager;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.Patterns;
import android.view.LayoutInflater;
@ -44,41 +44,71 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import static org.linphone.core.LinphoneAccountCreator.*;
/**
* @author Sylvain Berfini
*/
public class CreateAccountFragment extends Fragment {
private Handler mHandler = new Handler();
private EditText usernameEdit, passwordEdit, passwordConfirmEdit, emailEdit;
private TextView usernameError, passwordError, passwordConfirmError, emailError;
public class CreateAccountFragment extends Fragment implements CompoundButton.OnCheckedChangeListener, OnClickListener, LinphoneAccountCreatorListener {
private EditText phoneNumberEdit, usernameEdit, passwordEdit, passwordConfirmEdit, emailEdit, dialCode;
private TextView phoneNumberError, usernameError, passwordError, passwordConfirmError, emailError, assisstantTitle, sipUri, skip;
private ImageView phoneNumberInfo;
private boolean phoneNumberOk = false;
private boolean usernameOk = false;
private boolean passwordOk = false;
private boolean emailOk = false;
private boolean confirmPasswordOk = false;
private Button createAccount;
private boolean linkAccount = false;
private Button createAccount, selectCountry;
private CheckBox useUsername, useEmail;
private int countryCode;
private LinearLayout phoneNumberLayout, usernameLayout, emailLayout, passwordLayout, passwordConfirmLayout;
private final Pattern UPPER_CASE_REGEX = Pattern.compile("[A-Z]");
private LinphoneXmlRpcSession xmlRpcSession;
private String getUsername() {
String username = usernameEdit.getText().toString();
if (getResources().getBoolean(R.bool.allow_only_phone_numbers_in_wizard)) {
LinphoneProxyConfig lpc = LinphoneManager.getLc().createProxyConfig();
username = lpc.normalizePhoneNumber(username);
}
return username.toLowerCase(Locale.getDefault());
}
private CountryListFragment.Country country;
private LinphoneAccountCreator accountCreator;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.assistant_account_creation, container, false);
//Initialize accountCreator
accountCreator = new LinphoneAccountCreatorImpl(LinphoneManager.getLc(), LinphonePreferences.instance().getXmlrpcUrl());
accountCreator.setDomain(getResources().getString(R.string.default_domain));
accountCreator.setListener(this);
createAccount = (Button) view.findViewById(R.id.assistant_create);
phoneNumberLayout = (LinearLayout) view.findViewById(R.id.phone_number_layout);
usernameLayout = (LinearLayout) view.findViewById(R.id.username_layout);
emailLayout = (LinearLayout) view.findViewById(R.id.email_layout);
passwordLayout = (LinearLayout) view.findViewById(R.id.password_layout);
passwordConfirmLayout = (LinearLayout) view.findViewById(R.id.password_confirm_layout);
useUsername = (CheckBox) view.findViewById(R.id.use_username);
useEmail = (CheckBox) view.findViewById(R.id.use_email);
usernameError = (TextView) view.findViewById(R.id.username_error);
usernameEdit = (EditText) view.findViewById(R.id.username);
phoneNumberError = (TextView) view.findViewById(R.id.phone_number_error);
phoneNumberEdit = (EditText) view.findViewById(R.id.phone_number);
sipUri = (TextView) view.findViewById(R.id.sip_uri);
phoneNumberInfo = (ImageView) view.findViewById(R.id.info_phone_number);
selectCountry = (Button) view.findViewById(R.id.select_country);
dialCode = (EditText) view.findViewById(R.id.dial_code);
assisstantTitle = (TextView) view.findViewById(R.id.assistant_title);
passwordError = (TextView) view.findViewById(R.id.password_error);
passwordEdit = (EditText) view.findViewById(R.id.password);
@ -88,42 +118,207 @@ public class CreateAccountFragment extends Fragment {
emailError = (TextView) view.findViewById(R.id.email_error);
emailEdit = (EditText) view.findViewById(R.id.email);
addXMLRPCUsernameHandler(usernameEdit, null);
skip = (TextView) view.findViewById(R.id.assistant_skip);
if (getResources().getBoolean(R.bool.allow_only_phone_numbers_in_wizard)) {
usernameEdit.setInputType(InputType.TYPE_CLASS_NUMBER);
}
//Phone number
if(getResources().getBoolean(R.bool.use_phone_number_validation)){
//Automatically get the country code from the phone
TelephonyManager tm = (TelephonyManager) getActivity().getApplicationContext().getSystemService(getActivity().getApplicationContext().TELEPHONY_SERVICE);
String countryIso = tm.getNetworkCountryIso();
LinphoneProxyConfig proxyConfig = LinphoneManager.getLc().createProxyConfig();
countryCode = proxyConfig.lookupCCCFromIso(countryIso.toUpperCase());
addXMLRPCPasswordHandler(passwordEdit, null);
addXMLRPCConfirmPasswordHandler(passwordEdit, passwordConfirmEdit, null);
addXMLRPCEmailHandler(emailEdit, null);
phoneNumberLayout.setVisibility(View.VISIBLE);
createAccount = (Button) view.findViewById(R.id.assistant_create);
createAccount.setEnabled(false);
createAccount.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
createAccount(getUsername(), passwordEdit.getText().toString(), emailEdit.getText().toString(), false);
phoneNumberInfo.setOnClickListener(this);
addPhoneNumberHandler(phoneNumberEdit, null);
addPhoneNumberHandler(dialCode, null);
selectCountry.setOnClickListener(this);
String previousPhone = AssistantActivity.instance().phone_number;
if(previousPhone != null ){
phoneNumberEdit.setText(previousPhone);
}
});
setCountry(AssistantActivity.instance().country);
if (getResources().getBoolean(R.bool.pre_fill_email_in_wizard)) {
Account[] accounts = AccountManager.get(getActivity()).getAccountsByType("com.google");
//Allow user to enter a username instead use the phone number as username
if(getResources().getBoolean(R.bool.assistant_allow_username) ) {
useUsername.setVisibility(View.VISIBLE);
useUsername.setEnabled(false);
useUsername.setOnCheckedChangeListener(this);
}
}
for (Account account: accounts) {
if (isEmailCorrect(account.name)) {
String possibleEmail = account.name;
emailEdit.setText(possibleEmail);
emailOk = true;
break;
}
}
}
//Password & email address
if (getResources().getBoolean(R.bool.isTablet) || !getResources().getBoolean(R.bool.use_phone_number_validation)){
useEmail.setVisibility(View.VISIBLE);
useEmail.setOnCheckedChangeListener(this);
xmlRpcSession = new LinphoneXmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), getString(R.string.wizard_url));
addPasswordHandler(passwordEdit, null);
addConfirmPasswordHandler(passwordEdit, passwordConfirmEdit, null);
addEmailHandler(emailEdit, null);
if (getResources().getBoolean(R.bool.pre_fill_email_in_assistant)) {
Account[] accounts = AccountManager.get(getActivity()).getAccountsByType("com.google");
for (Account account: accounts) {
if (isEmailCorrect(account.name)) {
String possibleEmail = account.name;
emailEdit.setText(possibleEmail);
accountCreator.setEmail(possibleEmail);
emailOk = true;
break;
}
}
}
}
//Hide phone number and display username/email/password
if(!getResources().getBoolean(R.bool.use_phone_number_validation)){
useEmail.setVisibility(View.GONE);
useUsername.setVisibility(View.GONE);
usernameLayout.setVisibility(View.VISIBLE);
passwordLayout.setVisibility(View.VISIBLE);
passwordConfirmLayout.setVisibility(View.VISIBLE);
emailLayout.setVisibility(View.VISIBLE);
}
//Link account with phone number
if(getArguments().getBoolean("LinkPhoneNumber")){
linkAccount = true;
useEmail.setVisibility(View.GONE);
useUsername.setVisibility(View.GONE);
usernameLayout.setVisibility(View.GONE);
passwordLayout.setVisibility(View.GONE);
passwordConfirmLayout.setVisibility(View.GONE);
emailLayout.setVisibility(View.GONE);
skip.setVisibility(View.VISIBLE);
skip.setOnClickListener(this);
createAccount.setText(getResources().getString(R.string.link_account));
assisstantTitle.setText(getResources().getString(R.string.link_account));
}
addUsernameHandler(usernameEdit, null);
createAccount.setEnabled(false);
createAccount.setOnClickListener(this);
return view;
}
@Override
public void onPause() {
super.onPause();
accountCreator.setListener(null);
}
private String getUsername() {
if(usernameEdit != null) {
String username = usernameEdit.getText().toString();
return username.toLowerCase(Locale.getDefault());
}
return null;
}
private String getCountryCode() {
if(dialCode != null) {
String code = dialCode.getText().toString();
if(code != null && code.startsWith("+")) {
code = code.substring(1);
}
return code;
}
return null;
}
public void setCountry(CountryListFragment.Country c) {
country = c;
if( c!= null) {
dialCode.setText(c.dial_code);
selectCountry.setText(c.name);
} else {
if(countryCode != -1){
dialCode.setText("+" + countryCode);
} else {
dialCode.setText("+");
}
}
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(buttonView.getId() == R.id.use_username) {
if(isChecked) {
usernameLayout.setVisibility(View.VISIBLE);
if(getResources().getBoolean(R.bool.isTablet)){
passwordLayout.setVisibility(View.INVISIBLE);
}
} else {
usernameLayout.setVisibility(View.GONE);
accountCreator.setUsername(null);
}
} else if(buttonView.getId() == R.id.use_email){
if(isChecked) {
emailLayout.setVisibility(View.VISIBLE);
passwordLayout.setVisibility(View.VISIBLE);
passwordConfirmLayout.setVisibility(View.VISIBLE);
usernameLayout.setVisibility(View.VISIBLE);
useUsername.setEnabled(false);
} else {
if(!useUsername.isChecked()) {
usernameLayout.setVisibility(View.GONE);
}
emailLayout.setVisibility(View.GONE);
passwordLayout.setVisibility(View.GONE);
passwordConfirmLayout.setVisibility(View.GONE);
usernameLayout.setVisibility(View.GONE);
useUsername.setEnabled(true);
}
}
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.select_country: {
AssistantActivity.instance().displayCountryChooser();
break;
}
case R.id.assistant_skip: {
AssistantActivity.instance().success();
break;
}
case R.id.info_phone_number: {
if(linkAccount){
new AlertDialog.Builder(getActivity())
.setTitle(getString(R.string.phone_number_info_title))
.setMessage(getString(R.string.phone_number_link_info_content))
.show();
} else {
new AlertDialog.Builder(getActivity())
.setTitle(getString(R.string.phone_number_info_title))
.setMessage(getString(R.string.phone_number_info_content))
.show();
}
break;
}
case R.id.assistant_create: {
if(linkAccount){
addAlias();
} else {
createAccount();
}
break;
}
}
}
private void displayError(Boolean isOk, TextView error, EditText editText, String errorText){
if(isOk || editText.getText().toString().equals("")){
error.setVisibility(View.INVISIBLE);
@ -136,58 +331,6 @@ public class CreateAccountFragment extends Fragment {
}
}
private boolean isUsernameCorrect(String username) {
if (getResources().getBoolean(R.bool.allow_only_phone_numbers_in_wizard)) {
LinphoneProxyConfig lpc = LinphoneManager.getLc().createProxyConfig();
return lpc.isPhoneNumber(username);
} else {
return username.matches("^[a-z]+[a-z0-9.\\-_]{2,}$");
}
}
private void isUsernameRegistred(final String username, final ImageView icon) {
final Runnable runNotOk = new Runnable() {
public void run() {
usernameOk = false;
displayError(usernameOk, usernameError, usernameEdit, LinphoneManager.getInstance().getContext().getString(R.string.wizard_username_unavailable));
createAccount.setEnabled(usernameOk && passwordOk && confirmPasswordOk && emailOk);
}
};
final Runnable runOk = new Runnable() {
public void run() {
usernameOk = true;
displayError(usernameOk, usernameError, usernameEdit, "");
createAccount.setEnabled(usernameOk && passwordOk && confirmPasswordOk && emailOk);
}
};
final Runnable runNotReachable = new Runnable() {
public void run() {
usernameOk = false;
displayError(usernameOk, usernameError, usernameEdit, LinphoneManager.getInstance().getContext().getString(R.string.wizard_server_unavailable));
createAccount.setEnabled(usernameOk && passwordOk && confirmPasswordOk && emailOk);
}
};
LinphoneXmlRpcRequest xmlRpcRequest = new LinphoneXmlRpcRequestImpl("check_account", LinphoneXmlRpcRequest.ArgType.Int);
xmlRpcRequest.setListener(new LinphoneXmlRpcRequestListener() {
@Override
public void onXmlRpcRequestResponse(LinphoneXmlRpcRequest request) {
if (request.getStatus() == LinphoneXmlRpcRequest.Status.Ok) {
int response = request.getIntResponse();
if (response != 0) {
mHandler.post(runNotOk);
} else {
mHandler.post(runOk);
}
} else if (request.getStatus() == LinphoneXmlRpcRequest.Status.Failed) {
mHandler.post(runNotReachable);
}
}
});
xmlRpcRequest.addStringArg(username);
xmlRpcSession.sendRequest(xmlRpcRequest);
}
private boolean isEmailCorrect(String email) {
Pattern emailPattern = Patterns.EMAIL_ADDRESS;
return emailPattern.matcher(email).matches();
@ -197,47 +340,54 @@ public class CreateAccountFragment extends Fragment {
return password.length() >= 1;
}
private void createAccount(final String username, final String password, String email, boolean suscribe) {
final Runnable runNotOk = new Runnable() {
public void run() {
//TODO errorMessage.setText(R.string.wizard_failed);
}
};
final Runnable runOk = new Runnable() {
public void run() {
AssistantActivity.instance().displayAssistantConfirm(username, password);
}
};
final Runnable runNotReachable = new Runnable() {
public void run() {
//TODO errorMessage.setText(R.string.wizard_not_reachable);
}
};
private void addAlias() {
accountCreator.setUsername(LinphonePreferences.instance().getAccountUsername(LinphonePreferences.instance().getDefaultAccountIndex()));
String countryCode = dialCode.getText().toString();
if(countryCode != null && countryCode.startsWith("+")) {
countryCode = countryCode.substring(1);
}
Status status = accountCreator.setPhoneNumber(phoneNumberEdit.getText().toString(), getCountryCode());
if(status.equals(Status.Ok)){
accountCreator.linkPhoneNumberWithAccount();
}
}
LinphoneXmlRpcRequest xmlRpcRequest = new LinphoneXmlRpcRequestImpl("create_account_with_useragent", LinphoneXmlRpcRequest.ArgType.Int);
xmlRpcRequest.setListener(new LinphoneXmlRpcRequestListener() {
@Override
public void onXmlRpcRequestResponse(LinphoneXmlRpcRequest request) {
if (request.getStatus() == LinphoneXmlRpcRequest.Status.Ok) {
int response = request.getIntResponse();
if (response != 0) {
mHandler.post(runNotOk);
private void createAccount() {
if(accountCreator.getUsername() == null && !useUsername.isChecked()){
accountCreator.setUsername(accountCreator.getPhoneNumber());
}
accountCreator.createAccount();
}
private void addPhoneNumberHandler(final EditText field, final ImageView icon) {
field.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
public void onTextChanged(CharSequence s, int start, int count, int after) {
if (s.length() > 0) {
phoneNumberOk = false;
Status status = accountCreator.setPhoneNumber(phoneNumberEdit.getText().toString(), getCountryCode());
if(status.equals(Status.Ok)){
if(useUsername.isChecked()){
accountCreator.setUsername(usernameEdit.getText().toString());
}
accountCreator.isAccountUsed();
} else {
mHandler.post(runOk);
useUsername.setEnabled(phoneNumberOk);
displayError(phoneNumberOk, phoneNumberError, phoneNumberEdit, errorForStatus(status));
sipUri.setText("");
}
} else if (request.getStatus() == LinphoneXmlRpcRequest.Status.Failed) {
mHandler.post(runNotReachable);
} else {
useUsername.setEnabled(phoneNumberOk);
displayError(phoneNumberOk, phoneNumberError, phoneNumberEdit, "");
}
}
});
xmlRpcRequest.addStringArg(username);
xmlRpcRequest.addStringArg(password);
xmlRpcRequest.addStringArg(email);
xmlRpcRequest.addStringArg(LinphoneManager.getInstance().getUserAgent());
xmlRpcSession.sendRequest(xmlRpcRequest);
}
private void addXMLRPCUsernameHandler(final EditText field, final ImageView icon) {
private void addUsernameHandler(final EditText field, final ImageView icon) {
field.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
Matcher matcher = UPPER_CASE_REGEX.matcher(s);
@ -252,121 +402,223 @@ public class CreateAccountFragment extends Fragment {
}
public void onTextChanged(CharSequence s, int start, int count, int after) {
field.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(!hasFocus){
usernameOk = false;
String username = field.getText().toString();
if (isUsernameCorrect(username)) {
if (getResources().getBoolean(R.bool.allow_only_phone_numbers_in_wizard)) {
LinphoneProxyConfig lpc = LinphoneManager.getLc().createProxyConfig();
username = lpc.normalizePhoneNumber(username);
}
isUsernameRegistred(username, icon);
} else {
displayError(usernameOk, usernameError, usernameEdit, getResources().getString(R.string.wizard_username_incorrect));
}
} else {
displayError(true, usernameError, usernameEdit, "");
}
if(s.length() > 0){
usernameOk = false;
Status status = accountCreator.setUsername(field.getText().toString());
if(status.equals(Status.Ok)){
accountCreator.isAccountUsed();
} else {
displayError(usernameOk, usernameError, usernameEdit, errorForStatus(status));
sipUri.setText("");
}
});
} else {
displayError(true, usernameError, usernameEdit, "");
}
}
});
}
private void addXMLRPCEmailHandler(final EditText field, final ImageView icon) {
private void addEmailHandler(final EditText field, final ImageView icon) {
field.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int count, int after)
{
emailOk = false;
if (isEmailCorrect(field.getText().toString())) {
Status status = accountCreator.setEmail(field.getText().toString());
if (status.equals(Status.Ok)) {
emailOk = true;
displayError(emailOk, emailError, emailEdit, "");
}
else {
displayError(emailOk, emailError, emailEdit, getString(R.string.wizard_email_incorrect));
displayError(emailOk, emailError, emailEdit, errorForStatus(status));
}
createAccount.setEnabled(usernameOk && passwordOk && confirmPasswordOk && emailOk);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int count, int after) {
}
});
}
private void addXMLRPCPasswordHandler(final EditText field1, final ImageView icon) {
private void addPasswordHandler(final EditText field1, final ImageView icon) {
TextWatcher passwordListener = new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int count, int after)
{
passwordOk = false;
Status status = accountCreator.setPassword(field1.getText().toString());
if (isPasswordCorrect(field1.getText().toString())) {
passwordOk = true;
displayError(passwordOk, passwordError, passwordEdit, "");
}
else {
displayError(passwordOk, passwordError, passwordEdit, getString(R.string.wizard_password_incorrect));
displayError(passwordOk, passwordError, passwordEdit, errorForStatus(status));
}
createAccount.setEnabled(usernameOk && passwordOk && confirmPasswordOk && emailOk);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int count, int after) {
}
};
field1.addTextChangedListener(passwordListener);
}
private void addXMLRPCConfirmPasswordHandler(final EditText field1, final EditText field2, final ImageView icon) {
private void addConfirmPasswordHandler(final EditText field1, final EditText field2, final ImageView icon) {
TextWatcher passwordListener = new TextWatcher() {
public void afterTextChanged(Editable s) {
confirmPasswordOk = false;
if (field1.getText().toString().equals(field2.getText().toString())) {
confirmPasswordOk = true;
if (!isPasswordCorrect(field1.getText().toString())) {
displayError(passwordOk, passwordError, passwordEdit, getString(R.string.wizard_password_incorrect));
} else {
displayError(confirmPasswordOk, passwordConfirmError, passwordConfirmEdit, "");
}
} else {
displayError(confirmPasswordOk, passwordConfirmError, passwordConfirmEdit, getString(R.string.wizard_passwords_unmatched));
}
createAccount.setEnabled(usernameOk && passwordOk && confirmPasswordOk && emailOk);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int count, int after)
{
field2.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
confirmPasswordOk = false;
if (field1.getText().toString().equals(field2.getText().toString())) {
confirmPasswordOk = true;
if (!isPasswordCorrect(field1.getText().toString())) {
displayError(passwordOk, passwordError, passwordEdit, getString(R.string.wizard_password_incorrect));
} else {
displayError(confirmPasswordOk, passwordConfirmError, passwordConfirmEdit, "");
}
} else {
displayError(confirmPasswordOk, passwordConfirmError, passwordConfirmEdit, getString(R.string.wizard_passwords_unmatched));
}
createAccount.setEnabled(usernameOk && passwordOk && confirmPasswordOk && emailOk);
} else {
displayError(true, passwordConfirmError, passwordConfirmEdit, "");
}
}
});
}
public void onTextChanged(CharSequence s, int start, int count, int after) {}
};
field1.addTextChangedListener(passwordListener);
field2.addTextChangedListener(passwordListener);
}
String errorForStatus(Status status) {
if (status.equals(Status.EmailInvalid))
return getString(R.string.invalid_email);
if (status.equals(Status.UsernameInvalid)){
return getString(R.string.invalid_username);
}
if (status.equals(Status.UsernameTooShort)){
return getString(R.string.username_too_short);
}
if (status.equals(Status.UsernameTooLong)){
return getString(R.string.username_too_long);
}
if (status.equals(Status.UsernameInvalidSize))
return getString(R.string.username_invalid_size);
if (status.equals(Status.PhoneNumberTooShort))
return getString(R.string.phone_number_too_short);
if (status.equals(Status.PhoneNumberTooLong))
return getString(R.string.phone_number_too_long);
if (status.equals(Status.PhoneNumberInvalid))
return getString(R.string.phone_number_invalid);
if (status.equals(Status.PasswordTooShort))
return getString(R.string.username_too_short);
if (status.equals(Status.PasswordTooLong))
return getString(R.string.username_too_long);
if (status.equals(Status.DomainInvalid))
return getString(R.string.invalid_domain);
if (status.equals(Status.RouteInvalid))
return getString(R.string.invalid_route);
if (status.equals(Status.DisplayNameInvalid))
return getString(R.string.invalid_route);
if (status.equals(Status.Failed))
return getString(R.string.request_failed);
if (status.equals(Status.TransportNotSupported))
return getString(R.string.transport_unsupported);
if (status.equals(Status.AccountExist))
return getString(R.string.account_already_exist);
if (status.equals(Status.AccountExistWithAlias))
return getString(R.string.account_already_exist);
if (status.equals(Status.AccountCreated)
|| status.equals(Status.AccountNotCreated)
|| status.equals(Status.AccountNotExist)
|| status.equals(Status.AccountNotActivated)
|| status.equals(Status.AccountAlreadyActivated)
|| status.equals(Status.AccountActivated)
|| status.equals(Status.Ok)){
return "";
}
return null;
}
@Override
public void onAccountCreatorIsAccountUsed(LinphoneAccountCreator accountCreator, final Status status) {
if(getResources().getBoolean(R.bool.isTablet) || useEmail.isChecked() || !getResources().getBoolean(R.bool.use_phone_number_validation)){
if (status.equals(Status.AccountExist) || status.equals(Status.AccountExistWithAlias)) {
usernameOk = false;
displayError(usernameOk, usernameError, usernameEdit, errorForStatus(status));
sipUri.setText("");
} else {
usernameOk = true;
displayError(usernameOk, usernameError, usernameEdit, errorForStatus(status));
sipUri.setText("Sip uri is sip:" + accountCreator.getUsername() + "@" + getResources().getString(R.string.default_domain));
}
createAccount.setEnabled(usernameOk && emailOk);
}
if(getResources().getBoolean(R.bool.assistant_allow_username) && useUsername.isChecked()){
if (status.equals(Status.AccountExist) || status.equals(Status.AccountExistWithAlias)) {
usernameOk = false;
displayError(usernameOk, usernameError, usernameEdit, errorForStatus(status));
sipUri.setText("");
} else {
usernameOk = true;
displayError(usernameOk, usernameError, usernameEdit, errorForStatus(status));
sipUri.setText("Sip uri is sip:" + accountCreator.getUsername() + "@" + getResources().getString(R.string.default_domain));
}
createAccount.setEnabled(usernameOk && phoneNumberOk);
} else {
if (status.equals(Status.AccountExist) || status.equals(Status.AccountExistWithAlias)) {
phoneNumberOk = false;
displayError(phoneNumberOk, phoneNumberError, phoneNumberEdit, errorForStatus(status));
sipUri.setText("");
} else {
phoneNumberOk = true;
displayError(phoneNumberOk, phoneNumberError, phoneNumberEdit, errorForStatus(status));
sipUri.setText("Sip uri is sip:" + accountCreator.getPhoneNumber() + "@" + getResources().getString(R.string.default_domain));
}
createAccount.setEnabled(phoneNumberOk);
useUsername.setEnabled(phoneNumberOk);
}
}
@Override
public void onAccountCreatorAccountCreated(LinphoneAccountCreator accountCreator, Status status) {
if(status.equals(Status.AccountCreated)) {
if(useEmail.isChecked() || !getResources().getBoolean(R.bool.use_phone_number_validation)){
AssistantActivity.instance().displayAssistantConfirm(getUsername(), passwordEdit.getText().toString());
} else {
AssistantActivity.instance().displayAssistantCodeConfirm(getUsername(), phoneNumberEdit.getText().toString(), getCountryCode(), false);
}
} else {
Toast.makeText(getActivity().getApplicationContext(), errorForStatus(status), Toast.LENGTH_SHORT);
}
}
@Override
public void onAccountCreatorAccountActivated(LinphoneAccountCreator accountCreator, Status status) {
}
@Override
public void onAccountCreatorAccountLinkedWithPhoneNumber(LinphoneAccountCreator accountCreator, Status status) {
if(status.equals(Status.Ok)){
AssistantActivity.instance().displayAssistantCodeConfirm(getUsername(), phoneNumberEdit.getText().toString(), getCountryCode(), false);
}
}
@Override
public void onAccountCreatorPhoneNumberLinkActivated(LinphoneAccountCreator accountCreator, Status status) {
if(status.equals(Status.Ok)){
AssistantActivity.instance().displayAssistantCodeConfirm(getUsername(), phoneNumberEdit.getText().toString(), getCountryCode(), false);
}
}
@Override
public void onAccountCreatorIsAccountActivated(LinphoneAccountCreator accountCreator, Status status) {
}
@Override
public void onAccountCreatorPhoneAccountRecovered(LinphoneAccountCreator accountCreator, Status status) {
}
}

View file

@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import org.linphone.LinphoneManager;
import org.linphone.LinphonePreferences;
import org.linphone.R;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
@ -73,7 +74,7 @@ public class EchoCancellerCalibrationFragment extends Fragment implements Linpho
}
};
xmlRpcSession = new LinphoneXmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), getString(R.string.wizard_url));
xmlRpcSession = new LinphoneXmlRpcSessionImpl(LinphoneManager.getLcIfManagerNotDestroyedOrNull(), LinphonePreferences.instance().getXmlrpcUrl());
xmlRpcRequest = new LinphoneXmlRpcRequestImpl("add_ec_calibration_result", LinphoneXmlRpcRequest.ArgType.None);
xmlRpcRequest.setListener(this);

View file

@ -17,11 +17,18 @@ 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 org.linphone.LinphoneManager;
import org.linphone.LinphonePreferences;
import org.linphone.R;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.LinphoneAccountCreator;
import org.linphone.core.LinphoneAccountCreatorImpl;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.mediastream.Log;
import android.app.Fragment;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
@ -30,32 +37,96 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
/**
* @author Sylvain Berfini
*/
public class LinphoneLoginFragment extends Fragment implements OnClickListener, TextWatcher {
private EditText login, password, displayName;
private Button apply;
public class LinphoneLoginFragment extends Fragment implements CompoundButton.OnCheckedChangeListener, OnClickListener, TextWatcher, LinphoneAccountCreator.LinphoneAccountCreatorListener {
private EditText login, password, phoneNumberEdit, dialCode, displayName;
private Button apply, selectCountry;
private CheckBox useUsername, usePassword;
private LinearLayout phoneNumberLayout, usernameLayout, passwordLayout;
private TextView forgotPassword;
private CountryListFragment.Country country;
private Boolean recoverAccount = false;
private LinphoneAccountCreator accountCreator;
private int countryCode;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.assistant_linphone_login, container, false);
accountCreator = new LinphoneAccountCreatorImpl(LinphoneManager.getLc(), LinphonePreferences.instance().getXmlrpcUrl());
accountCreator.setListener(this);
String url = "http://linphone.org/free-sip-service.html&action=recover";
login = (EditText) view.findViewById(R.id.assistant_username);
login.addTextChangedListener(this);
dialCode = (EditText) view.findViewById(R.id.dial_code);
phoneNumberEdit = (EditText) view.findViewById(R.id.phone_number);
phoneNumberLayout = (LinearLayout) view.findViewById(R.id.phone_number_layout);
addPhoneNumberHandler(phoneNumberEdit, null);
useUsername = (CheckBox) view.findViewById(R.id.use_username);
usernameLayout = (LinearLayout) view.findViewById(R.id.username_layout);
passwordLayout = (LinearLayout) view.findViewById(R.id.password_layout);
password = (EditText) view.findViewById(R.id.assistant_password);
password.addTextChangedListener(this);
forgotPassword = (TextView) view.findViewById(R.id.forgot_password);
forgotPassword.setText(Compatibility.fromHtml("<a href=\"" + url + "\"'>"+ getString(R.string.forgot_password) + "</a>"));
forgotPassword.setMovementMethod(LinkMovementMethod.getInstance());
displayName = (EditText) view.findViewById(R.id.assistant_display_name);
forgotPassword = (TextView) view.findViewById(R.id.forgot_password);
selectCountry = (Button) view.findViewById(R.id.select_country);
//Phone number
if(getResources().getBoolean(R.bool.use_phone_number_validation)){
//Automatically get the country code from the phone
TelephonyManager tm = (TelephonyManager) getActivity().getApplicationContext().getSystemService(getActivity().getApplicationContext().TELEPHONY_SERVICE);
String countryIso = tm.getNetworkCountryIso();
LinphoneProxyConfig proxyConfig = LinphoneManager.getLc().createProxyConfig();
countryCode = proxyConfig.lookupCCCFromIso(countryIso.toUpperCase());
phoneNumberLayout.setVisibility(View.VISIBLE);
selectCountry.setOnClickListener(this);
String previousPhone = AssistantActivity.instance().phone_number;
if(previousPhone != null ){
phoneNumberEdit.setText(previousPhone);
}
setCountry(AssistantActivity.instance().country);
//Allow user to enter a username instead use the phone number as username
if(getResources().getBoolean(R.bool.assistant_allow_username) ) {
useUsername.setVisibility(View.VISIBLE);
useUsername.setOnCheckedChangeListener(this);
}
}
if(getResources().getBoolean(R.bool.assistant_allow_username)) {
useUsername.setVisibility(View.VISIBLE);
useUsername.setOnCheckedChangeListener(this);
password.addTextChangedListener(this);
forgotPassword.setText(Compatibility.fromHtml("<a href=\"" + url + "\"'>" + getString(R.string.forgot_password) + "</a>"));
forgotPassword.setMovementMethod(LinkMovementMethod.getInstance());
}
//Hide phone number and display username/email/password
if(!getResources().getBoolean(R.bool.use_phone_number_validation)){
phoneNumberLayout.setVisibility(View.GONE);
useUsername.setVisibility(View.GONE);
usernameLayout.setVisibility(View.VISIBLE);
passwordLayout.setVisibility(View.VISIBLE);
}
apply = (Button) view.findViewById(R.id.assistant_apply);
apply.setEnabled(false);
apply.setOnClickListener(this);
@ -63,13 +134,79 @@ public class LinphoneLoginFragment extends Fragment implements OnClickListener,
return view;
}
private String getCountryCode() {
if(dialCode != null) {
String code = dialCode.getText().toString();
if(code != null && code.startsWith("+")) {
code = code.substring(1);
}
return code;
}
return null;
}
public void setCountry(CountryListFragment.Country c) {
country = c;
if( c!= null) {
dialCode.setText(c.dial_code);
selectCountry.setText(c.name);
} else {
if(countryCode != -1){
dialCode.setText("+" + countryCode);
} else {
dialCode.setText("+");
}
}
}
private String getPhoneNumber(){
LinphoneProxyConfig proxyConfig = LinphoneManager.getLc().createProxyConfig();
String countryCode = dialCode.getText().toString();
if(countryCode != null && countryCode.startsWith("+")) {
countryCode = countryCode.substring(1);
}
proxyConfig.setDialPrefix(countryCode);
return proxyConfig.normalizePhoneNumber(phoneNumberEdit.getText().toString());
}
public void linphoneLogIn() {
if (login.getText() == null || login.length() == 0 || password.getText() == null || password.length() == 0) {
Toast.makeText(getActivity(), getString(R.string.first_launch_no_login_password), Toast.LENGTH_LONG).show();
return;
}
AssistantActivity.instance().linphoneLogIn(login.getText().toString(), password.getText().toString(), null, null, getResources().getBoolean(R.bool.assistant_account_validation_mandatory));
}
AssistantActivity.instance().linphoneLogIn(login.getText().toString(), password.getText().toString(), displayName.getText().toString(), getResources().getBoolean(R.bool.setup_account_validation_mandatory));
private void addPhoneNumberHandler(final EditText field, final ImageView icon) {
field.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
//phoneNumberOk = false;
String countryCode = dialCode.getText().toString();
if (countryCode != null && countryCode.startsWith("+")) {
countryCode = countryCode.substring(1);
}
LinphoneAccountCreator.Status status = accountCreator.setPhoneNumber(phoneNumberEdit.getText().toString(), countryCode);
if (status.equals(LinphoneAccountCreator.Status.Ok)) {
status = accountCreator.isAccountUsed();
if (status.equals(LinphoneAccountCreator.Status.Ok)) {
recoverAccount = true;
}
} else {
//displayError(phoneNumberOk, phoneNumberError, phoneNumberEdit, errorForStatus(status));
}
} else {
//displayError(phoneNumberOk, phoneNumberError, phoneNumberEdit, "");
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int count, int after) {
}
});
}
@Override
@ -77,8 +214,19 @@ public class LinphoneLoginFragment extends Fragment implements OnClickListener,
int id = v.getId();
if (id == R.id.assistant_apply) {
linphoneLogIn();
if(recoverAccount){
recoverAccount();
} else {
linphoneLogIn();
}
}
if (id == R.id.select_country) {
AssistantActivity.instance().displayCountryChooser();
}
}
private void recoverAccount() {
accountCreator.recoverPhoneAccount();
}
@Override
@ -91,4 +239,53 @@ public class LinphoneLoginFragment extends Fragment implements OnClickListener,
@Override
public void afterTextChanged(Editable s) {}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(buttonView.getId() == R.id.use_username) {
if(isChecked) {
usernameLayout.setVisibility(View.VISIBLE);
passwordLayout.setVisibility(View.VISIBLE);
recoverAccount = false;
} else {
usernameLayout.setVisibility(View.GONE);
passwordLayout.setVisibility(View.INVISIBLE);
}
}
}
@Override
public void onAccountCreatorIsAccountUsed(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
apply.setEnabled(true);
}
@Override
public void onAccountCreatorAccountCreated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorAccountActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorAccountLinkedWithPhoneNumber(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorPhoneNumberLinkActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
}
@Override
public void onAccountCreatorIsAccountActivated(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
apply.setEnabled(true);
}
@Override
public void onAccountCreatorPhoneAccountRecovered(LinphoneAccountCreator accountCreator, LinphoneAccountCreator.Status status) {
AssistantActivity.instance().displayAssistantCodeConfirm(accountCreator.getUsername(), phoneNumberEdit.getText().toString(), getCountryCode(), true);
}
}

View file

@ -82,7 +82,7 @@ public class LoginFragment extends Fragment implements OnClickListener, TextWatc
}
}
AssistantActivity.instance().genericLogIn(login.getText().toString(), password.getText().toString(), displayName.getText().toString(), domain.getText().toString(), transport);
AssistantActivity.instance().genericLogIn(login.getText().toString(), password.getText().toString(), null, domain.getText().toString(), transport);
}
}

View file

@ -42,21 +42,21 @@ public class WelcomeFragment extends Fragment implements OnClickListener {
createAccount.setOnClickListener(this);
logLinphoneAccount = (Button) view.findViewById(R.id.login_linphone);
if (getResources().getBoolean(R.bool.hide_linphone_accounts_wizard)) {
if (getResources().getBoolean(R.bool.hide_linphone_accounts_in_assistant)) {
logLinphoneAccount.setVisibility(View.GONE);
} else {
logLinphoneAccount.setOnClickListener(this);
}
logGenericAccount = (Button) view.findViewById(R.id.login_generic);
if (getResources().getBoolean(R.bool.hide_generic_accounts_wizard)) {
if (getResources().getBoolean(R.bool.hide_generic_accounts_in_assistant)) {
logGenericAccount.setVisibility(View.GONE);
} else {
logGenericAccount.setOnClickListener(this);
}
remoteProvisioning = (Button) view.findViewById(R.id.remote_provisioning);
if (getResources().getBoolean(R.bool.hide_remote_provisioning_in_wizard)) {
if (getResources().getBoolean(R.bool.hide_remote_provisioning_in_assistant)) {
remoteProvisioning.setVisibility(View.GONE);
} else {
remoteProvisioning.setOnClickListener(this);

View file

@ -1,7 +1,7 @@
package org.linphone.compatibility;
import android.annotation.TargetApi;
import android.widget.TextView;
import android.annotation.TargetApi;
/*
ApiTwentyThreePlus.java

View file

@ -19,80 +19,134 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import java.util.ArrayList;
import java.util.Locale;
import java.util.List;
import org.linphone.LinphoneManager;
import org.linphone.LinphonePreferences;
import org.linphone.R;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.mediastream.Log;
import org.linphone.xmlrpc.XmlRpcHelper;
import org.linphone.xmlrpc.XmlRpcListenerBase;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;
/**
* @author Sylvain Berfini
*/
public class InAppPurchaseActivity extends Activity implements InAppPurchaseListener, OnClickListener {
private static InAppPurchaseActivity instance;
private InAppPurchaseHelper inAppPurchaseHelper;
private LinearLayout purchasableItemsLayout;
private ArrayList<Purchasable> purchasedItems;
private Button buyItemButton, recoverAccountButton;
private Handler mHandler = new Handler();
private ImageView cancel, back;
private ProgressBar inProgress;
private EditText username, email;
private TextView errorMessage;
private boolean usernameOk = false;
private List<Purchasable> purchasedItems;
private Fragment fragment;
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
inAppPurchaseHelper = new InAppPurchaseHelper(this, this);
setContentView(R.layout.in_app);
setContentView(R.layout.in_app_store);
purchasableItemsLayout = (LinearLayout) findViewById(R.id.purchasable_items);
inProgress = (ProgressBar) findViewById(R.id.purchaseItemsFetchInProgress);
inProgress.setVisibility(View.VISIBLE);
username = (EditText) findViewById(R.id.username);
email = (EditText) findViewById(R.id.email);
errorMessage = (TextView) findViewById(R.id.username_error);
addUsernameHandler(username, errorMessage);
back = (ImageView) findViewById(R.id.back);
back.setOnClickListener(this);
back.setVisibility(View.INVISIBLE);
cancel = (ImageView) findViewById(R.id.cancel);
cancel.setOnClickListener(this);
instance = this;
}
private void changeFragment(Fragment newFragment) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
transaction.commitAllowingStateLoss();
}
public void displayInappList() {
fragment = new InAppPurchaseListFragment();
changeFragment(fragment);
}
public void displayPurchase(Purchasable item) {
Bundle extra = new Bundle();
extra.putString("item_id",item.getId());
fragment = new InAppPurchaseFragment();
fragment.setArguments(extra);
changeFragment(fragment);
}
public void buyInapp(String username, Purchasable item){
LinphonePreferences.instance().setInAppPurchasedItem(item);
inAppPurchaseHelper.purchaseItemAsync(item.getId(), username);
}
public String getGmailAccount() {
return inAppPurchaseHelper.getGmailAccount();
}
@Override
protected void onDestroy() {
instance = null;
inAppPurchaseHelper.destroy();
super.onDestroy();
}
public List<Purchasable> getPurchasedItems() {
if (purchasedItems == null || purchasedItems.size() == 0) {
Log.w("nul");
}
return purchasedItems;
}
public Purchasable getPurchasedItem(String id) {
for(Purchasable item : purchasedItems){
if (item.getId().equals(id)){
return item;
}
}
return null;
}
public static InAppPurchaseActivity instance() {
return instance;
}
@Override
public void onServiceAvailableForQueries() {
email.setText(inAppPurchaseHelper.getGmailAccount());
email.setEnabled(false);
//email.setText(inAppPurchaseHelper.getGmailAccount());
//email.setEnabled(false);
inAppPurchaseHelper.getPurchasedItemsAsync();
//inAppPurchaseHelper.getPurchasedItemsAsync();
inAppPurchaseHelper.getAvailableItemsForPurchaseAsync();
}
@Override
public void onAvailableItemsForPurchaseQueryFinished(ArrayList<Purchasable> items) {
purchasableItemsLayout.removeAllViews();
//purchasableItemsLayout.removeAllViews();
inProgress.setVisibility(View.GONE);
purchasedItems = new ArrayList<Purchasable>();
for (Purchasable item : items) {
displayBuySubscriptionButton(item);
purchasedItems.add(item);
}
displayInappList();
}
@Override
@ -104,7 +158,7 @@ public class InAppPurchaseActivity extends Activity implements InAppPurchaseList
} else {
for (Purchasable purchasedItem : purchasedItems) {
Log.d("[In-app purchase] Found already bought item, expires " + purchasedItem.getExpireDate());
displayRecoverAccountButton(purchasedItem);
//displayRecoverAccountButton(purchasedItem);
}
}
}
@ -113,28 +167,26 @@ public class InAppPurchaseActivity extends Activity implements InAppPurchaseList
public void onPurchasedItemConfirmationQueryFinished(boolean success) {
if (success) {
XmlRpcHelper xmlRpcHelper = new XmlRpcHelper();
xmlRpcHelper.createAccountAsync(new XmlRpcListenerBase() {
Purchasable item = LinphonePreferences.instance().getInAppPurchasedItem();
xmlRpcHelper.updateAccountExpireAsync(new XmlRpcListenerBase() {
@Override
public void onAccountCreated(String result) {
public void onAccountExpireUpdated(String result) {
//TODO
}
}, getUsername(), email.getText().toString(), null);
}, LinphonePreferences.instance().getAccountUsername(0), LinphonePreferences.instance().getAccountHa1(0), getString(R.string.default_domain), item.getPayload(), item.getPayloadSignature());
}
}
@Override
public void onClick(View v) {
Purchasable item = (Purchasable) v.getTag();
if (v.equals(recoverAccountButton)) {
XmlRpcHelper xmlRpcHelper = new XmlRpcHelper();
xmlRpcHelper.createAccountAsync(new XmlRpcListenerBase() {
@Override
public void onAccountCreated(String result) {
//TODO
}
}, getUsername(), email.getText().toString(), null);
} else {
inAppPurchaseHelper.purchaseItemAsync(item.getId(), getUsername());
int id = v.getId();
if (id == R.id.cancel) {
finish();
} else if (id == R.id.back) {
onBackPressed();
}
}
@ -145,12 +197,6 @@ public class InAppPurchaseActivity extends Activity implements InAppPurchaseList
@Override
public void onRecoverAccountSuccessful(boolean success) {
mHandler.post(new Runnable() {
@Override
public void run() {
recoverAccountButton.setEnabled(false);
}
});
}
@Override
@ -159,6 +205,7 @@ public class InAppPurchaseActivity extends Activity implements InAppPurchaseList
mHandler.post(new Runnable() {
@Override
public void run() {
inProgress.setVisibility(View.GONE);
Toast.makeText(InAppPurchaseActivity.this, error, Toast.LENGTH_LONG).show();
}
});
@ -170,70 +217,4 @@ public class InAppPurchaseActivity extends Activity implements InAppPurchaseList
Log.d("[In-app purchase] Account activated");
}
}
private void displayBuySubscriptionButton(Purchasable item) {
View layout = LayoutInflater.from(this).inflate(R.layout.in_app_purchasable, purchasableItemsLayout);
Button button = (Button) layout.findViewById(R.id.inapp_button);
button.setText("Buy account (" + item.getPrice() + ")");
button.setTag(item);
button.setOnClickListener(this);
XmlRpcHelper xmlRpcHelper = new XmlRpcHelper();
xmlRpcHelper.createAccountAsync(new XmlRpcListenerBase() {
@Override
public void onAccountCreated(String result) {
//TODO
}
}, getUsername(), email.getText().toString(), null);
buyItemButton = button;
buyItemButton.setEnabled(usernameOk);
}
private void displayRecoverAccountButton(Purchasable item) {
View layout = LayoutInflater.from(this).inflate(R.layout.in_app_purchasable, purchasableItemsLayout);
Button button = (Button) layout.findViewById(R.id.inapp_button);
button.setText("Recover account");
button.setTag(item);
button.setOnClickListener(this);
recoverAccountButton = button;
recoverAccountButton.setEnabled(usernameOk);
}
private String getUsername() {
String username = this.username.getText().toString();
LinphoneProxyConfig lpc = LinphoneManager.getLc().createProxyConfig();
username = lpc.normalizePhoneNumber(username);
return username.toLowerCase(Locale.getDefault());
}
private boolean isUsernameCorrect(String username) {
LinphoneProxyConfig lpc = LinphoneManager.getLc().createProxyConfig();
return lpc.isPhoneNumber(username);
}
private void addUsernameHandler(final EditText field, final TextView errorMessage) {
field.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int count, int after) {
usernameOk = false;
String username = s.toString();
if (isUsernameCorrect(username)) {
usernameOk = true;
errorMessage.setText("");
} else {
errorMessage.setText(R.string.wizard_username_incorrect);
}
if (buyItemButton != null) buyItemButton.setEnabled(usernameOk);
if (recoverAccountButton != null) recoverAccountButton.setEnabled(usernameOk);
}
});
}
}

View file

@ -0,0 +1,185 @@
package org.linphone.purchase;
/*
InAppPurchaseFragment.java
Copyright (C) 2016 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.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.linphone.LinphoneManager;
import org.linphone.LinphonePreferences;
import org.linphone.R;
import org.linphone.mediastream.Log;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.xmlrpc.XmlRpcHelper;
import org.linphone.xmlrpc.XmlRpcListenerBase;
import java.util.Locale;
import java.util.regex.Pattern;
public class InAppPurchaseFragment extends Fragment implements View.OnClickListener {
private LinearLayout usernameLayout;
private EditText username, email;
private TextView errorMessage;
private boolean usernameOk = false, emailOk = false;
private Handler mHandler = new Handler();
private String defaultUsername, defaultEmail;
private Button buyItemButton, recoverAccountButton;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutInflater mInflater = inflater;
View view = inflater.inflate(R.layout.in_app_store, container, false);
String id = getArguments().getString("item_id");
Purchasable item = InAppPurchaseActivity.instance().getPurchasedItem(id);
buyItemButton = (Button) view.findViewById(R.id.inapp_button);
displayBuySubscriptionButton(item);
defaultEmail = InAppPurchaseActivity.instance().getGmailAccount();
defaultUsername = LinphonePreferences.instance().getAccountUsername(LinphonePreferences.instance().getDefaultAccountIndex());
usernameLayout = (LinearLayout) view.findViewById(R.id.username_layout);
username = (EditText) view.findViewById(R.id.username);
if(!getResources().getBoolean(R.bool.hide_username_in_inapp)){
usernameLayout.setVisibility(View.VISIBLE);
username.setText(LinphonePreferences.instance().getAccountUsername(LinphonePreferences.instance().getDefaultAccountIndex()));
addUsernameHandler(username, errorMessage);
} else {
if(defaultUsername != null){
usernameLayout.setVisibility(View.GONE);
usernameOk = true;
}
}
email = (EditText) view.findViewById(R.id.email);
if(defaultEmail != null){
email.setText(defaultEmail);
emailOk = true;
}
buyItemButton.setEnabled(emailOk && usernameOk);
errorMessage = (TextView) view.findViewById(R.id.username_error);
return view;
}
private void addUsernameHandler(final EditText field, final TextView errorMessage) {
field.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int count, int after) {
usernameOk = false;
String username = s.toString();
if (isUsernameCorrect(username)) {
usernameOk = true;
errorMessage.setText("");
} else {
errorMessage.setText(R.string.wizard_username_incorrect);
}
if (buyItemButton != null) buyItemButton.setEnabled(usernameOk);
if (recoverAccountButton != null) recoverAccountButton.setEnabled(usernameOk);
}
});
}
private void addEmailHandler(final EditText field, final TextView errorMessage) {
field.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int count, int after) {
emailOk = false;
String email = s.toString();
if (isEmailCorrect(email)) {
emailOk = true;
errorMessage.setText("");
} else {
errorMessage.setText(R.string.wizard_email_incorrect);
}
if (buyItemButton != null) buyItemButton.setEnabled(emailOk && usernameOk);
if (recoverAccountButton != null) recoverAccountButton.setEnabled(emailOk && usernameOk);
}
});
}
private boolean isEmailCorrect(String email) {
Pattern emailPattern = Patterns.EMAIL_ADDRESS;
return emailPattern.matcher(email).matches();
}
private boolean isUsernameCorrect(String username) {
LinphoneProxyConfig lpc = LinphoneManager.getLc().createProxyConfig();
return lpc.isPhoneNumber(username);
}
private void displayBuySubscriptionButton(Purchasable item) {
buyItemButton.setText("Buy account (" + item.getPrice() + ")");
buyItemButton.setTag(item);
buyItemButton.setOnClickListener(this);
buyItemButton.setEnabled(usernameOk && emailOk);
}
@Override
public void onClick(View v) {
Purchasable item = (Purchasable) v.getTag();
if (v.equals(recoverAccountButton)) {
//TODO
} else {
InAppPurchaseActivity.instance().buyInapp(getUsername(), item);
}
}
private String getUsername() {
String username = this.username.getText().toString();
LinphoneProxyConfig lpc = LinphoneManager.getLc().createProxyConfig();
username = lpc.normalizePhoneNumber(username);
return username.toLowerCase(Locale.getDefault());
}
}

View file

@ -127,14 +127,19 @@ public class InAppPurchaseHelper {
mListener = listener;
mGmailAccount = getGmailAccount();
Log.d("[In-app purchase] creating InAppPurchaseHelper for context "+context.getLocalClassName());
mServiceConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("[In-app purchase] onServiceDisconnected!");
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("[In-app purchase] onServiceConnected!");
mService = IInAppBillingService.Stub.asInterface(service);
String packageName = mContext.getPackageName();
try {
@ -191,6 +196,7 @@ public class InAppPurchaseHelper {
String desc = object.getString(SKU_DETAILS_DESC);
Purchasable purchasable = new Purchasable(id).setTitle(title).setDescription(desc).setPrice(price);
Log.w("Purchasable item " + purchasable.getDescription());
products.add(purchasable);
} catch (JSONException e) {
Log.e(e);
@ -277,6 +283,10 @@ public class InAppPurchaseHelper {
String payload = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA);
String signature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE);
Purchasable item = LinphonePreferences.instance().getInAppPurchasedItem();
item.setPayloadAndSignature(payload, signature);
LinphonePreferences.instance().setInAppPurchasedItem(item);
XmlRpcHelper xmlRpcHelper = new XmlRpcHelper();
xmlRpcHelper.verifySignatureAsync(new XmlRpcListenerBase() {
@Override

View file

@ -0,0 +1,100 @@
package org.linphone.purchase;
/*
InAppPurchaseListFragment.java
Copyright (C) 2016 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.widget.AdapterView;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import org.linphone.R;
import org.linphone.mediastream.Log;
import java.util.List;
public class InAppPurchaseListFragment extends Fragment implements AdapterView.OnItemClickListener{
private ListView inappList;
private LayoutInflater mInflater;
private List<Purchasable> mPurchasableItems;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mInflater = inflater;
View view = inflater.inflate(R.layout.in_app_list, container, false);
mPurchasableItems = InAppPurchaseActivity.instance().getPurchasedItems();
inappList = (ListView) view.findViewById(R.id.inapp_list);
if(mPurchasableItems != null){
inappList.setAdapter(new InAppListAdapter());
inappList.setOnItemClickListener(this);
}
return view;
}
class InAppListAdapter extends BaseAdapter {
InAppListAdapter() {}
public int getCount() {
return mPurchasableItems.size();
}
public Object getItem(int position) {
return mPurchasableItems.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView != null) {
view = convertView;
} else {
view = mInflater.inflate(R.layout.in_app_purchase_item, parent, false);
}
final Purchasable item = mPurchasableItems.get(position);
TextView itemTitle = (TextView) view.findViewById(R.id.purchase_title);
TextView itemDesc = (TextView) view.findViewById(R.id.purchase_description);
TextView itemPrice = (TextView) view.findViewById(R.id.purchase_price);
itemTitle.setText(item.getTitle());
itemDesc.setText(item.getDescription());
itemPrice.setText(item.getPrice());
view.setTag(item);
return view;
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Purchasable item = (Purchasable) view.getTag();
InAppPurchaseActivity.instance().displayPurchase(item);
}
}

View file

@ -11,6 +11,9 @@ import org.linphone.mediastream.Log;
public class XmlRpcHelper {
public static final String SERVER_ERROR_INVALID_ACCOUNT = "ERROR_INVALID_ACCOUNT";
public static final String SERVER_RESPONSE_OK = "OK";
public static final String SERVER_ERROR_INCORRECT_PHONE_NUMBER = "ERROR_PHONE_ISNT_E164";
public static final String SERVER_ERROR_ACCOUNT_DOESNT_EXIST = "ERROR_ACCOUNT_DOESNT_EXIST";
public static final String SERVER_ERROR_PURCHASE_CANCELLED = "ERROR_PURCHASE_CANCELLED";
public static final String SERVER_ERROR_RECEIPT_PARSING_FAILED = "ERROR_RECEIPT_PARSING_FAILED";
public static final String SERVER_ERROR_UID_ALREADY_IN_USE = "ERROR_UID_ALREADY_IN_USE";
@ -53,7 +56,7 @@ public class XmlRpcHelper {
}
public void getAccountExpireAsync(final XmlRpcListener listener, String username, String password) {
LinphoneXmlRpcRequest xmlRpcRequest = new LinphoneXmlRpcRequestImpl("get_expiration_for_account", LinphoneXmlRpcRequest.ArgType.String);
LinphoneXmlRpcRequest xmlRpcRequest = new LinphoneXmlRpcRequestImpl("get_account_expiration", LinphoneXmlRpcRequest.ArgType.String);
xmlRpcRequest.setListener(new LinphoneXmlRpcRequestListener() {
@Override
public void onXmlRpcRequestResponse(LinphoneXmlRpcRequest request) {
@ -76,7 +79,7 @@ public class XmlRpcHelper {
xmlRpcSession.sendRequest(xmlRpcRequest);
}
public void updateAccountExpireAsync(final XmlRpcListener listener, String username, String password, String payload, String signature) {
public void updateAccountExpireAsync(final XmlRpcListener listener, String username, String password, String domain, String payload, String signature) {
LinphoneXmlRpcRequest xmlRpcRequest = new LinphoneXmlRpcRequestImpl("update_expiration_date", LinphoneXmlRpcRequest.ArgType.String);
xmlRpcRequest.setListener(new LinphoneXmlRpcRequestListener() {
@Override
@ -97,6 +100,7 @@ public class XmlRpcHelper {
});
xmlRpcRequest.addStringArg(username);
xmlRpcRequest.addStringArg(password);
xmlRpcRequest.addStringArg(domain);
xmlRpcRequest.addStringArg(payload);
xmlRpcRequest.addStringArg(signature);
xmlRpcSession.sendRequest(xmlRpcRequest);
@ -152,7 +156,7 @@ public class XmlRpcHelper {
}
public void isTrialAccountAsync(final XmlRpcListener listener, String username, String password) {
LinphoneXmlRpcRequest xmlRpcRequest = new LinphoneXmlRpcRequestImpl("check_account_trial", LinphoneXmlRpcRequest.ArgType.String);
LinphoneXmlRpcRequest xmlRpcRequest = new LinphoneXmlRpcRequestImpl("is_account_trial", LinphoneXmlRpcRequest.ArgType.String);
xmlRpcRequest.setListener(new LinphoneXmlRpcRequestListener() {
@Override
public void onXmlRpcRequestResponse(LinphoneXmlRpcRequest request) {
@ -161,7 +165,7 @@ public class XmlRpcHelper {
if (!"NOK".equals(result) && !"OK".equals(result)) {
listener.onError(result);
}
listener.onAccountFetched("OK".equals(result));
listener.onTrialAccountFetched("OK".equals(result));
} else if (request.getStatus() == LinphoneXmlRpcRequest.Status.Failed) {
Log.e(result);
listener.onError(result);
@ -349,12 +353,13 @@ public class XmlRpcHelper {
}
public void verifySignatureAsync(final XmlRpcListener listener, String payload, String signature) {
LinphoneXmlRpcRequest xmlRpcRequest = new LinphoneXmlRpcRequestImpl("verify_payload_signature", LinphoneXmlRpcRequest.ArgType.String);
LinphoneXmlRpcRequest xmlRpcRequest = new LinphoneXmlRpcRequestImpl("check_payload_signature", LinphoneXmlRpcRequest.ArgType.String);
xmlRpcRequest.setListener(new LinphoneXmlRpcRequestListener() {
@Override
public void onXmlRpcRequestResponse(LinphoneXmlRpcRequest request) {
String result = request.getStringResponse();
if (request.getStatus() == LinphoneXmlRpcRequest.Status.Ok) {
Log.w(result);
if (result.startsWith("ERROR_")) {
Log.e(result);
listener.onError(result);

@ -1 +1 @@
Subproject commit bc85d6a842ce94a59a01698fd4373b162b53c2b9
Subproject commit dd095f5c12af3f78905eaeb15a4e91098e8d856f

@ -1 +1 @@
Subproject commit 580af25d04fcedfa1eafe28a24fa514dc7c91994
Subproject commit 990ab5fa309cb312a9ef2cd1a84bc2738e14475d

@ -1 +1 @@
Subproject commit e5c5c45147098164183cf4f11e55730688682a2c
Subproject commit 638c77300b5c32250b50a8d7a9fae05904dd0b91

View file

@ -26,6 +26,7 @@ public class AccountAssistant extends SampleTest {
@MediumTest
@LargeTest
public void testAWizardDisplayedAfterInstall() {
LinphonePreferences.instance().setXmlrpcUrl("https://sip3.linphone.org:444/inapp.php");
solo.waitForActivity("AssistantActivity", 3000);
solo.assertCurrentActivity("Expected Assistant Activity", AssistantActivity.class);
}
@ -38,11 +39,13 @@ public class AccountAssistant extends SampleTest {
solo.assertCurrentActivity("Expected Assistant Activity", AssistantActivity.class);
solo.clickOnView(solo.getView(org.linphone.R.id.login_linphone));
solo.clickOnView(solo.getView(org.linphone.R.id.use_username));
solo.enterText((EditText) solo.getView(org.linphone.R.id.assistant_username), iContext.getString(R.string.account_linphone_login));
solo.enterText((EditText) solo.getView(org.linphone.R.id.assistant_password), iContext.getString(R.string.account_linphone_pwd));
solo.enterText((EditText) solo.getView(org.linphone.R.id.assistant_display_name), iContext.getString(R.string.account_linphone_display_name));
solo.clickOnView(solo.getView(org.linphone.R.id.assistant_apply));
solo.clickOnView(solo.getView(org.linphone.R.id.assistant_skip));
solo.sleep(1000);
//Test echo calibration launch at first start
@ -69,8 +72,8 @@ public class AccountAssistant extends SampleTest {
String proxy = prefs.getAccountProxy(0);
Assert.assertEquals("<sip:" + aContext.getString(org.linphone.R.string.default_domain) + ";transport=tls>", proxy);
String display_name = prefs.getAccountDisplayName(0);
Assert.assertEquals(iContext.getString(R.string.account_linphone_display_name), display_name);
String username = prefs.getAccountUsername(0);
Assert.assertEquals(iContext.getString(R.string.account_linphone_login), username);
boolean ice = prefs.isIceEnabled();
Assert.assertEquals(ice, true);
@ -120,8 +123,6 @@ public class AccountAssistant extends SampleTest {
Assert.assertEquals(error.getText(), aContext.getString(org.linphone.R.string.wizard_username_incorrect));
Assert.assertFalse(createAccount.isEnabled());
solo.clearEditText((EditText) solo.getView(org.linphone.R.id.username));
solo.enterText((EditText) solo.getView(org.linphone.R.id.username), iContext.getString(R.string.account_linphone_login));
solo.sleep(sleepingTime * 2);