Binary file libs/android-support-v13.jar has changed
Binary file res/drawable/beem_status_icon_available.png has changed
Binary file res/drawable/beem_status_icon_away.png has changed
Binary file res/drawable/beem_status_icon_busy.png has changed
Binary file res/drawable/beem_status_icon_gray.png has changed
--- a/res/drawable/shape_line_green.xml Tue Jun 05 16:29:25 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android" type="line">
-<stroke android:width="1dp"
- android:height="2dp"
- android:color="#D6F94C" />
- <size android:height="1dp" />
-</shape>
--- a/res/layout/chat.xml Tue Jun 05 16:29:25 2012 +0200
+++ b/res/layout/chat.xml Tue Jun 05 16:44:38 2012 +0200
@@ -51,7 +51,7 @@
android:layout_height="fill_parent" android:layout_weight="1"
android:maxLines="5"
android:inputType="textShortMessage|textAutoCorrect|textMultiLine|textCapSentences"
- android:imeOptions="actionSend" android:cursorVisible="true"
+ android:imeOptions="actionSend|flagNoExtractUi" android:cursorVisible="true"
android:hint="@string/chat_input_default_value" />
<Button android:id="@+id/chat_send_message"
android:layout_width="wrap_content" android:layout_height="wrap_content"
--- a/res/layout/chat_compact.xml Tue Jun 05 16:29:25 2012 +0200
+++ b/res/layout/chat_compact.xml Tue Jun 05 16:44:38 2012 +0200
@@ -18,7 +18,7 @@
android:layout_height="fill_parent" android:layout_weight="1"
android:maxLines="5"
android:inputType="textShortMessage|textAutoCorrect|textMultiLine|textCapSentences"
- android:imeOptions="actionSend" android:cursorVisible="true"
+ android:imeOptions="actionSend|flagNoExtractUi" android:cursorVisible="true"
android:hint="@string/chat_input_default_value" />
<Button android:id="@+id/chat_send_message"
android:layout_width="wrap_content" android:layout_height="fill_parent"
--- a/res/layout/contactlist.xml Tue Jun 05 16:29:25 2012 +0200
+++ b/res/layout/contactlist.xml Tue Jun 05 16:44:38 2012 +0200
@@ -4,12 +4,21 @@
android:orientation="vertical">
<ViewStub android:id="@+id/contactlist_stub" android:inflatedId="@+id/contactlist_groupstub" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout="@layout/contactlist_groupstub"/>
+
+ <!--
+
<LinearLayout android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="horizontal"
android:padding="2px">
<ListView android:id="@+id/contactlist" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:transcriptMode="disabled"
android:textFilterEnabled="true" />
-
</LinearLayout>
+ -->
+
+ <android.support.v4.view.ViewPager android:id="@+id/pager"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="2px"/>
+
</LinearLayout>
--- a/res/layout/contactlist_group.xml Tue Jun 05 16:29:25 2012 +0200
+++ b/res/layout/contactlist_group.xml Tue Jun 05 16:44:38 2012 +0200
@@ -1,5 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ BEEM is a videoconference application on the Android Platform.
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ Copyright (C) 2009-2011 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM 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 BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+-->
+<com.beem.project.beem.ui.views.SectionTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:beem="http://schemas.android.com/apk/res/com.beem.project.beem"
android:textColor="@color/white" android:textColorHighlight="@color/red"
android:textSize="18sp" android:typeface="normal" android:textStyle="bold"
- android:id="@+id/contactlist_group"></TextView>
\ No newline at end of file
+ android:paddingLeft="20dp" android:paddingRight="20dp"
+ beem:principalColor="@color/vert_manu"
+ android:id="@+id/contactlist_group"
+ />
--- a/res/layout/contactlist_groupstub.xml Tue Jun 05 16:29:25 2012 +0200
+++ b/res/layout/contactlist_groupstub.xml Tue Jun 05 16:44:38 2012 +0200
@@ -1,10 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2011 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM 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 BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contactlist_groupstub" android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Gallery xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contactlist_banner" android:layout_width="fill_parent"
- android:layout_height="40dp" android:spacing="25dp"
+ android:layout_height="40dp" android:spacing="0dp"
android:unselectedAlpha="0.4" android:background="#222222" />
<View android:layout_width="fill_parent" android:layout_height="2dp"
android:fadingEdge="horizontal" android:background="#555555" />
--- a/res/layout/preferences.xml Tue Jun 05 16:29:25 2012 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- The format of the preference key is defined in
- src/com/beem/project/beem/BeemApplication.java
- Basically it is just a simple name like account_username.
- TODO: There is still a lot of keys to convert
--->
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- android:shouldDisableView="true" android:selectable="true">
- <PreferenceCategory android:title="@string/general_preferences">
- <PreferenceScreen android:key="contact_list"
- android:title="@string/contact_list_preferences" android:summary="@string/contact_list_preferences_sum">
- <CheckBoxPreference android:title="@string/CLP_hidden_contact"
- android:defaultValue="false" android:summary="@string/CLP_hidden_contact_sum"
- android:key="show_offline_contacts" />
- <CheckBoxPreference android:title="@string/CLP_hide_groups"
- android:defaultValue="false" android:summary="@string/CLP_hide_groups_sum"
- android:key="hide_groups" />
- <CheckBoxPreference android:title="@string/away_chk_title"
- android:defaultValue="true" android:summary="@string/away_chk_sum"
- android:key="use_auto_away" />
- <EditTextPreference android:dependency="use_auto_away"
- android:singleLine="true" android:summary="@string/away_message_sum"
- android:title="@string/away_message_title" android:key="auto_away_msg"
- android:hint="@string/away_message_hint" />
- </PreferenceScreen>
- <PreferenceScreen android:key="chat"
- android:title="@string/chat_preferences" android:summary="@string/chat_preferences_sum">
- <PreferenceCategory android:title="@string/history_preferences">
- <CheckBoxPreference android:id="@+id/chat_history"
- android:title="@string/history" android:summary="@string/history_sum"
- android:defaultValue="false" android:key="settings_key_history" />
- <EditTextPreference android:dependency="settings_key_history"
- android:singleLine="true" android:title="@string/chat_history_path"
- android:summary="@string/chat_history_path_sum" android:key="settings_chat_history_path"
- android:hint="/Android/data/com.beem.project.beem/chat/" />
- </PreferenceCategory>
- <PreferenceCategory android:title="@string/chat_layout_option">
- <CheckBoxPreference android:title="@string/settings_chat_compact"
- android:defaultValue="false" android:summary="@string/settings_chat_compact_sum"
- android:key="use_compact_chat_ui" />
- </PreferenceCategory>
- </PreferenceScreen>
- <PreferenceScreen android:title="@string/notification_preferences">
- <CheckBoxPreference android:title="@string/notification_enable_vibrate_title"
- android:defaultValue="false" android:summary="@string/notification_enable_vibrate_sum"
- android:key="notification_vibrate" />
- <RingtonePreference android:title="@string/notification_snd_title"
- android:key="notification_sound" android:summary="@string/notification_snd_sum"
- android:ringtoneType="notification" android:showDefault="true" />
- </PreferenceScreen>
- </PreferenceCategory>
- <PreferenceCategory android:title="@string/user_preferences">
- <EditTextPreference android:singleLine="true"
- android:summary="@string/SettingsText" android:title="@string/settings_account_username"
- android:key="account_username" android:hint="@string/login_username_info_default"
- android:inputType="textEmailAddress" />
- <EditTextPreference android:name="password"
- android:singleLine="true" android:password="true" android:summary="@string/SettingsPassword"
- android:title="@string/settings_account_password" android:key="account_password" />
- </PreferenceCategory>
- <PreferenceCategory android:title="@string/user_preferences_advanced">
- <EditTextPreference android:key="connection_resource"
- android:title="@string/SettingsResourceTitle" android:summary="@string/SettingsResourceSummary"
- android:defaultValue="Beem" />
- <EditTextPreference android:key="connection_priority"
- android:title="@string/SettingsPriorityTitle" android:summary="@string/SettingsPrioritySummary"
- android:numeric="signed" android:defaultValue="0" />
- </PreferenceCategory>
- <PreferenceCategory android:title="@string/network_preferences">
- <PreferenceScreen android:key="proxy" android:title="@string/SettingsProxy"
- android:summary="@string/settings_proxy_sum">
- <CheckBoxPreference android:title="@string/SettingsProxyProxy"
- android:defaultValue="false" android:summary="@string/SettingsProxySummary"
- android:key="proxy_use" />
- <PreferenceCategory android:title="@string/proxy_proxy_settings">
- <ListPreference android:dependency="proxy_use"
- android:title="@string/SettingsProxyType" android:entries="@array/proxy_types"
- android:summary="@string/SettingsProxyTypeSummary"
- android:defaultValue="HTTP" android:entryValues="@array/proxy_types"
- android:key="proxy_type" />
- <EditTextPreference android:singleLine="true"
- android:dependency="proxy_use" android:name="serveur"
- android:summary="@string/SettingsProxyServer" android:title="@string/settings_proxy_server"
- android:key="proxy_server" />
- <EditTextPreference android:singleLine="true"
- android:dependency="proxy_use" android:name="port"
- android:summary="@string/SettingsProxyPort" android:title="@string/settings_proxy_port"
- android:key="proxy_port" android:numeric="signed"
- android:hint="@string/comments_proxy_port" />
- </PreferenceCategory>
- <PreferenceCategory android:title="@string/proxy_user_settings">
- <EditTextPreference android:singleLine="true"
- android:dependency="proxy_use" android:name="Utilisateur"
- android:summary="@string/SettingsProxyUser" android:title="@string/settings_proxy_username"
- android:key="proxy_username" />
- <EditTextPreference android:singleLine="true"
- android:dependency="proxy_use" android:name="pass_user"
- android:password="true" android:summary="@string/SettingsProxyPassword"
- android:title="@string/settings_proxy_password" android:key="proxy_password" />
- </PreferenceCategory>
- </PreferenceScreen>
-
- <PreferenceScreen android:key="advanced"
- android:title="@string/SettingsAdvanced" android:summary="@string/settings_advanced_sum">
- <PreferenceCategory android:title="@string/settings_advanced_service_behaviour">
- <CheckBoxPreference android:title="@string/settings_xmpp_use_tls"
- android:defaultValue="false" android:key="settings_key_xmpp_tls_use" />
- <CheckBoxPreference android:title="@string/settings_smack_debug"
- android:defaultValue="false" android:key="smack_debug" />
- <EditTextPreference android:singleLine="true"
- android:title="@string/settings_reco_delay" android:name="Reconnect delay"
- android:summary="@string/SettingsAdvancedRecoDelay" android:key="settings_key_reco_delay"
- android:defaultValue="10" />
- </PreferenceCategory>
- <CheckBoxPreference android:title="@string/SettingsAdvancedOptions"
- android:defaultValue="false" android:summary="@string/SettingsAdvancedSpecOpt"
- android:key="settings_key_specific_server" />
- <EditTextPreference android:singleLine="true"
- android:dependency="settings_key_specific_server" android:name="adresse"
- android:summary="@string/SettingsAdvancedAddOpt" android:title="@string/settings_xmpp_server"
- android:key="settings_key_xmpp_server" android:hint="@string/comments_xmpp_server" />
- <EditTextPreference android:singleLine="true"
- android:dependency="settings_key_specific_server" android:name="port"
- android:summary="@string/SettingsAdvancedPortOpt" android:title="@string/settings_xmpp_port"
- android:defaultValue="5222" android:numeric="signed" android:key="settings_key_xmpp_port"
- android:hint="@string/comments_xmpp_port" />
- <CheckBoxPreference android:title="@string/settings_full_jid_login"
- android:defaultValue="false" android:summary="@string/settings_full_jid_login_sum"
- android:key="full_jid_login" />
- </PreferenceScreen>
- </PreferenceCategory>
-</PreferenceScreen>
--- a/res/values-fr/strings.xml Tue Jun 05 16:29:25 2012 +0200
+++ b/res/values-fr/strings.xml Tue Jun 05 16:44:38 2012 +0200
@@ -90,7 +90,9 @@
d\'ami(e)s</string>
<string name="CLP_hide_groups">Cachez les groupes</string>
<string name="CLP_hide_groups_sum">Cochez cette option pour cacher les groupes</string>
- <string name="CLP_hidden_contact">Cachez les contacts</string>
+ <string name="CLP_show_jid">Affichez les JID</string>
+ <string name="CLP_show_jid_sum">Cochez cette option pour afficher les JIDs des contacts</string>
+ <string name="CLP_hidden_contact">Cachez les contacts déconnectés</string>
<string name="CLP_hidden_contact_sum">Cochez cette option pour cacher les contacts déconnectés</string>
<string name="settings_account_username">Nom d\'utilisateur (JID)</string>
<string name="login_username_info_default">beem@beem-project.com</string>
--- a/res/values-nb/strings.xml Tue Jun 05 16:29:25 2012 +0200
+++ b/res/values-nb/strings.xml Tue Jun 05 16:44:38 2012 +0200
@@ -3,217 +3,217 @@
<!-- Generic terms -->
<string name="app_name">Beem</string>
<string name="OkButton">Ok</string>
-<string name="ClearButton">Löschen</string>
-<string name="CancelButton">Abbrechen</string>
-<string name="AcceptButton">Authorisieren</string>
-<string name="RefuseButton">Ablehnen</string>
-<string name="JabberID">Jabber ID</string>
-<string name="Password">Passwort</string>
-<string name="Continue">Fortfahren</string>
+<string name="ClearButton">Tøm</string>
+<string name="CancelButton">Avbryt</string>
+<string name="AcceptButton">Godkjenn</string>
+<string name="RefuseButton">Avslå</string>
+<string name="JabberID">Jabber-ID</string>
+<string name="Password">Passord</string>
+<string name="Continue">Fortsett</string>
<!-- AccountConfigure class -->
-<string name="AccountConfigureManualConfiguration">Manuelle Konfiguration</string>
+<string name="AccountConfigureManualConfiguration">Manuelt oppsett</string>
<!-- Beem class -->
-<string name="BeemJabberID">Jabber ID</string>
+<string name="BeemJabberID">Jabber-ID</string>
<!-- BeemApplication class -->
-<string name="BeemApplicationConnect">Verbinden...</string>
+<string name="BeemApplicationConnect">Kobler til ...</string>
<!-- BeemService class -->
-<string name="BeemServiceDescription">Benutze Beem Service</string>
-<string name="BeemServiceCreated">Beem Service erstellt</string>
-<string name="BeemServiceDestroyed">Beem Service verworfen</string>
+<string name="BeemServiceDescription">Bruk Beem tjeneste </string>
+<string name="BeemServiceCreated">Beem tjeneste opprettet</string>
+<string name="BeemServiceDestroyed">Beem tjeneste slettet</string>
<!-- ContactDialog class -->
-<string name="CDChat">Chatten</string>
-<string name="CDCall">Anrufen</string>
-<string name="CDInfos">Kontakt bearbeiten</string>
+<string name="CDChat">Prat</string>
+<string name="CDCall">Ring</string>
+<string name="CDInfos">Behandle kontakt</string>
<!-- AddContact class -->
-<string name="AddCActTitle">Beem - Kontakt hinzufügen</string>
+<string name="AddCActTitle">Beem - legg til en kontakt</string>
-<string name="AddCLogin">Benutzername</string>
+<string name="AddCLogin">Brukernavn</string>
<string name="AddCAlias">Alias</string>
<string name="AddCGroup">Gruppe</string>
-<string name="AddCOkButton">Hinzufügen</string>
-<string name="AddCContactAdded">Kontakt hinzugefügt</string>
-<string name="AddCContactAddedError">Fehler, Benutzer nicht hinzugefügt</string>
-<string name="AddCContactAddedLoginError">Fehler bei der Anmeldung</string>
-<string name="AddCBadForm">Mangelhafte Form</string>
-<string name="AddCContactAlready">Kontakt existiert bereits</string>
+<string name="AddCOkButton">Legg til</string>
+<string name="AddCContactAdded">Kontakt lagt til</string>
+<string name="AddCContactAddedError">Feil ved lagring av kontakt</string>
+<string name="AddCContactAddedLoginError">Feil ved innlogging</string>
+<string name="AddCBadForm">Feil utfylt</string>
+<string name="AddCContactAlready">Kontakten finnes allerede</string>
<!-- ChangeStatus class -->
-<string name="ChangeStatusActTitle">Beem - Meinen Status ändern</string>
-<string name="ChangeStatusType">Mein Status</string>
-<string name="ChangeStatusMessage">Meine persönliche Nachricht</string>
-<string name="OpenContactList">Kontaktliste öffnen</string>
+<string name="ChangeStatusActTitle">Beem - Endre status</string>
+<string name="ChangeStatusType">Min status</string>
+<string name="ChangeStatusMessage">Min personlige melding</string>
+<string name="OpenContactList">Åpne kontaktlista</string>
-<string name="MenuAddContact">Kontakt hinzufügen</string>
-<string name="MenuAccountAbout">Beem Project</string>
-<string name="MenuAccountCreate">Konto erstellen</string>
-<string name="MenuConnection">Konto bearbeiten</string>
-<string name="ChangeStatusOk">Aktualisiere Status</string>
-<string name="ChangeStatusNoChange">Nichts zu ändern</string>
-<string name="my_avatar">Mein Avatar</string>
-<string name="select_avatar">Wähle Avatar</string>
-<string name="take_photo">Foto machen</string>
-<string name="pick_photo">Bild auswählen</string>
-<string name="delete_avatar">Kein Avatar</string>
-<string name="photoPickerNotFoundText">Fotoauswahl nicht gefunden</string>
+<string name="MenuAddContact">Legg til ny kontakt</string>
+<string name="MenuAccountAbout">Beem-prosjektet</string>
+<string name="MenuAccountCreate">Opprett konto</string>
+<string name="MenuConnection">Rediger konto</string>
+<string name="ChangeStatusOk">Oppdaterer status</string>
+<string name="ChangeStatusNoChange">Ingen endringer</string>
+<string name="my_avatar">Mitt personbilde</string>
+<string name="select_avatar">Velg ditt personbilde</string>
+<string name="take_photo">Ta et bilde</string>
+<string name="pick_photo">Velg et bilde</string>
+<string name="delete_avatar">Ingen personbilde</string>
+<string name="photoPickerNotFoundText">Bildevelger ikke funnet</string>
<!-- Settings class -->
-<string name="SettingsText">Benutzername bearbeiten</string>
-<string name="SettingsPassword">Passwort bearbeiten</string>
-<string name="SettingsProxy">Proxy</string>
-<string name="SettingsProxyProxy">Benutze einen Proxyserver</string>
-<string name="SettingsProxySummary">Anmeldung über einen Proxyserver</string>
+<string name="SettingsText">Rediger brukernavn</string>
+<string name="SettingsPassword">Rediger passord</string>
+<string name="SettingsProxy">Mellomtjener</string>
+<string name="SettingsProxyProxy">Bruk en mellomtjener</string>
+<string name="SettingsProxySummary">Logg inn via en mellomtjener</string>
<string name="SettingsProxyType">Protokoll</string>
-<string name="SettingsProxyTypeSummary">Art des Proxyservers wählen</string>
-<string name="SettingsProxyServer">Adresse des Proxyservers bearbeiten</string>
-<string name="SettingsProxyPort">Port des Proxyservers bearbeiten</string>
-<string name="SettingsProxyUser">Optional, erlaubt das Authentifizieren mit dem Proxyserver</string>
-<string name="SettingsProxyPassword">Optional, erlaubt das Authentifizieren mit dem Proxyserver</string>
-<string name="SettingsAdvanced">Erweitert</string>
-<string name="SettingsAdvancedOptions">Spezifische Server Optionen</string>
-<string name="SettingsAdvancedRecoDelay">Bearbeite die Verzögerung bei der Wiederverbindung</string>
-<string name="SettingsAdvancedSpecOpt">Aktivieren, um einen spezifischen Server für die Verbindung zu benutzen</string>
-<string name="SettingsAdvancedAddOpt">Adresse des Servers bearbeiten</string>
-<string name="SettingsAdvancedPortOpt">Port des Servers bearbeiten</string>
-<string name="SettingsResourceTitle">Ressource</string>
-<string name="SettingsPriorityTitle">Priorität</string>
-<string name="SettingsResourceSummary">XMPP Ressource des Clients einstellen</string>
-<string name="SettingsPrioritySummary">Priorität des Clients einstellen</string>
+<string name="SettingsProxyTypeSummary">Velg mellomtjenertype</string>
+<string name="SettingsProxyServer">Rediger mellomtjeneradresse</string>
+<string name="SettingsProxyPort">Rediger mellomtjenerport</string>
+<string name="SettingsProxyUser">Valgfritt, tillat autentisering på mellomtjeneren</string>
+<string name="SettingsProxyPassword">Valgfritt, tillat autentisering på mellomtjeneren</string>
+<string name="SettingsAdvanced">Avansert</string>
+<string name="SettingsAdvancedOptions">Spesielle tjenerinnstilling</string>
+<string name="SettingsAdvancedRecoDelay">Endre forsinkelse ved ny tilkobling</string>
+<string name="SettingsAdvancedSpecOpt">Aktiver hvis du vil bruke en spesifikk tjener for din tilkobling</string>
+<string name="SettingsAdvancedAddOpt">Rediger tjeneradresse</string>
+<string name="SettingsAdvancedPortOpt">Rediger tjenerport</string>
+<string name="SettingsResourceTitle">Ressurs</string>
+<string name="SettingsPriorityTitle">Prioritet</string>
+<string name="SettingsResourceSummary">Velg XMPP ressurs for denne klienten</string>
+<string name="SettingsPrioritySummary">Velg prioritet for denne klienten</string>
<string name="contact_list_preferences">Kontaktliste</string>
<string name="contact_list_preferences_sum">A set of display options for your buddy list
</string>
-<string name="CLP_hide_groups">Gruppen ausblenden</string>
-<string name="CLP_hide_groups_sum">Aktivieren, um Gruppen auszublenden</string>
-<string name="CLP_hidden_contact">Kontakte ausblenden</string>
+<string name="CLP_hide_groups">Skjul grupper</string>
+<string name="CLP_hide_groups_sum">Aktiver for å skjule grupper</string>
+<string name="CLP_hidden_contact">Skjul kontakter</string>
<string name="CLP_hidden_contact_sum">Check this option to hide unconnected buddies
</string>
-<string name="settings_account_username">Benutzername (JID)</string>
+<string name="settings_account_username">Brukernavn (JID)</string>
<string name="login_username_info_default">beem@beem-project.com</string>
-<string name="settings_account_password">Passwort</string>
-<string name="settings_account_server">Server</string>
+<string name="settings_account_password">Passord</string>
+<string name="settings_account_server">Tjener</string>
<string name="settings_account_port">Port</string>
-<string name="settings_advanced_service_behaviour">Verhalten des Dienstes</string>
-<string name="settings_advanced_sum">Erweiterte Einstellungen für fortgeschrittene Benutzer</string>
+<string name="settings_advanced_service_behaviour">Tjenesteoppførsel</string>
+<string name="settings_advanced_sum">Innstillinger for avanserte brukere</string>
<string name="settings_xmpp_server">Adresse</string>
<string name="comments_xmpp_server">example.com</string>
<string name="settings_xmpp_port">Port</string>
-<string name="settings_xmpp_use_tls">Verwende SSL/TLS</string>
-<string name="settings_reco_delay">Verzögerung bei der Wiederverbindung</string>
+<string name="settings_xmpp_use_tls">Krev SSL/TLS</string>
+<string name="settings_reco_delay">Forsinkelse ved ny tilkobling</string>
<string name="comments_xmpp_port">Standard: 5222</string>
-<string name="settings_proxy_sum">Einstellungen für das Benutzen eines Proxyservers</string>
-<string name="settings_proxy_use">Benutze einen Proxyserver</string>
-<string name="settings_proxy_type_prompt">Art des Proxyservers wählen</string>
-<string name="settings_proxy_server">Server</string>
+<string name="settings_proxy_sum">Innstillinger for bruk av mellomtjener</string>
+<string name="settings_proxy_use">Koble til via en mellomtjener</string>
+<string name="settings_proxy_type_prompt">Velg mellomtjenertype</string>
+<string name="settings_proxy_server">Tjener</string>
<string name="settings_proxy_port">Port</string>
<string name="comments_proxy_port">Standard: 1080</string>
-<string name="settings_proxy_username">Benutzername</string>
-<string name="settings_proxy_password">Passwort</string>
-<string name="away_chk_title">Aktiviere automatische Abwesenheit</string>
-<string name="away_chk_sum">Status auf Abwesend wenn Bildschirm aus</string>
-<string name="away_message_title">Abwesenheitsnachricht</string>
-<string name="away_message_sum">Angezeigte Abwesenheitsnachricht</string>
-<string name="away_message_hint">Ich bin abwesend, mein Telefonbildschirm ist aus</string>
-<string name="notification_preferences">Benachrichtigungseinstellungen</string>
-<string name="notification_enable_vibrate_title">Aktiviere Vibration</string>
-<string name="notification_enable_vibrate_sum">Aktiviere Vibration für eingehende Nachrichten</string>
-<string name="notification_snd_title">Nachrichtensignalton</string>
-<string name="notification_snd_sum">Lege den Signalton für eingehende Nachrichten fest</string>
-<string name="settings_chat_compact">Kompakter Chat</string>
-<string name="settings_chat_compact_sum">Benutze kompakte Chatfenster</string>
-<string name="history">Chronik</string>
-<string name="history_sum">Aktivieren, um Unterhaltungen auf die Speicherkarte zu speichern</string>
-<string name="history_mount">Die Speicherkarte muss eingehängt und beschreibbar sein, um die Chronik zu aktivieren</string>
-<string name="history_on_off">Aktiviere Nachrichtenchronik</string>
-<string name="chat_preferences">Chat</string>
-<string name="chat_preferences_sum">Chronik, Layout Größe ...</string>
-<string name="chat_history_path">Chronik Pfad</string>
-<string name="chat_history_path_sum">Unterhaltungen werden in einem Ordner auf der Speicherkarte gespeichert</string>
-<string name="settings_smack_debug">Aktiviere XMPP Debug Modus</string>
-<string name="settings_full_jid_login">Benutze meine vollständige JID als Benutzername</string>
-<string name="settings_full_jid_login_sum">Wird von einigen Servern, z.b. Google Talk, vorausgesetzt</string>
+<string name="settings_proxy_username">Brukernavn</string>
+<string name="settings_proxy_password">Passord</string>
+<string name="away_chk_title">Bruk auto-borte</string>
+<string name="away_chk_sum">Endre status til borte når skjermen er av</string>
+<string name="away_message_title">Borte-melding</string>
+<string name="away_message_sum">Borte-melding som vil bli vist</string>
+<string name="away_message_hint">Jeg er borte, telefonens skjerm er av</string>
+<string name="notification_preferences">Varslingsinnstillinger</string>
+<string name="notification_enable_vibrate_title">Bruk vibrasjon</string>
+<string name="notification_enable_vibrate_sum">Bruk vibrasjon ved innkommende meldinger</string>
+<string name="notification_snd_title">Meldingsringetone</string>
+<string name="notification_snd_sum">Velg ringetone for innkommende meldinger</string>
+<string name="settings_chat_compact">Kompakt pratevindu</string>
+<string name="settings_chat_compact_sum">Velg kompakt pratevindu</string>
+<string name="history">Historikk</string>
+<string name="history_sum">Aktiver for å lagre meldinger på minnekortet</string>
+<string name="history_mount">Du trenger et montert og skrivebart minnekort for å kunne aktivere historikk</string>
+<string name="history_on_off">Aktiver historikk</string>
+<string name="chat_preferences">Prat</string>
+<string name="chat_preferences_sum">Historikk, utseende ...</string>
+<string name="chat_history_path">Sti til historikk</string>
+<string name="chat_history_path_sum">Samtaler lagres i en mappe på minnekortet</string>
+<string name="settings_smack_debug">Aktiver XMPP feilsøking</string>
+<string name="settings_full_jid_login">Bruk full JID som brukernavn</string>
+<string name="settings_full_jid_login_sum">Kreves på visse tjenere slik som Google Talk</string>
<!-- Subscription class -->
-<string name="SubscriptAccept">Zustimmung angenommen</string>
-<string name="SubscriptError">Zustimmungsfehler</string>
-<string name="SubscriptRefused">Zustimmung abgelehnt</string>
-<string name="SubscriptText">%s will dich zu seiner/ihrer Kontaktliste hinzufügen. Willst du ihn/sie authorisieren?</string>
-<string name="SubscriptTitle">Kontakt authorisieren?</string>
+<string name="SubscriptAccept">Abonnement godkjent</string>
+<string name="SubscriptError">Feil ved abonnement</string>
+<string name="SubscriptRefused">Abonnement avslått</string>
+<string name="SubscriptText">%s ønsker å legge deg til sin kontaktliste. Godkjenne forespørselen?</string>
+<string name="SubscriptTitle">Godkjenne kontakt?</string>
<!-- BeemChatManager -->
-<string name="BeemChatManagerNewMessage">Du hast eine neue Nachricht</string>
+<string name="BeemChatManagerNewMessage">Du har en ny melding</string>
<!-- BeemBroadcastReceiver class -->
-<string name="BeemBroadcastReceiverDisconnect">BEEM: Die Verbindung wurde getrennt</string>
+<string name="BeemBroadcastReceiverDisconnect">BEEM: du har koblet fra</string>
<!-- XmppConnectionAdapter class -->
-<string name="AcceptContactRequest">%s hat dich gerade zu seiner/ihrer Kontaktliste hinzugefügt.</string>
-<string name="AcceptContactRequestFrom">Authorisiere %s dich zu kontaktieren.</string>
+<string name="AcceptContactRequest">%s har lagt deg til sin kontaktliste</string>
+<string name="AcceptContactRequestFrom">Godkjenn at %s kontakter deg</string>
<!-- Activities -->
-<string name="login_tag">Beem - Anmeldung</string>
-<string name="edit_settings_name">Beem - Einstellungen</string>
-<string name="edit_settings_tag">Beem - Einstellungen bearbeiten</string>
-<string name="create_account_name">Beem - Konto erstellen</string>
-<string name="create_account_tag">Beem - Konto erstellen</string>
-<string name="contact_list_name">Beem - Kontakte</string>
-<string name="contact_list_tag">Beem - Kontaktliste</string>
-<string name="user_info_name">Beem - Benutzerinformation</string>
+<string name="login_tag">Beem - Aktivitet innlogging</string>
+<string name="edit_settings_name">Beem - Innstillinger</string>
+<string name="edit_settings_tag">Beem - Aktivitet innstillinger</string>
+<string name="create_account_name">Beem - Opprett konto</string>
+<string name="create_account_tag">Beem - Aktivitet opprett konto</string>
+<string name="contact_list_name">Beem - Kontakter</string>
+<string name="contact_list_tag">Beem - Aktivitet kontaktliste</string>
+<string name="user_info_name">Beem - Brukerinformasjon</string>
<!-- Buttons -->
-<string name="button_create_account">Dieses Konto erstellen</string>
-<string name="button_create_login_account">Dieses Konto erstellen und benutzen</string>
+<string name="button_create_account">Opprett kontoen</string>
+<string name="button_create_login_account">Opprett og bruk kontoen</string>
<!-- LogAs Activity -->
-<string name="login_username">Benutzername</string>
-<string name="login_password">Passwort</string>
-<string name="login_error_dialog_title">Anmeldung - Fehler</string>
-<string name="login_close_dialog_button">Schließen</string>
-<string name="login_menu_create_account">Konto erstellen</string>
-<string name="login_menu_settings">Einstellungen</string>
-<string name="login_menu_about">Über</string>
-<string name="login_about_title">Beem %s - Über</string>
+<string name="login_username">Brukernavn</string>
+<string name="login_password">Passord</string>
+<string name="login_error_dialog_title">Feil ved innlogging</string>
+<string name="login_close_dialog_button">Lukk</string>
+<string name="login_menu_create_account">Opprett konto</string>
+<string name="login_menu_settings">Innstillinger</string>
+<string name="login_menu_about">Om</string>
+<string name="login_about_title">Beem %s - Om</string>
<string name="login_about_msg">
Beem is an EPITECH Innovative Project. Visit us at
http://www.beem-project.com !
</string>
-<string name="login_about_button">Schließen</string>
-<string name="login_settings_button">Einstellungen</string>
-<string name="login_login_button">Anmelden</string>
-<string name="login_login_progress">Verbinden. Bitte warten...</string>
+<string name="login_about_button">Lukk</string>
+<string name="login_settings_button">Innstillinger</string>
+<string name="login_login_button">Logg inn</string>
+<string name="login_login_progress">Kobler til ...</string>
<string name="login_error_msg">Unfortunately, an error occured.\n\nError
detail:\n%s</string>
-<string name="login_menu_login">Anmelden</string>
-<string name="login_no_connectivity">Keine Internetverbindung gefunden</string>
-<string name="login_start_msg">Konfiguration der Einstellungen im Menü</string>
+<string name="login_menu_login">Innlogging</string>
+<string name="login_no_connectivity">Ingen nettforbindelse funnet</string>
+<string name="login_start_msg">Innstillinger i menyen</string>
<!-- LoginAnim activity -->
-<string name="loganim_connecting">Verbinden...</string>
-<string name="loganim_authenticating">Authentifizieren...</string>
-<string name="loganim_login_success">Erfolgreich angemeldet</string>
-<string name="loganim_login_failed">Anmeldung gescheitert</string>
+<string name="loganim_connecting">Kobler til ...</string>
+<string name="loganim_authenticating">Autentiserer ...</string>
+<string name="loganim_login_success">Innlogging vellykket</string>
+<string name="loganim_login_failed">Feil ved innlogging</string>
<!-- EditSettings Activity -->
-<string name="settings_menu_create_account">Konto erstellen</string>
-<string name="settings_menu_privacy_lists">Meine Privatsphärenliste verwalten</string>
-<string name="settings_saved_ok">Die Einstellungen wurden erfolgreich gespeichert.</string>
+<string name="settings_menu_create_account">Opprett en konto</string>
+<string name="settings_menu_privacy_lists">Behandle personvernlister</string>
+<string name="settings_saved_ok">Innstillinger lagret</string>
<!-- EditSettings Activity Categories -->
-<string name="general_preferences">Allgemeine Einstellungen</string>
-<string name="user_preferences">Benutzereinstellungen (notwendig)</string>
-<string name="user_preferences_advanced">Zusätzliche Benutzereinstellungen (optional)</string>
-<string name="network_preferences">Netzwerk Einstellungen</string>
-<string name="proxy_proxy_settings">Proxy Einstellungen</string>
-<string name="proxy_user_settings">Proxy Einstellungen</string>
-<string name="history_preferences">Chronik</string>
-<string name="chat_layout_option">Chat Ansicht</string>
+<string name="general_preferences">Generelle innstillinger</string>
+<string name="user_preferences">Brukerinnstillinger (kreves)</string>
+<string name="user_preferences_advanced">Avanserte brukerinnstillinger (valgfritt)</string>
+<string name="network_preferences">Nettverksinnstillinger</string>
+<string name="proxy_proxy_settings">Tjenerinnstillinger</string>
+<string name="proxy_user_settings">Tjenerinnstillinger</string>
+<string name="history_preferences">Historikk</string>
+<string name="chat_layout_option">Utseende</string>
<!-- EditSettings Activity Tabs -->
@@ -222,132 +222,132 @@
<string name="settings_tab_tag_xmpp">edit_settings_tab_xmpp</string>
<string name="settings_tab_label_xmpp">XMPP</string>
<string name="settings_tab_tag_proxy">edit_settings_tab_proxy</string>
-<string name="settings_tab_label_proxy">Proxy</string>
+<string name="settings_tab_label_proxy">Tjener</string>
<!-- wizard activities -->
-<string name="account_wizard_text1"><b>Willkommen bei BEEM.</b>nnDu hast noch kein XMPP (Jabber) Konto konfiguriert. Wähle eine der folgenden Optionen:</string>
-<string name="account_wizard_configure_text"><b>Bitte trage die Zugangsdaten für dein vorhandenes Konto ein</b></string>
-<string name="account_wizard_configure_account">Ich habe bereits ein Konto, das ich benutzen will</string>
-<string name="account_wizard_create_account">Ich möchte ein neues Konto registrieren</string>
+<string name="account_wizard_text1"><b>Velkomment til BEEM.</b>nnDu har ikke satt opp en XMPP (Jabber) konto.nVelg et av følgende alternativ :</string>
+<string name="account_wizard_configure_text"><b>Fyll inn informasjon for din eksisterende konto</b></string>
+<string name="account_wizard_configure_account">Jeg har en konto som jeg ønsker å bruke</string>
+<string name="account_wizard_create_account">Jeg ønsker å registrer en ny konto</string>
<!-- Create an account Activity -->
-<string name="create_account_instr_dialog_title">Konto erstellen - Anweisungen</string>
-<string name="create_account_err_dialog_title">Konto erstellen - Fehler</string>
-<string name="create_account_err_dialog_settings_button">Einstellungen ändern</string>
-<string name="create_account_close_dialog_button">Schließen</string>
-<string name="create_account_successfull_after">Das Konto %s wurde erfolgreich erstellt</string>
-<string name="create_account_err_username">Mangelhafte Jabber ID</string>
-<string name="create_account_err_passwords">Passwörter stimmen nicht überein.</string>
-<string name="create_account_username">Benutzername</string>
-<string name="create_account_password">Passwort</string>
-<string name="create_account_confirm_password">Passwort bestätigen</string>
+<string name="create_account_instr_dialog_title">Opprett en konto - Veiledning</string>
+<string name="create_account_err_dialog_title">Opprett en konto - Feil</string>
+<string name="create_account_err_dialog_settings_button">Endre innstillinger</string>
+<string name="create_account_close_dialog_button">Lukk</string>
+<string name="create_account_successfull_after">Konto %s opprettet</string>
+<string name="create_account_err_username">Ugyldig JabberID</string>
+<string name="create_account_err_passwords">Passordene er ikke like</string>
+<string name="create_account_username">Brukernavn</string>
+<string name="create_account_password">Passord</string>
+<string name="create_account_confirm_password">Bekreft passord</string>
<!-- ContactList Activity -->
-<string name="contact_list_menu_add_contact">Kontakt hinzufügen</string>
-<string name="contact_list_menu_status">Status ändern</string>
-<string name="contact_list_menu_settings">Einstellungen</string>
-<string name="contact_list_menu_disconnect">Verbindung trennen</string>
-<string name="contact_list_all_contact">Alle Kontakte</string>
-<string name="contact_list_no_group">Keine Gruppe</string>
+<string name="contact_list_menu_add_contact">Legg til kontakt</string>
+<string name="contact_list_menu_status">Endre status</string>
+<string name="contact_list_menu_settings">Innstillinger</string>
+<string name="contact_list_menu_disconnect">Koble fra</string>
+<string name="contact_list_all_contact">Alle kontakter</string>
+<string name="contact_list_no_group">Ingen gruppe</string>
<!-- UserInfo dialog -->
<string name="userinfo_label_alias">Alias</string>
-<string name="userinfo_label_chg_group">Gruppen verwalten</string>
-<string name="userinfo_label_re_subscription">Einladung erneut senden</string>
-<string name="userinfo_label_block">Sperren</string>
-<string name="userinfo_label_delete">Löschen</string>
-<string name="userinfo_resend">Zustimmung erneut senden</string>
+<string name="userinfo_label_chg_group">Behandle grupper</string>
+<string name="userinfo_label_re_subscription">Send invitasjon på nytt</string>
+<string name="userinfo_label_block">Blokker</string>
+<string name="userinfo_label_delete">Slett</string>
+<string name="userinfo_resend">Send abonnement på nytt</string>
<string name="userinfo_sure2delete">Are you sure you want to delete this contact?
</string>
<string name="userinfo_yes">Ja</string>
-<string name="userinfo_no">Nein</string>
-<string name="userinfo_sureresend">Bist du sicher, dass du die Einladung erneut senden willst?</string>
+<string name="userinfo_no">Nei</string>
+<string name="userinfo_sureresend">Sende invitasjon på nytt?</string>
-<string name="chat_name">Beem - Chat</string>
-<string name="chat_input_default_value">Nachricht eingeben</string>
-<string name="chat_self">Ich</string>
-<string name="chat_error">Fehler</string>
-<string name="chat_send_message">Senden</string>
+<string name="chat_name">Beep - Prat</string>
+<string name="chat_input_default_value">Skriv melding</string>
+<string name="chat_self">Meg</string>
+<string name="chat_error">Feil</string>
+<string name="chat_send_message">Send</string>
<string name="chat_menu_contacts_list">Kontaktliste</string>
-<string name="chat_menu_change_chat">Chat wechseln</string>
-<string name="chat_menu_start_otr_session">OTR Sitzung starten</string>
-<string name="chat_menu_stop_otr_session">OTR Sitzung beenden</string>
-<string name="chat_menu_otr_verify_key">OTR Schlüssel authentifizieren</string>
-<string name="chat_menu_otr_submenu">OTR Optionen</string>
-<string name="chat_dialog_change_chat_title">Offene Chats</string>
-<string name="chat_menu_close_chat">Diesen Chat schließen</string>
-<string name="chat_no_more_chats">Keine weiteren aktiven Chats</string>
-<string name="chat_state_composing">schreibt gerade</string>
-<string name="chat_state_gone">hat die Unterhaltung verlassen</string>
-<string name="chat_state_active">verfolgt die Unterhaltung</string>
-<string name="chat_state_inactive">macht etwas anderes</string>
-<string name="chat_otrstate_plaintext">KLARTEXT</string>
-<string name="chat_otrstate_encrypted">VERSCHLÜSSELT</string>
-<string name="chat_otrstate_finished">BEENDET</string>
-<string name="chat_otrstate_authenticated">AUTHENTIFIZIERT</string>
+<string name="chat_menu_change_chat">Veksle prateøkt</string>
+<string name="chat_menu_start_otr_session">Start OTR-økt</string>
+<string name="chat_menu_stop_otr_session">Stopp OTR-økt</string>
+<string name="chat_menu_otr_verify_key">OTR-kontrollnøkkel</string>
+<string name="chat_menu_otr_submenu">OTR-handlinger</string>
+<string name="chat_dialog_change_chat_title">Åpne prateøkter</string>
+<string name="chat_menu_close_chat">Lukk denne prateøkten</string>
+<string name="chat_no_more_chats">Ingen flere aktive prateøkter</string>
+<string name="chat_state_composing">skriver en melding</string>
+<string name="chat_state_gone">har lukket prateøkten</string>
+<string name="chat_state_active">følger med på prateøkten</string>
+<string name="chat_state_inactive">gjør noe annet</string>
+<string name="chat_otrstate_plaintext">KLARTEKST</string>
+<string name="chat_otrstate_encrypted">KRYPTERT</string>
+<string name="chat_otrstate_finished">AVSLUTTET</string>
+<string name="chat_otrstate_authenticated">AUTENTISERT</string>
<string name="chat_otr_verify_key" formatted="false">
Authenticating a buddy helps ensure that the person you are talking to is who they claim to be.\n\n
To verify the fingerprint, contact your buddy via some <i>other</i> authenticated channel, such as the telephone or GPG-signed email. Each of you should tell your fingerprint to the other.\n\n
If everything matches up, you should indicate in the above dialog that you <b>have</b> verified the fingerprint.\n\n
Local fingerprint %s\n\nRemote fingerprint %s\n\nVerify fingerprint ?</string>
-<string name="contact_status_msg_available">Online</string>
-<string name="contact_status_msg_available_chat">Bereit zum Chatten</string>
-<string name="contact_status_msg_dnd">Beschäftigt</string>
-<string name="contact_status_msg_away">Abwesend</string>
-<string name="contact_status_msg_xa">N/A</string>
-<string name="contact_status_msg_offline">Offline</string>
+<string name="contact_status_msg_available">Tilgjengelig</string>
+<string name="contact_status_msg_available_chat">Tilgjengelig for prat</string>
+<string name="contact_status_msg_dnd">Ikke forstyrr</string>
+<string name="contact_status_msg_away">Borte</string>
+<string name="contact_status_msg_xa">Ikke tilgjengelig</string>
+<string name="contact_status_msg_offline">Koblet fra</string>
-<string name="privacy_list_name">Beem - Meine Privatsphärenliste verwalten</string>
-<string name="privacy_list_no_data">Keine Privatsphärenliste vorhanden.</string>
-<string name="privacy_list_menu_create">Privatsphärenliste erstellen</string>
-<string name="privacy_list_create_dialog_title">Privatsphärenliste erstellen</string>
-<string name="privacy_list_create_dialog_list_name_label">Titel</string>
-<string name="privacy_list_create_dialog_create_button">Erstellen</string>
-<string name="privacy_list_select_dialog_buddies">Kontakte</string>
-<string name="privacy_list_select_dialog_groups">Gruppen</string>
-<string name="privacy_list_select_dialog_delete">Löschen</string>
-<string name="privacy_list_delete_dialog_msg">Bist du sicher, dass du die Privatsphärenliste mit dem Titel \'%s\' löschen willst?</string>
+<string name="privacy_list_name">Beem - Behandle personvernlister</string>
+<string name="privacy_list_no_data">Ingen registrerte personvernlister</string>
+<string name="privacy_list_menu_create">Opprett en personvernliste</string>
+<string name="privacy_list_create_dialog_title">Opprett en personvernliste</string>
+<string name="privacy_list_create_dialog_list_name_label">Tittel</string>
+<string name="privacy_list_create_dialog_create_button">Opprett</string>
+<string name="privacy_list_select_dialog_buddies">Kontakter</string>
+<string name="privacy_list_select_dialog_groups">Grupper</string>
+<string name="privacy_list_select_dialog_delete">Slett</string>
+<string name="privacy_list_delete_dialog_msg">Slette personvernliste \'%s\'?</string>
<string name="privacy_list_delete_dialog_yes">Ja</string>
-<string name="privacy_list_delete_dialog_no">Nein</string>
+<string name="privacy_list_delete_dialog_no">Nei</string>
-<string name="UpdateButton">Aktualisieren</string>
+<string name="UpdateButton">Oppdater</string>
<!-- MemorizingTrustManager library -->
-<string name="mtm_accept_cert">Unbekanntes Zertifikat akzeptieren?</string>
-<string name="mtm_decision_always">Immer</string>
-<string name="mtm_decision_once">Einmalig</string>
-<string name="mtm_decision_abort">Abbrechen</string>
+<string name="mtm_accept_cert">Godkjenn ukjent sertifikat</string>
+<string name="mtm_decision_always">Alltid</string>
+<string name="mtm_decision_once">Denne gangen</string>
+<string name="mtm_decision_abort">Avbryt</string>
-<string name="mtm_notification">Zertifikatprüfung</string>
+<string name="mtm_notification">Sertifikatkontroll</string>
<!-- Error messages -->
-<string name="error_login_authentication">Ein Fehler ist während der Authentifizierung aufgetreten: mangelhafter Benutzername oder Passwort.</string>
+<string name="error_login_authentication">Feil ved innlogging, feil brukernavn eller passord</string>
-<string name="interna_server_error">Remoteserver Fehler</string>
-<string name="bad_request">Mangelhafte Anfrage</string>
-<string name="forbidden">Verboten</string>
-<string name="item_not_found">Eintrag nicht gefunden</string>
-<string name="conflict">Konflikt</string>
-<string name="feature_not_implemented">Feature nicht vorhanden</string>
-<string name="gone">verloren</string>
-<string name="jid_malformed">JID mangelhaft</string>
-<string name="no_acceptable">nicht akzeptabel</string>
-<string name="not_allowed">nicht erlaubt</string>
-<string name="not_authorized">nicht authorisiert</string>
-<string name="payment_required">Bezahlung erforderlich</string>
-<string name="recipient_unavailable">Empfänger unerreichbar</string>
-<string name="redirect">weiterleiten</string>
-<string name="registration_required">Anmeldung wird benötigt</string>
-<string name="remote_server_not_found">Remoteserver nicht gefunden</string>
-<string name="remote_server_timeout">Keine Antwort vom Server</string>
-<string name="remote_server_error">Remoteserver Fehler</string>
-<string name="resource_constraint">Ressourcen Einschränkung</string>
-<string name="service_unavailable">Dienst unerreichbar</string>
-<string name="subscription_required">Zustimmung wird benötigt</string>
-<string name="undefined_condition">Undefinierte Bedingung</string>
-<string name="unexpected_condition">Unerwartete Bedingung</string>
-<string name="request_timeout">Zeitüberschreitung bei der Anfrage</string>
+<string name="interna_server_error">Remote server error</string>
+<string name="bad_request">bad-request</string>
+<string name="forbidden">forbidden</string>
+<string name="item_not_found">item-not-found</string>
+<string name="conflict">conflict</string>
+<string name="feature_not_implemented">feature-not-implemented</string>
+<string name="gone">gone</string>
+<string name="jid_malformed">jid-malformed</string>
+<string name="no_acceptable">no-acceptable</string>
+<string name="not_allowed">not-allowed</string>
+<string name="not_authorized">not-authorized</string>
+<string name="payment_required">payment-required</string>
+<string name="recipient_unavailable">recipient-unavailable</string>
+<string name="redirect">redirect</string>
+<string name="registration_required">registration-required</string>
+<string name="remote_server_not_found">Remote server not found</string>
+<string name="remote_server_timeout">No server response</string>
+<string name="remote_server_error">Remote server error</string>
+<string name="resource_constraint">resource-constraint</string>
+<string name="service_unavailable">service-unavailable</string>
+<string name="subscription_required">subscription-required</string>
+<string name="undefined_condition">undefined-condition</string>
+<string name="unexpected_condition">unexpected-condition</string>
+<string name="request_timeout">request-timeout</string>
</resources>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/res/values/attrs.xml Tue Jun 05 16:44:38 2012 +0200
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2011 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM 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 BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+-->
+<resources>
+ <declare-styleable name="SectionTextView">
+ <attr name="principalColor" format="color" />
+ <attr name="nonPrincipalColor" format="color" />
+ <attr name="principalLineSize" format="dimension" />
+ <attr name="nonPrincipalLineSize" format="dimension" />
+ </declare-styleable>
+</resources>
--- a/res/values/strings.xml Tue Jun 05 16:29:25 2012 +0200
+++ b/res/values/strings.xml Tue Jun 05 16:44:38 2012 +0200
@@ -90,6 +90,8 @@
</string>
<string name="CLP_hide_groups">Hide groups</string>
<string name="CLP_hide_groups_sum">Check this option to hide groups</string>
+ <string name="CLP_show_jid">Show JID</string>
+ <string name="CLP_show_jid_sum">Check this option to always show Contact\'s JID</string>
<string name="CLP_hidden_contact">Hide buddies</string>
<string name="CLP_hidden_contact_sum">Check this option to hide unconnected buddies
</string>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/res/xml/preferences.xml Tue Jun 05 16:44:38 2012 +0200
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2011 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM 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 BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+-->
+<!--
+ The format of the preference key is defined in
+ src/com/beem/project/beem/BeemApplication.java
+ Basically it is just a simple name like account_username.
+ TODO: There is still a lot of keys to convert
+-->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shouldDisableView="true" android:selectable="true">
+ <PreferenceCategory android:title="@string/general_preferences">
+ <PreferenceScreen android:key="contact_list"
+ android:title="@string/contact_list_preferences" android:summary="@string/contact_list_preferences_sum">
+ <CheckBoxPreference android:title="@string/CLP_hidden_contact"
+ android:defaultValue="false" android:summary="@string/CLP_hidden_contact_sum"
+ android:key="show_offline_contacts" />
+ <CheckBoxPreference android:title="@string/CLP_hide_groups"
+ android:defaultValue="false" android:summary="@string/CLP_hide_groups_sum"
+ android:key="hide_groups" />
+ <CheckBoxPreference android:title="@string/CLP_show_jid"
+ android:defaultValue="false" android:key="show_jid"
+ android:summary="@string/CLP_show_jid_sum"/>
+ <CheckBoxPreference android:title="@string/away_chk_title"
+ android:defaultValue="true" android:summary="@string/away_chk_sum"
+ android:key="use_auto_away" />
+ <EditTextPreference android:dependency="use_auto_away"
+ android:singleLine="true" android:summary="@string/away_message_sum"
+ android:title="@string/away_message_title" android:key="auto_away_msg"
+ android:hint="@string/away_message_hint" />
+ </PreferenceScreen>
+ <PreferenceScreen android:key="chat"
+ android:title="@string/chat_preferences" android:summary="@string/chat_preferences_sum">
+ <PreferenceCategory android:title="@string/history_preferences">
+ <CheckBoxPreference android:id="@+id/chat_history"
+ android:title="@string/history" android:summary="@string/history_sum"
+ android:defaultValue="false" android:key="settings_key_history" />
+ <EditTextPreference android:dependency="settings_key_history"
+ android:singleLine="true" android:title="@string/chat_history_path"
+ android:summary="@string/chat_history_path_sum" android:key="settings_chat_history_path"
+ android:hint="/Android/data/com.beem.project.beem/chat/" />
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/chat_layout_option">
+ <CheckBoxPreference android:title="@string/settings_chat_compact"
+ android:defaultValue="false" android:summary="@string/settings_chat_compact_sum"
+ android:key="use_compact_chat_ui" />
+ </PreferenceCategory>
+ </PreferenceScreen>
+ <PreferenceScreen android:title="@string/notification_preferences">
+ <CheckBoxPreference android:title="@string/notification_enable_vibrate_title"
+ android:defaultValue="true" android:summary="@string/notification_enable_vibrate_sum"
+ android:key="notification_vibrate" />
+ <RingtonePreference android:title="@string/notification_snd_title"
+ android:key="notification_sound" android:summary="@string/notification_snd_sum"
+ android:defaultValue="content://settings/system/notification_sound"
+ android:ringtoneType="notification" android:showDefault="true" />
+ </PreferenceScreen>
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/user_preferences">
+ <EditTextPreference android:singleLine="true"
+ android:summary="@string/SettingsText" android:title="@string/settings_account_username"
+ android:key="account_username" android:hint="@string/login_username_info_default"
+ android:inputType="textEmailAddress" />
+ <EditTextPreference android:name="password"
+ android:singleLine="true" android:password="true" android:summary="@string/SettingsPassword"
+ android:title="@string/settings_account_password" android:key="account_password" />
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/user_preferences_advanced">
+ <EditTextPreference android:key="connection_resource"
+ android:title="@string/SettingsResourceTitle" android:summary="@string/SettingsResourceSummary"
+ android:defaultValue="Beem" />
+ <EditTextPreference android:key="connection_priority"
+ android:title="@string/SettingsPriorityTitle" android:summary="@string/SettingsPrioritySummary"
+ android:numeric="signed" android:defaultValue="0" />
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/network_preferences">
+ <PreferenceScreen android:key="proxy" android:title="@string/SettingsProxy"
+ android:summary="@string/settings_proxy_sum">
+ <CheckBoxPreference android:title="@string/SettingsProxyProxy"
+ android:defaultValue="false" android:summary="@string/SettingsProxySummary"
+ android:key="proxy_use" />
+ <PreferenceCategory android:title="@string/proxy_proxy_settings">
+ <ListPreference android:dependency="proxy_use"
+ android:title="@string/SettingsProxyType" android:entries="@array/proxy_types"
+ android:summary="@string/SettingsProxyTypeSummary"
+ android:defaultValue="HTTP" android:entryValues="@array/proxy_types"
+ android:key="proxy_type" />
+ <EditTextPreference android:singleLine="true"
+ android:dependency="proxy_use" android:name="serveur"
+ android:summary="@string/SettingsProxyServer" android:title="@string/settings_proxy_server"
+ android:key="proxy_server" />
+ <EditTextPreference android:singleLine="true"
+ android:dependency="proxy_use" android:name="port"
+ android:summary="@string/SettingsProxyPort" android:title="@string/settings_proxy_port"
+ android:key="proxy_port" android:numeric="signed"
+ android:hint="@string/comments_proxy_port" />
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/proxy_user_settings">
+ <EditTextPreference android:singleLine="true"
+ android:dependency="proxy_use" android:name="Utilisateur"
+ android:summary="@string/SettingsProxyUser" android:title="@string/settings_proxy_username"
+ android:key="proxy_username" />
+ <EditTextPreference android:singleLine="true"
+ android:dependency="proxy_use" android:name="pass_user"
+ android:password="true" android:summary="@string/SettingsProxyPassword"
+ android:title="@string/settings_proxy_password" android:key="proxy_password" />
+ </PreferenceCategory>
+ </PreferenceScreen>
+
+ <PreferenceScreen android:key="advanced"
+ android:title="@string/SettingsAdvanced" android:summary="@string/settings_advanced_sum">
+ <PreferenceCategory android:title="@string/settings_advanced_service_behaviour">
+ <CheckBoxPreference android:title="@string/settings_xmpp_use_tls"
+ android:defaultValue="false" android:key="settings_key_xmpp_tls_use" />
+ <CheckBoxPreference android:title="@string/settings_smack_debug"
+ android:defaultValue="false" android:key="smack_debug" />
+ <EditTextPreference android:singleLine="true"
+ android:title="@string/settings_reco_delay" android:name="Reconnect delay"
+ android:summary="@string/SettingsAdvancedRecoDelay" android:key="settings_key_reco_delay"
+ android:defaultValue="10" />
+ </PreferenceCategory>
+ <CheckBoxPreference android:title="@string/SettingsAdvancedOptions"
+ android:defaultValue="false" android:summary="@string/SettingsAdvancedSpecOpt"
+ android:key="settings_key_specific_server" />
+ <EditTextPreference android:singleLine="true"
+ android:dependency="settings_key_specific_server" android:name="adresse"
+ android:summary="@string/SettingsAdvancedAddOpt" android:title="@string/settings_xmpp_server"
+ android:key="settings_key_xmpp_server" android:hint="@string/comments_xmpp_server" />
+ <EditTextPreference android:singleLine="true"
+ android:dependency="settings_key_specific_server" android:name="port"
+ android:summary="@string/SettingsAdvancedPortOpt" android:title="@string/settings_xmpp_port"
+ android:defaultValue="5222" android:numeric="signed" android:key="settings_key_xmpp_port"
+ android:hint="@string/comments_xmpp_port" />
+ <CheckBoxPreference android:title="@string/settings_full_jid_login"
+ android:defaultValue="false" android:summary="@string/settings_full_jid_login_sum"
+ android:key="full_jid_login" />
+ </PreferenceScreen>
+ </PreferenceCategory>
+</PreferenceScreen>
--- a/src/com/beem/project/beem/BeemApplication.java Tue Jun 05 16:29:25 2012 +0200
+++ b/src/com/beem/project/beem/BeemApplication.java Tue Jun 05 16:44:38 2012 +0200
@@ -103,6 +103,8 @@
public static final String USE_COMPACT_CHAT_UI_KEY = "use_compact_chat_ui";
/** Preference key for history path on the SDCard. */
public static final String CHAT_HISTORY_KEY = "settings_chat_history_path";
+ /** Preference key to show the jid in the contact list. */
+ public static final String SHOW_JID = "show_jid";
//TODO add the other one
--- a/src/com/beem/project/beem/BeemService.java Tue Jun 05 16:29:25 2012 +0200
+++ b/src/com/beem/project/beem/BeemService.java Tue Jun 05 16:44:38 2012 +0200
@@ -215,6 +215,7 @@
mPort = DEFAULT_XMPP_PORT;
mService = StringUtils.parseServer(tmpJid);
mHost = mService;
+ initMemorizingTrustManager();
if (mSettings.getBoolean("settings_key_specific_server", false)) {
mHost = mSettings.getString("settings_key_xmpp_server", "").trim();
@@ -350,10 +351,8 @@
/**
* Install the MemorizingTrustManager in the ConnectionConfiguration of Smack.
- *
- * @param config the configuration to modify
*/
- private void initMemorizingTrustManager(ConnectionConfiguration config) {
+ private void initMemorizingTrustManager() {
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, MemorizingTrustManager.getInstanceList(this),
--- a/src/com/beem/project/beem/service/XmppConnectionAdapter.java Tue Jun 05 16:29:25 2012 +0200
+++ b/src/com/beem/project/beem/service/XmppConnectionAdapter.java Tue Jun 05 16:44:38 2012 +0200
@@ -40,7 +40,7 @@
Flavien Astraud, November 26, 2009
Head of the EIP Laboratory.
-*/
+ */
package com.beem.project.beem.service;
import java.util.Iterator;
@@ -119,8 +119,7 @@
private BeemAvatarManager mAvatarManager;
private PepSubManager mPepManager;
private SharedPreferences mPref;
- private final RemoteCallbackList<IBeemConnectionListener> mRemoteConnListeners =
- new RemoteCallbackList<IBeemConnectionListener>();
+ private final RemoteCallbackList<IBeemConnectionListener> mRemoteConnListeners = new RemoteCallbackList<IBeemConnectionListener>();
private final SubscribePacketListener mSubscribePacketListener = new SubscribePacketListener();
private final PingListener mPingListener = new PingListener();
@@ -136,8 +135,8 @@
* @param password password to use on connect
* @param service the background service associated with the connection.
*/
- public XmppConnectionAdapter(final ConnectionConfiguration config,
- final String login, final String password, final BeemService service) {
+ public XmppConnectionAdapter(final ConnectionConfiguration config, final String login, final String password,
+ final BeemService service) {
this(new XMPPConnection(config), login, password, service);
}
@@ -148,8 +147,8 @@
* @param password password to use on connect
* @param service the background service associated with the connection.
*/
- public XmppConnectionAdapter(final String serviceName,
- final String login, final String password, final BeemService service) {
+ public XmppConnectionAdapter(final String serviceName, final String login, final String password,
+ final BeemService service) {
this(new XMPPConnection(serviceName), login, password, service);
}
@@ -160,8 +159,8 @@
* @param password The password to use
* @param service the background service associated with the connection.
*/
- public XmppConnectionAdapter(final XMPPConnection con,
- final String login, final String password, final BeemService service) {
+ public XmppConnectionAdapter(final XMPPConnection con, final String login, final String password,
+ final BeemService service) {
mAdaptee = con;
PrivacyListManager.getInstanceFor(mAdaptee);
mLogin = login;
@@ -203,8 +202,8 @@
try {
//TODO NIKITA DOES SOME SHIT !!! Fix this monstruosity
String str = mService.getResources().getString(
- mService.getResources().getIdentifier(
- e.getXMPPError().getCondition().replace("-", "_"), "string", "com.beem.project.beem"));
+ mService.getResources().getIdentifier(e.getXMPPError().getCondition().replace("-", "_"),
+ "string", "com.beem.project.beem"));
mErrorMsg = str;
} catch (NullPointerException e2) {
if (!"".equals(e.getMessage()))
@@ -328,7 +327,7 @@
mPreviousPriority = p;
pres.setPriority(p);
mAdaptee.sendPacket(pres);
- updateNotification(m);
+ updateNotification(Status.getStatusFromPresence(pres), m);
}
/**
@@ -341,7 +340,6 @@
/**
* Get the AvatarManager of this connection.
- *
* @return the AvatarManager or null if there is not
*/
public BeemAvatarManager getAvatarManager() {
@@ -366,17 +364,17 @@
/**
* Update the notification for the Beem status.
+ * @param status the status to display.
* @param text the text to display.
*/
- private void updateNotification(String text) {
+ private void updateNotification(int status, String text) {
Notification mStatusNotification;
- mStatusNotification = new Notification(com.beem.project.beem.R.drawable.beem_status_icon, text, System
- .currentTimeMillis());
+ mStatusNotification = new Notification(Status.getIconBarFromStatus(status), text, System.currentTimeMillis());
mStatusNotification.defaults = Notification.DEFAULT_LIGHTS;
mStatusNotification.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
- mStatusNotification.setLatestEventInfo(mService, "Beem Status", text, PendingIntent.getActivity(mService, 0,
- new Intent(mService, ChangeStatus.class), 0));
+ mStatusNotification.setLatestEventInfo(mService, "Beem Status", text,
+ PendingIntent.getActivity(mService, 0, new Intent(mService, ChangeStatus.class), 0));
// bypass the preferences for notification
mService.getNotificationManager().notify(BeemService.NOTIFICATION_STATUS_ID, mStatusNotification);
}
@@ -423,7 +421,6 @@
/**
* Get the user informations.
- *
* @return the user infos or null if not logged
*/
public UserInfo getUserInfo() {
@@ -679,13 +676,14 @@
R.string.AcceptContactRequest, from), System.currentTimeMillis());
notif.flags = Notification.FLAG_AUTO_CANCEL;
Intent intent = new Intent(mService, Subscription.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .putExtra("from", from);
- notif.setLatestEventInfo(mService, from, mService
- .getString(R.string.AcceptContactRequestFrom, from), PendingIntent.getActivity(mService, 0,
- intent, PendingIntent.FLAG_ONE_SHOT));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).putExtra("from", from);
+ notif.setLatestEventInfo(mService, from,
+ mService.getString(R.string.AcceptContactRequestFrom, from),
+ PendingIntent.getActivity(mService, 0, intent, PendingIntent.FLAG_ONE_SHOT));
int id = packet.hashCode();
mService.sendNotification(id, notif);
+ Presence p = (Presence) packet;
+ updateNotification(Status.getStatusFromPresence(p), p.getStatus());
}
}, filter);
@@ -731,9 +729,9 @@
notification.flags = Notification.FLAG_AUTO_CANCEL;
Intent intent = new Intent(mService, Subscription.class);
intent.setData(Contact.makeXmppUri(from));
- notification.setLatestEventInfo(mService, from, mService
- .getString(R.string.AcceptContactRequestFrom, from), PendingIntent.getActivity(mService, 0,
- intent, PendingIntent.FLAG_ONE_SHOT));
+ notification.setLatestEventInfo(mService, from,
+ mService.getString(R.string.AcceptContactRequestFrom, from),
+ PendingIntent.getActivity(mService, 0, intent, PendingIntent.FLAG_ONE_SHOT));
int id = p.hashCode();
mService.sendNotification(id, notification);
}
@@ -761,11 +759,17 @@
}
/**
- * Listener for Ping request.
- * It will respond with a Pong.
+ * Listener for Ping request. It will respond with a Pong.
*/
private class PingListener implements PacketListener {
+ /**
+ * Constructor.
+ */
+ public PingListener() {
+
+ }
+
@Override
public void processPacket(Packet packet) {
if (!(packet instanceof PingExtension))
--- a/src/com/beem/project/beem/ui/Chat.java Tue Jun 05 16:29:25 2012 +0200
+++ b/src/com/beem/project/beem/ui/Chat.java Tue Jun 05 16:44:38 2012 +0200
@@ -52,9 +52,6 @@
import java.util.List;
import java.util.Map;
-import org.jivesoftware.smack.packet.Presence.Mode;
-import org.jivesoftware.smack.util.StringUtils;
-
import android.app.Activity;
import android.app.Dialog;
import android.content.ComponentName;
@@ -62,6 +59,7 @@
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
@@ -81,8 +79,9 @@
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
-import android.view.View.OnClickListener;
+import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.BaseAdapter;
import android.widget.Button;
@@ -109,6 +108,10 @@
import com.beem.project.beem.utils.BeemBroadcastReceiver;
import com.beem.project.beem.utils.Status;
+import org.jivesoftware.smack.packet.Presence.Mode;
+import org.jivesoftware.smack.util.StringUtils;
+
+
/**
* This class represents an activity which allows the user to chat with his/her contacts.
* @author Jean-Manuel Da Silva <dasilvj at beem-project dot com>
@@ -167,6 +170,11 @@
super.onCreate(savedBundle);
this.registerReceiver(mBroadcastReceiver, new IntentFilter(BeemBroadcastReceiver.BEEM_CONNECTION_CLOSED));
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
+
+ if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ }
+
mCompact = settings.getBoolean(BeemApplication.USE_COMPACT_CHAT_UI_KEY, false);
// UI
if (!mCompact) {
@@ -437,6 +445,165 @@
return result;
}
+
+ /**
+ * {@inheritDoc}.
+ */
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (v == mInputField && actionId == EditorInfo.IME_ACTION_SEND) {
+ sendMessage();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Send an XMPP message.
+ */
+ private void sendMessage() {
+ final String inputContent = mInputField.getText().toString();
+
+ if (!"".equals(inputContent)) {
+ Message msgToSend = new Message(mContact.getJIDWithRes(), Message.MSG_TYPE_CHAT);
+ msgToSend.setBody(inputContent);
+
+ try {
+ if (mChat == null) {
+ mChat = mChatManager.createChat(mContact, mMessageListener);
+ mChat.setOpen(true);
+ }
+ mChat.sendMessage(msgToSend);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.getMessage());
+ }
+
+ final String self = getString(R.string.chat_self);
+ MessageText lastMessage = null;
+ if (mListMessages.size() != 0)
+ lastMessage = mListMessages.get(mListMessages.size() - 1);
+
+ if (lastMessage != null && lastMessage.getName().equals(self)) {
+ lastMessage.setMessage(lastMessage.getMessage().concat("\n" + inputContent));
+ lastMessage.setTimestamp(new Date());
+ } else
+ mListMessages.add(new MessageText(self, self, inputContent, false, new Date()));
+ mMessagesListAdapter.notifyDataSetChanged();
+ mInputField.setText(null);
+ }
+ }
+
+
+ /**
+ * Update the contact informations.
+ */
+ private void updateContactInformations() {
+ // Check for a contact name update
+ String name = mContact.getName();
+ String res = mContact.getSelectedRes();
+ if (!"".equals(res))
+ name += "(" + res + ")";
+ if (!mCompact) {
+ if (!(mContactNameTextView.getText().toString().equals(name)))
+ mContactNameTextView.setText(name);
+ //Check for a contact status message update
+ if (!(mContactStatusMsgTextView.getText().toString().equals(mContact.getMsgState()))) {
+ mContactStatusMsgTextView.setText(mContact.getMsgState());
+ Linkify.addLinks(mContactStatusMsgTextView, Linkify.WEB_URLS);
+ }
+ } else {
+ Mode m = Status.getPresenceModeFromStatus(mContact.getStatus());
+ if (m == null)
+ setTitle(getString(R.string.chat_name) + " " + name + " ("
+ + getString(R.string.contact_status_msg_offline) + ")");
+ else
+ setTitle(getString(R.string.chat_name) + " " + name + " (" + m.name() + ")");
+ }
+ }
+
+ /**
+ * Update the OTR informations.
+ * @param otrState the otr state
+ */
+ private void updateOtrInformations(final String otrState) {
+ String text = null;
+ if ("ENCRYPTED".equals(otrState)) {
+ text = Chat.this.getString(R.string.chat_otrstate_encrypted);
+ } else if ("FINISHED".equals(otrState)) {
+ text = Chat.this.getString(R.string.chat_otrstate_finished);
+ } else if ("AUTHENTICATED".equals(otrState)) {
+ text = Chat.this.getString(R.string.chat_otrstate_authenticated);
+ } else {
+ text = Chat.this.getString(R.string.chat_otrstate_plaintext);
+ }
+ if (mContactOtrState != null)
+ mContactOtrState.setText(text);
+ }
+
+ /**
+ * Update the contact status icon.
+ */
+ private void updateContactStatusIcon() {
+ if (mCompact)
+ return;
+ String id = mContact.getAvatarId();
+ if (id == null)
+ id = "";
+ Log.d(TAG, "update contact icon : " + id);
+ if (!id.equals(mCurrentAvatarId)) {
+ Drawable avatar = getAvatarDrawable(mContact.getAvatarId());
+ mAvatarStatusDrawable.setDrawableByLayerId(R.id.avatar, avatar);
+ mCurrentAvatarId = id;
+ }
+ mContactStatusIcon.setImageLevel(mContact.getStatus());
+ }
+
+ /**
+ * Get a Drawable containing the avatar icon.
+ * @param avatarId the avatar id to retrieve or null to get default
+ * @return a Drawable
+ */
+ private Drawable getAvatarDrawable(String avatarId) {
+ Drawable avatarDrawable = null;
+ if (avatarId != null) {
+ Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build();
+ InputStream in = null;
+ try {
+ try {
+ in = getContentResolver().openInputStream(uri);
+ avatarDrawable = Drawable.createFromStream(in, avatarId);
+ } finally {
+ if (in != null)
+ in.close();
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Error while setting the avatar", e);
+ }
+ }
+ if (avatarDrawable == null)
+ avatarDrawable = getResources().getDrawable(R.drawable.beem_launcher_icon_silver);
+ return avatarDrawable;
+ }
+
+ /**
+ * Prepare the status icons map.
+ */
+ private void prepareIconsStatus() {
+ mStatusIconsMap.put(Status.CONTACT_STATUS_AVAILABLE,
+ BitmapFactory.decodeResource(getResources(), android.R.drawable.presence_online));
+ mStatusIconsMap.put(Status.CONTACT_STATUS_AVAILABLE_FOR_CHAT,
+ BitmapFactory.decodeResource(getResources(), android.R.drawable.presence_online));
+ mStatusIconsMap.put(Status.CONTACT_STATUS_AWAY,
+ BitmapFactory.decodeResource(getResources(), android.R.drawable.presence_away));
+ mStatusIconsMap.put(Status.CONTACT_STATUS_BUSY,
+ BitmapFactory.decodeResource(getResources(), android.R.drawable.presence_busy));
+ mStatusIconsMap.put(Status.CONTACT_STATUS_DISCONNECT,
+ BitmapFactory.decodeResource(getResources(), android.R.drawable.presence_offline));
+ mStatusIconsMap.put(Status.CONTACT_STATUS_UNAVAILABLE,
+ BitmapFactory.decodeResource(getResources(), R.drawable.status_requested));
+ }
+
+
/**
* {@inheritDoc}.
*/
@@ -623,115 +790,6 @@
}
/**
- * Update the contact informations.
- */
- private void updateContactInformations() {
- // Check for a contact name update
- String name = mContact.getName();
- String res = mContact.getSelectedRes();
- if (!"".equals(res))
- name += "(" + res + ")";
- if (!mCompact) {
- if (!(mContactNameTextView.getText().toString().equals(name)))
- mContactNameTextView.setText(name);
- //Check for a contact status message update
- if (!(mContactStatusMsgTextView.getText().toString().equals(mContact.getMsgState()))) {
- mContactStatusMsgTextView.setText(mContact.getMsgState());
- Linkify.addLinks(mContactStatusMsgTextView, Linkify.WEB_URLS);
- }
- } else {
- Mode m = Status.getPresenceModeFromStatus(mContact.getStatus());
- if (m == null)
- setTitle(getString(R.string.chat_name) + " " + name + " ("
- + getString(R.string.contact_status_msg_offline) + ")");
- else
- setTitle(getString(R.string.chat_name) + " " + name + " (" + m.name() + ")");
- }
- }
-
- /**
- * Update the OTR informations.
- * @param otrState the otr state
- */
- private void updateOtrInformations(final String otrState) {
- String text = null;
- if ("ENCRYPTED".equals(otrState)) {
- text = Chat.this.getString(R.string.chat_otrstate_encrypted);
- } else if ("FINISHED".equals(otrState)) {
- text = Chat.this.getString(R.string.chat_otrstate_finished);
- } else if ("AUTHENTICATED".equals(otrState)) {
- text = Chat.this.getString(R.string.chat_otrstate_authenticated);
- } else {
- text = Chat.this.getString(R.string.chat_otrstate_plaintext);
- }
- if (mContactOtrState != null)
- mContactOtrState.setText(text);
- }
-
- /**
- * Update the contact status icon.
- */
- private void updateContactStatusIcon() {
- if (mCompact)
- return;
- String id = mContact.getAvatarId();
- if (id == null)
- id = "";
- Log.d(TAG, "update contact icon : " + id);
- if (!id.equals(mCurrentAvatarId)) {
- Drawable avatar = getAvatarDrawable(mContact.getAvatarId());
- mAvatarStatusDrawable.setDrawableByLayerId(R.id.avatar, avatar);
- mCurrentAvatarId = id;
- }
- mContactStatusIcon.setImageLevel(mContact.getStatus());
- }
-
- /**
- * Get a Drawable containing the avatar icon.
- * @param avatarId the avatar id to retrieve or null to get default
- * @return a Drawable
- */
- private Drawable getAvatarDrawable(String avatarId) {
- Drawable avatarDrawable = null;
- if (avatarId != null) {
- Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build();
- InputStream in = null;
- try {
- try {
- in = getContentResolver().openInputStream(uri);
- avatarDrawable = Drawable.createFromStream(in, avatarId);
- } finally {
- if (in != null)
- in.close();
- }
- } catch (IOException e) {
- Log.w(TAG, "Error while setting the avatar", e);
- }
- }
- if (avatarDrawable == null)
- avatarDrawable = getResources().getDrawable(R.drawable.beem_launcher_icon_silver);
- return avatarDrawable;
- }
-
- /**
- * Prepare the status icons map.
- */
- private void prepareIconsStatus() {
- mStatusIconsMap.put(Status.CONTACT_STATUS_AVAILABLE,
- BitmapFactory.decodeResource(getResources(), android.R.drawable.presence_online));
- mStatusIconsMap.put(Status.CONTACT_STATUS_AVAILABLE_FOR_CHAT,
- BitmapFactory.decodeResource(getResources(), android.R.drawable.presence_online));
- mStatusIconsMap.put(Status.CONTACT_STATUS_AWAY,
- BitmapFactory.decodeResource(getResources(), android.R.drawable.presence_away));
- mStatusIconsMap.put(Status.CONTACT_STATUS_BUSY,
- BitmapFactory.decodeResource(getResources(), android.R.drawable.presence_busy));
- mStatusIconsMap.put(Status.CONTACT_STATUS_DISCONNECT,
- BitmapFactory.decodeResource(getResources(), android.R.drawable.presence_offline));
- mStatusIconsMap.put(Status.CONTACT_STATUS_UNAVAILABLE,
- BitmapFactory.decodeResource(getResources(), R.drawable.status_requested));
- }
-
- /**
* {@inheritDoc}.
*/
private class MessagesListAdapter extends BaseAdapter {
@@ -942,53 +1000,6 @@
}
/**
- * {@inheritDoc}.
- */
- @Override
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (v == mInputField && actionId == EditorInfo.IME_ACTION_SEND) {
- sendMessage();
- return true;
- }
- return false;
- }
-
- /**
- * Send an XMPP message.
- */
- private void sendMessage() {
- final String inputContent = mInputField.getText().toString();
-
- if (!"".equals(inputContent)) {
- Message msgToSend = new Message(mContact.getJIDWithRes(), Message.MSG_TYPE_CHAT);
- msgToSend.setBody(inputContent);
-
- try {
- if (mChat == null) {
- mChat = mChatManager.createChat(mContact, mMessageListener);
- mChat.setOpen(true);
- }
- mChat.sendMessage(msgToSend);
- } catch (RemoteException e) {
- Log.e(TAG, e.getMessage());
- }
-
- final String self = getString(R.string.chat_self);
- MessageText lastMessage = null;
- if (mListMessages.size() != 0)
- lastMessage = mListMessages.get(mListMessages.size() - 1);
-
- if (lastMessage != null && lastMessage.getName().equals(self)) {
- lastMessage.setMessage(lastMessage.getMessage().concat("\n" + inputContent));
- lastMessage.setTimestamp(new Date());
- } else
- mListMessages.add(new MessageText(self, self, inputContent, false, new Date()));
- mMessagesListAdapter.notifyDataSetChanged();
- mInputField.setText(null);
- }
- }
-
- /**
* This class is in charge of getting the new chat in the activity if someone talk to you.
*/
private class ChatManagerListener extends IChatManagerListener.Stub {
--- a/src/com/beem/project/beem/ui/ContactList.java Tue Jun 05 16:29:25 2012 +0200
+++ b/src/com/beem/project/beem/ui/ContactList.java Tue Jun 05 16:44:38 2012 +0200
@@ -44,31 +44,27 @@
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
import java.util.Map;
-import java.io.InputStream;
-import java.io.IOException;
-import org.jivesoftware.smack.util.StringUtils;
-
-import android.app.Activity;
import android.app.Dialog;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
-import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
import android.util.Log;
-import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -77,22 +73,13 @@
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
-import android.widget.Filter;
-import android.widget.Filterable;
import android.widget.Gallery;
-import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
+import com.beem.project.beem.BeemApplication;
import com.beem.project.beem.R;
-import com.beem.project.beem.BeemApplication;
-import com.beem.project.beem.providers.AvatarProvider;
import com.beem.project.beem.service.Contact;
import com.beem.project.beem.service.PresenceAdapter;
import com.beem.project.beem.service.aidl.IBeemRosterListener;
@@ -103,14 +90,15 @@
import com.beem.project.beem.ui.dialogs.builders.ChatList;
import com.beem.project.beem.ui.dialogs.builders.DeleteContact;
import com.beem.project.beem.ui.dialogs.builders.ResendSubscription;
+import com.beem.project.beem.ui.views.SectionTextView;
import com.beem.project.beem.utils.BeemBroadcastReceiver;
-import com.beem.project.beem.utils.SortedList;
-import com.beem.project.beem.utils.Status;
+
+import org.jivesoftware.smack.util.StringUtils;
/**
* The contact list activity displays the roster of the user.
*/
-public class ContactList extends Activity {
+public class ContactList extends FragmentActivity {
private static final Intent SERVICE_INTENT = new Intent();
static {
@@ -118,30 +106,27 @@
}
private static final String TAG = "ContactList";
- private final BeemContactList mAdapterContactList = new BeemContactList();
- private final List<String> mListGroup = new ArrayList<String>();
+ private final List<GroupHolder> mListGroup = new ArrayList<GroupHolder>();
/** Map containing a list of the different contacts of a given group.
* Each list is a @{link SortedList} so there is no need to sort it again.
* */
private final Map<String, List<Contact>> mContactOnGroup = new HashMap<String, List<Contact>>();
- private final BeemContactListOnClick mOnContactClick = new BeemContactListOnClick();
- private final Handler mHandler = new Handler();
private final ServiceConnection mServConn = new BeemServiceConnection();
private final BeemBroadcastReceiver mReceiver = new BeemBroadcastReceiver();
- private final ComparatorContactListByStatusAndName<Contact> mComparator =
- new ComparatorContactListByStatusAndName<Contact>();
+ private final BeemBanner mAdapterBanner = new BeemBanner();
+ private final Map<String, ContactListAdapter> contactListAdapters = new HashMap<String, ContactListAdapter>();
+
private final BeemRosterListener mBeemRosterListener = new BeemRosterListener();
- private List<Contact> mListContact;
- private String mSelectedGroup;
private IRoster mRoster;
- private Contact mSelectedContact;
private IXmppFacade mXmppFacade;
private IChatManager mChatManager;
private SharedPreferences mSettings;
private LayoutInflater mInflater;
- private BeemBanner mAdapterBanner;
private boolean mBinded;
+ private ViewPager viewPager;
+ private ListPagerAdapter groupsPagesAdapter;
+ private Gallery groupGallery;
/**
* Constructor.
@@ -195,92 +180,6 @@
}
@Override
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.contactlist_context, menu);
- AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
- Contact c = mListContact.get(info.position);
- try {
- mSelectedContact = mRoster.getContact(c.getJID());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- menu.setHeaderTitle(mSelectedContact.getJID());
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- Intent in;
- boolean result;
- if (mSelectedContact != null) {
- switch (item.getItemId()) {
- case R.id.contact_list_context_menu_chat_item:
- List<String> res = mSelectedContact.getMRes();
- if (res.isEmpty()) {
- result = false;
- break;
- }
- for (String resv : res) {
- in = new Intent(this, Chat.class);
- in.setData(mSelectedContact.toUri(resv));
- item.getSubMenu().add(resv).setIntent(in);
- }
- result = true;
- break;
- case R.id.contact_list_context_menu_call_item:
- res = mSelectedContact.getMRes();
- if (res.isEmpty()) {
- result = false;
- break;
- }
- for (String resv : res) {
- in = new Intent(this, Call.class);
- in.setData(mSelectedContact.toUri(resv));
- in.putExtra("isCaller", true);
- item.getSubMenu().add(resv).setIntent(in);
- }
- result = true;
- break;
- case R.id.contact_list_context_menu_user_info:
- item.getSubMenu().setHeaderTitle(mSelectedContact.getJID());
- result = true;
- break;
- case R.id.contact_list_context_menu_userinfo_alias:
- Dialog alias = new Alias(ContactList.this, mRoster, mSelectedContact).create();
- alias.show();
- result = true;
- break;
- case R.id.contact_list_context_menu_userinfo_group:
- in = new Intent(this, GroupList.class);
- in.putExtra("contact", mSelectedContact);
- startActivity(in);
- result = true;
- break;
- case R.id.contact_list_context_menu_userinfo_subscription:
- Dialog subscription = new ResendSubscription(ContactList.this,
- mXmppFacade, mSelectedContact).create();
- subscription.show();
- result = true;
- break;
- case R.id.contact_list_context_menu_userinfo_block:
- result = true;
- break;
- case R.id.contact_list_context_menu_userinfo_delete:
- Dialog delete = new DeleteContact(ContactList.this, mRoster, mSelectedContact).create();
- delete.show();
- result = true;
- break;
- default:
- result = super.onContextItemSelected(item);
- break;
- }
- return result;
- }
- return super.onContextItemSelected(item);
- }
-
- @Override
protected void onCreate(Bundle saveBundle) {
super.onCreate(saveBundle);
mSettings = PreferenceManager.getDefaultSharedPreferences(this);
@@ -289,17 +188,24 @@
this.registerReceiver(mReceiver, new IntentFilter(BeemBroadcastReceiver.BEEM_CONNECTION_CLOSED));
mInflater = getLayoutInflater();
- mAdapterBanner = new BeemBanner(mInflater, mListGroup);
- mListContact = new ArrayList<Contact>();
- ListView listView = (ListView) findViewById(R.id.contactlist);
- listView.setOnItemClickListener(mOnContactClick);
- registerForContextMenu(listView);
- listView.setAdapter(mAdapterContactList);
+
+ viewPager = (ViewPager) findViewById(R.id.pager);
+ viewPager.setOnPageChangeListener(new OnPageChangeListener());
+ groupsPagesAdapter = new ListPagerAdapter(getSupportFragmentManager(), viewPager);
+
+ mListGroup.add(new GroupHolder(getString(R.string.contact_list_all_contact)));
+ mListGroup.add(new GroupHolder(getString(R.string.contact_list_no_group)));
+ mAdapterBanner.notifyDataSetChanged();
}
@Override
- protected void onResume() {
- super.onResume();
+ protected void onStart() {
+ super.onStart();
+ if (!mSettings.getBoolean(BeemApplication.HIDE_GROUPS_KEY, false))
+ showGroups();
+ else
+ hideGroups();
+
if (!mBinded)
mBinded = bindService(SERVICE_INTENT, mServConn, BIND_AUTO_CREATE);
}
@@ -333,14 +239,75 @@
}
/**
- * Build and display the contact list.
- * @param group name of the contact list.
+ * Get a {@link ContactListAdapter} for a group.
+ * The {@link ContactListAdapter} will be created if it is not exist.
+ * @param group the group
+ * @return the adapter
*/
- private void buildContactList(String group) {
- mListContact = mContactOnGroup.get(group);
- mSelectedGroup = group;
- Log.d(TAG, "buildContactList for group " + group);
- mAdapterContactList.notifyDataSetChanged();
+ ContactListAdapter getContactListAdapter(String group) {
+ synchronized (contactListAdapters) {
+ ContactListAdapter contactListAdapter = contactListAdapters.get(group);
+ if (contactListAdapter == null) {
+ contactListAdapter = new ContactListAdapter(ContactList.this);
+ contactListAdapters.put(group, contactListAdapter);
+ List<GroupHolder> realGroups = mListGroup.subList(1, mListGroup.size() - 1);
+ if (!GroupHolder.contains(mListGroup, group)) {
+ GroupHolder gh = new GroupHolder(group);
+ boolean added = false;
+ // insert group in sorted list
+ for (ListIterator<GroupHolder> iterator = realGroups.listIterator(); iterator.hasNext();) {
+ GroupHolder currentGroup = (GroupHolder) iterator.next();
+ if (currentGroup.group.compareTo(group) > 0) {
+ iterator.previous();
+ iterator.add(gh);
+ added = true;
+ break;
+ }
+ }
+ if (!added)
+ realGroups.add(gh);
+ groupsPagesAdapter.notifyDataSetChanged();
+ mAdapterBanner.notifyDataSetChanged();
+ }
+ }
+ boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
+ contactListAdapter.setOnlineOnly(hideDisconnected);
+ return contactListAdapter;
+ }
+ }
+
+ /**
+ * Exectute a context menu action on a specified contact.
+ * @param itemId the id of the menu action
+ * @param contact the contact
+ */
+ void doContextMenuAction(int itemId, Contact contact) {
+ switch (itemId) {
+ case R.id.contact_list_context_menu_call_item:
+ try {
+ mXmppFacade.call(contact.getJID() + "/psi");
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ break;
+ case R.id.contact_list_context_menu_userinfo_alias:
+ Dialog alias = new Alias(ContactList.this, mRoster, contact).create();
+ alias.show();
+ break;
+ case R.id.contact_list_context_menu_userinfo_subscription:
+ Dialog subscription = new ResendSubscription(ContactList.this,
+ mXmppFacade, contact).create();
+ subscription.show();
+ break;
+ case R.id.contact_list_context_menu_userinfo_delete:
+ Dialog delete = new DeleteContact(ContactList.this, mRoster, contact).create();
+ delete.show();
+ break;
+ default:
+ Log.w(TAG, "Context menu action not supported" + itemId);
+ break;
+ }
+
}
/**
@@ -351,15 +318,16 @@
ViewStub stub = (ViewStub) findViewById(R.id.contactlist_stub);
if (stub != null) {
View v = stub.inflate();
- Gallery g = (Gallery) v.findViewById(R.id.contactlist_banner);
- g.setOnItemClickListener(new OnItemClickGroupName());
- g.setAdapter(mAdapterBanner);
- g.setSelection(0);
+ groupGallery = (Gallery) v.findViewById(R.id.contactlist_banner);
+ groupGallery.setOnItemClickListener(new OnItemClickGroupName());
+ groupGallery.setAdapter(mAdapterBanner);
+ groupGallery.setSelection(0);
} else {
((LinearLayout) findViewById(R.id.contactlist_groupstub)).setVisibility(View.VISIBLE);
- Gallery g = (Gallery) findViewById(R.id.contactlist_banner);
- g.setSelection(0);
+ groupGallery = (Gallery) findViewById(R.id.contactlist_banner);
+ groupGallery.setSelection(0);
}
+ GroupHolder.setUniquePrincipal(mListGroup, 0);
}
/**
@@ -372,6 +340,42 @@
}
/**
+ * Remove old groups on the banner.
+ * @throws RemoteException if an error occur when communicating with the service
+ */
+ private void cleanBannerGroup() throws RemoteException {
+ if (mListGroup.size() <= 2)
+ return;
+ List<String> rosterGroups = mRoster.getGroupsNames();
+ Collections.sort(rosterGroups);
+ List<GroupHolder> realGroups = mListGroup.subList(1, mListGroup.size() - 1);
+ realGroups.clear();
+ realGroups.addAll(GroupHolder.createFrom(rosterGroups));
+ // restore principal
+ GroupHolder.setUniquePrincipal(mListGroup, viewPager.getCurrentItem());
+ mAdapterBanner.notifyDataSetChanged();
+ groupsPagesAdapter.notifyDataSetChanged();
+ }
+
+ /**
+ * Add a contact to the special list No Group and All contacts.
+ * The contact will be added if the list is not the current list otherwise
+ * the list must be modified in a Handler.
+ *
+ * @param contact the contact to add.
+ */
+ private void addToSpecialList(Contact contact) {
+ List<String> groups = contact.getGroups();
+
+ ContactListAdapter adapter = getContactListAdapter(getString(R.string.contact_list_all_contact));
+ adapter.put(contact);
+ if (groups.isEmpty()) {
+ adapter = getContactListAdapter(getString(R.string.contact_list_no_group));
+ adapter.put(contact);
+ }
+ }
+
+ /**
* Listener on service event.
*/
private class BeemRosterListener extends IBeemRosterListener.Stub {
@@ -392,29 +396,9 @@
*/
@Override
public void onEntriesAdded(final List<String> addresses) throws RemoteException {
- final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
for (String newName : addresses) {
- Contact contact = mRoster.getContact(newName);
- boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus());
- List<String> groups = contact.getGroups();
- if (visible) {
- for (String group : groups) {
- if (!mListGroup.contains(group)) {
- mListGroup.add(mListGroup.size() - 1, group);
- List<Contact> tmplist = new SortedList<Contact>(new LinkedList<Contact>(), mComparator);
- mContactOnGroup.put(group, tmplist);
- }
- List<Contact> contactByGroups = mContactOnGroup.get(group);
- if (mSelectedGroup.equals(group)) {
- updateCurrentList(group, contact);
- continue;
- }
- contactByGroups.add(contact);
- }
-
- // add the contact to all and no groups
- addToSpecialList(contact);
- }
+ final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(newName));
+ putContactInList(contact);
}
}
@@ -429,26 +413,18 @@
public void onEntriesDeleted(final List<String> addresses) throws RemoteException {
Log.d(TAG, "onEntries deleted " + addresses);
for (String cToDelete : addresses) {
- Contact contact = new Contact(cToDelete);
- for (Map.Entry<String, List<Contact>> entry : mContactOnGroup.entrySet()) {
- List<Contact> contactByGroups = entry.getValue();
- if (mSelectedGroup.equals(entry.getKey())) {
- updateCurrentList(entry.getKey(), contact);
- continue;
- }
- contactByGroups.remove(contact);
+ final Contact contact = new Contact(cToDelete);
+ for (final ContactListAdapter adapter : contactListAdapters.values()) {
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ adapter.remove(contact);
+ }
+ });
}
- cleanBannerGroup();
}
-
- mHandler.post(new Runnable() {
- public void run() {
- mSelectedGroup = getString(R.string.contact_list_all_contact);
- mListContact = mContactOnGroup.get(mSelectedGroup);
-
- mAdapterContactList.notifyDataSetChanged();
- }
- });
+ cleanBannerGroup();
}
@@ -463,36 +439,16 @@
*/
@Override
public void onEntriesUpdated(final List<String> addresses) throws RemoteException {
- final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
- for (String adr : addresses) {
- Contact contact = mRoster.getContact(adr);
- boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus());
- List<String> groups = contact.getGroups();
- for (Map.Entry<String, List<Contact>> entry : mContactOnGroup.entrySet()) {
- List<Contact> contactByGroups = entry.getValue();
- if (mSelectedGroup.equals(entry.getKey())) {
- updateCurrentList(entry.getKey(), contact);
- continue;
- }
- contactByGroups.remove(contact);
- if (visible) {
- for (String group : groups) {
- if (!mListGroup.contains(group)) {
- mListGroup.add(mListGroup.size() - 1, group);
- List<Contact> tmplist = new SortedList<Contact>(
- new LinkedList<Contact>(), mComparator);
- mContactOnGroup.put(group, tmplist);
- }
- mContactOnGroup.get(group).remove(contact);
- }
- }
-
+ Log.d(TAG, "onEntries updated " + addresses);
+ for (String cToDelete : addresses) {
+ Contact contact = new Contact(cToDelete);
+ for (ContactListAdapter adapter : contactListAdapters.values()) {
+ adapter.remove(contact);
}
-
- // add the contact to all and no groups
- if (visible) {
- addToSpecialList(contact);
- }
+ }
+ for (String newName : addresses) {
+ final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(newName));
+ putContactInList(contact);
}
cleanBannerGroup();
}
@@ -509,266 +465,56 @@
@Override
public void onPresenceChanged(PresenceAdapter presence) throws RemoteException {
String from = presence.getFrom();
- final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(from));
- boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus());
- List<String> groups = contact.getGroups();
- for (Map.Entry<String, List<Contact>> entry : mContactOnGroup.entrySet()) {
- List<Contact> contactByGroups = entry.getValue();
- if (mSelectedGroup.equals(entry.getKey())) {
- updateCurrentList(entry.getKey(), contact);
- continue;
- }
- contactByGroups.remove(contact);
- if (visible) {
- if (groups.contains(entry.getKey())) {
- contactByGroups.add(contact);
- }
- }
- }
- if (visible) {
- addToSpecialList(contact);
- }
- }
-
- /**
- * Add a contact to the special list No Group and All contacts.
- * The contact will be added if the list is not the current list otherwise
- * the list must be modified in a Handler.
- *
- * @param contact the contact to add.
- */
- private void addToSpecialList(Contact contact) {
- List<String> groups = contact.getGroups();
- List<Contact> list = mContactOnGroup.get(getString(R.string.contact_list_all_contact));
- if (list != mListContact) {
- list.add(contact);
- }
- list = mContactOnGroup.get(getString(R.string.contact_list_no_group));
- if (list != mListContact && groups.isEmpty()) {
- list.add(contact);
- }
- }
-
- /**
- * Update the current list with the status of contact.
- *
- * @param listName name of the current list
- * @param contact contact to update
- */
- private void updateCurrentList(String listName, final Contact contact) {
- final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
- final List<String> groups = contact.getGroups();
- String noGroup = getString(R.string.contact_list_no_group);
- String allGroup = getString(R.string.contact_list_all_contact);
- final boolean add = ((!hideDisconnected || Status.statusOnline(contact.getStatus())) && // must show and
- (
- (listName.equals(noGroup) && groups.isEmpty()) || // in no group
- groups.contains(listName) || // or in current
- listName.equals(allGroup) // or in all
- ));
- mHandler.post(new Runnable() {
- public void run() {
- mListContact.remove(contact);
- if (add) {
- mListContact.add(contact);
- }
- mAdapterContactList.notifyDataSetChanged();
- }
- });
-
- }
-
- /**
- * Remove old groups on the banner.
- * @throws RemoteException if an error occur when communicating with the service
- */
- private void cleanBannerGroup() throws RemoteException {
- List<String> rosterGroups = mRoster.getGroupsNames();
- List<String> realGroups = mListGroup.subList(1, mListContact.size() - 1);
- realGroups.retainAll(rosterGroups);
- }
-
- }
-
- /**
- * Adapter contact list.
- */
- private class BeemContactList extends BaseAdapter implements Filterable {
-
- private final ContactFilter mFilter;
-
- /**
- * Constructor.
- */
- public BeemContactList() {
- mFilter = new ContactFilter();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int getCount() {
- return mListContact.size();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Object getItem(int position) {
- return mListContact.get(position);
+ putContactInList(contact);
}
/**
- * {@inheritDoc}
- */
- @Override
- public long getItemId(int position) {
- return mListContact.get(position).hashCode();
- }
-
-
- /**
- * {@inheritDoc}
+ * Put a contact in the different group list.
+ * @param contact the contact
*/
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
- if (convertView == null) {
- v = mInflater.inflate(R.layout.contactlistcontact, null);
- }
- Contact c = mListContact.get(position);
- if (mRoster != null) {
- try {
- c = mRoster.getContact(c.getJID());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- bindView(v, c);
- return v;
- }
-
- @Override
- public Filter getFilter() {
- return mFilter;
- }
-
- /**
- * Adapte curContact to the view.
- * @param view the row view.
- * @param curContact the current contact.
- */
- private void bindView(View view, Contact curContact) {
- if (curContact != null) {
- TextView v = (TextView) view.findViewById(R.id.contactlistpseudo);
- v.setText(curContact.getName());
- v = (TextView) view.findViewById(R.id.contactlistmsgperso);
- v.setText(curContact.getMsgState());
- ImageView img = (ImageView) view.findViewById(R.id.avatar);
- String avatarId = curContact.getAvatarId();
- int contactStatus = curContact.getStatus();
- Drawable avatar = getAvatarStatusDrawable(avatarId);
- img.setImageDrawable(avatar);
- img.setImageLevel(contactStatus);
- }
- }
+ private void putContactInList(final Contact contact) {
+ List<String> groups = contact.getGroups();
+ for (final String group : groups) {
+ runOnUiThread(new Runnable() {
- /**
- * Get a LayerDrawable containing the avatar and the status icon.
- * The status icon will change with the level of the drawable.
- * @param avatarId the avatar id to retrieve or null to get default
- * @return a LayerDrawable
- */
- private Drawable getAvatarStatusDrawable(String avatarId) {
- Drawable avatarDrawable = null;
- if (avatarId != null) {
- Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build();
- InputStream in = null;
- try {
- try {
- in = getContentResolver().openInputStream(uri);
- avatarDrawable = Drawable.createFromStream(in, avatarId);
- } finally {
- if (in != null)
- in.close();
+ @Override
+ public void run() {
+ ContactListAdapter contactListAdapter = getContactListAdapter(group);
+ contactListAdapter.put(contact);
}
- } catch (IOException e) {
- Log.w(TAG, "Error while setting the avatar " + avatarId, e);
- }
- }
- if (avatarDrawable == null)
- avatarDrawable = getResources().getDrawable(R.drawable.beem_launcher_icon_silver);
- LayerDrawable ld = (LayerDrawable) getResources().getDrawable(R.drawable.avatar_status);
- ld.setLayerInset(1, 36, 36, 0, 0);
- ld.setDrawableByLayerId(R.id.avatar, avatarDrawable);
- return ld;
- }
-
- /**
- * A Filter which select Contact to display by searching in ther Jid.
- */
- private class ContactFilter extends Filter {
-
- /**
- * Create a ContactFilter.
- */
- public ContactFilter() { }
-
- @Override
- protected Filter.FilterResults performFiltering(CharSequence constraint) {
- Log.d(TAG, "performFiltering");
- List<Contact> result = mListContact;
- if (constraint.length() > 0) {
- result = new LinkedList<Contact>();
- for (Contact c : mContactOnGroup.get(mSelectedGroup)) {
- if (c.getJID().contains(constraint))
- result.add(c);
- }
- }
- Filter.FilterResults fr = new Filter.FilterResults();
- fr.values = result;
- fr.count = result.size();
- return fr;
+ });
}
- @Override
- protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
- Log.d(TAG, "publishResults");
- List<Contact> contacts = (List<Contact>) results.values;
- mListContact = contacts;
- notifyDataSetChanged();
- }
+ runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ addToSpecialList(contact);
+ }
+ });
}
}
/**
* Adapter banner list.
*/
- private static class BeemBanner extends BaseAdapter {
- private List<String> mGroups;
- private LayoutInflater mInflater;
+ private class BeemBanner extends BaseAdapter {
/**
* Constructor.
- * @param inflater the inflater use to create the view for the banner
- * @param groups list of the differents groups to adapt
*/
- public BeemBanner(final LayoutInflater inflater, final List<String> groups) {
- mGroups = groups;
- mInflater = inflater;
+ public BeemBanner() {
}
@Override
public int getCount() {
- return mGroups.size();
+ return mListGroup.size();
}
@Override
public Object getItem(int position) {
- return mGroups.get(position);
+ return mListGroup.get(position);
}
@Override
@@ -778,11 +524,13 @@
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
+ SectionTextView v = (SectionTextView) convertView;
if (convertView == null) {
- v = mInflater.inflate(R.layout.contactlist_group, null);
+ v = (SectionTextView) mInflater.inflate(R.layout.contactlist_group, null);
}
- ((TextView) v).setText(mGroups.get(position));
+ GroupHolder gh = (GroupHolder) getItem(position);
+ v.setText(gh.group);
+ v.setPrincipal(gh.isPrincipal);
return v;
}
}
@@ -805,19 +553,14 @@
mRoster = mXmppFacade.getRoster();
if (mRoster != null) {
List<String> tmpGroupList = mRoster.getGroupsNames();
- Collections.sort(tmpGroupList);
- mListGroup.clear();
- mListGroup.add(getString(R.string.contact_list_all_contact));
- mListGroup.addAll(tmpGroupList);
- mListGroup.add(getString(R.string.contact_list_no_group));
+ cleanBannerGroup();
+ synchronized (contactListAdapters) {
+ for (ContactListAdapter ca : contactListAdapters.values()) {
+ ca.clear();
+ }
+ }
assignContactToGroups(mRoster.getContactList(), tmpGroupList);
- makeSortedList(mContactOnGroup);
- if (!mSettings.getBoolean(BeemApplication.HIDE_GROUPS_KEY, false))
- showGroups();
- else
- hideGroups();
- String group = getString(R.string.contact_list_all_contact);
- buildContactList(group);
+
mRoster.addRosterListener(mBeemRosterListener);
Log.d(TAG, "add roster listener");
mChatManager = mXmppFacade.getChatManager();
@@ -837,10 +580,10 @@
mXmppFacade = null;
mChatManager = null;
mRoster = null;
- mListContact.clear();
mListGroup.clear();
mContactOnGroup.clear();
mBinded = false;
+
}
/**
@@ -851,88 +594,38 @@
* @param groupNames list of existing groups
*/
private void assignContactToGroups(List<Contact> contacts, List<String> groupNames) {
- boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
- mContactOnGroup.clear();
- List<Contact> all = new LinkedList<Contact>();
- List<Contact> noGroups = new LinkedList<Contact>();
- for (String group : groupNames) {
- mContactOnGroup.put(group, new LinkedList<Contact>());
- }
for (Contact c : contacts) {
- if (hideDisconnected && !Status.statusOnline(c.getStatus())) {
- continue;
- }
- all.add(c);
+ addToSpecialList(c);
+
List<String> groups = c.getGroups();
- if (groups.isEmpty())
- noGroups.add(c);
- else {
- for (String currentGroup : groups) {
- List<Contact> contactsByGroups = mContactOnGroup.get(currentGroup);
- contactsByGroups.add(c);
- }
+
+ for (String currentGroup : groups) {
+ ContactListAdapter cl = getContactListAdapter(currentGroup);
+ cl.put(c);
}
}
- mContactOnGroup.put(getString(R.string.contact_list_no_group), noGroups);
- mContactOnGroup.put(getString(R.string.contact_list_all_contact), all);
}
- /**
- * Make the List of the map became Insertion sorted list.
- *
- * @param map the map to convert.
- */
- private void makeSortedList(Map<String, List<Contact>> map) {
- for (Map.Entry<String, List<Contact>> entry : map.entrySet()) {
- List<Contact> l = entry.getValue();
- entry.setValue(new SortedList<Contact>(l, mComparator));
- }
- }
}
-
-
/**
- * Comparator Contact by status and name.
+ * Listener on page change event.
*/
- private static class ComparatorContactListByStatusAndName<T> implements Comparator<T> {
- /**
- * Constructor.
- */
- public ComparatorContactListByStatusAndName() {
- }
-
- @Override
- public int compare(T c1, T c2) {
- if (((Contact) c1).getStatus() < ((Contact) c2).getStatus()) {
- return 1;
- } else if (((Contact) c1).getStatus() > ((Contact) c2).getStatus()) {
- return -1;
- } else
- return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName());
- }
- }
-
- /**
- * Event simple click on item of the contact list.
- */
- private class BeemContactListOnClick implements OnItemClickListener {
- /**
- * Constructor.
- */
- public BeemContactListOnClick() {
- }
+ private class OnPageChangeListener extends ViewPager.SimpleOnPageChangeListener {
/**
- * {@inheritDoc}
+ * Create a {@link OnPageChangeListener}.
*/
+ public OnPageChangeListener() {
+ }
@Override
- public void onItemClick(AdapterView<?> arg0, View v, int pos, long lpos) {
- Contact c = mListContact.get(pos);
- Intent i = new Intent(ContactList.this, Chat.class);
- i.setData(c.toUri());
- startActivity(i);
+ public void onPageSelected(int position) {
+ GroupHolder.setUniquePrincipal(mListGroup, position);
+ if (groupGallery != null) {
+ groupGallery.setSelection(position);
+ }
+ mAdapterBanner.notifyDataSetChanged();
}
}
@@ -949,9 +642,96 @@
@Override
public void onItemClick(AdapterView<?> arg0, View v, int i, long l) {
- String group = mListGroup.get(i);
- buildContactList(group);
+ viewPager.setCurrentItem(i, true);
}
}
+ /**
+ * PagerAdapter for the contact list.
+ */
+ private class ListPagerAdapter extends FragmentPagerAdapter {
+
+ /**
+ * Create a {@link ListPagerAdapter}.
+ * @param fm the {@link FragmentManager}
+ * @param viewPager the {@link ViewPager} associate with this adapter
+ */
+ public ListPagerAdapter(final FragmentManager fm, final ViewPager viewPager) {
+ super(fm);
+ viewPager.setAdapter(this);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ String group = mListGroup.get(position).group;
+ ContactListFragment f = ContactListFragment.newInstance(group);
+ f.setListAdapter(getContactListAdapter(group));
+ return f;
+ }
+
+ @Override
+ public int getCount() {
+ return mListGroup.size();
+ }
+
+ }
+
+ /**
+ * A holder for a group name and is principal state.
+ * It is an helper class to manage the state of the tabs.
+ */
+ private static class GroupHolder {
+
+ String group;
+ boolean isPrincipal;
+
+ /**
+ * Create a {@link GroupHolder}.
+ * @param group the group name
+ */
+ public GroupHolder(final String group) {
+ this.group = group;
+ }
+
+ /**
+ * Create a list of GroupHolder.
+ * @param groups list of group name
+ * @return a list of {@link GroupHolder}
+ */
+ public static List<GroupHolder> createFrom(List<String> groups) {
+ List<GroupHolder> result = new ArrayList<ContactList.GroupHolder>();
+ for (String s : groups) {
+ result.add(new GroupHolder(s));
+ }
+ return result;
+ }
+
+ /**
+ * Test if a group exist in a list of {@link GroupHolder}.
+ * @param list the list
+ * @param group the group
+ * @return true if the group is in the list false otherwise
+ */
+ public static boolean contains(List<GroupHolder> list, String group) {
+ for (GroupHolder groupHolder : list) {
+ if (groupHolder.group.equals(group))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Set a unique principal in the {@link GroupHolder} list.
+ * @param groups the list
+ * @param position the position of the principal
+ */
+ public static void setUniquePrincipal(List<GroupHolder> groups, int position) {
+ for (GroupHolder gh : groups) {
+ gh.isPrincipal = false;
+ }
+ groups.get(position).isPrincipal = true;
+ }
+ }
+
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/ui/ContactListAdapter.java Tue Jun 05 16:44:38 2012 +0200
@@ -0,0 +1,294 @@
+/*
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2011 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM 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 BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+*/
+package com.beem.project.beem.ui;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.net.Uri;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.Filter;
+import android.widget.Filterable;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.beem.project.beem.BeemApplication;
+import com.beem.project.beem.R;
+import com.beem.project.beem.providers.AvatarProvider;
+import com.beem.project.beem.service.Contact;
+import com.beem.project.beem.utils.SortedList;
+import com.beem.project.beem.utils.Status;
+
+/**
+ * An Adapter for the contact list.
+ * It displays a list of contact in a particular group.
+ *
+ */
+public class ContactListAdapter extends BaseAdapter implements Filterable {
+ private static final String TAG = ContactListAdapter.class.getSimpleName();
+ private final ComparatorContactListByStatusAndName<Contact> mComparator =
+ new ComparatorContactListByStatusAndName<Contact>();
+ private List<Contact> mCurrentList;
+ private final List<Contact> allContacts = new SortedList<Contact>(new LinkedList<Contact>(), mComparator);
+ private final List<Contact> onlineContacts = new SortedList<Contact>(new LinkedList<Contact>(), mComparator);
+ private final Filter mFilter = new ContactFilter();
+ private final Context context;
+ private LayoutInflater mInflater;
+
+ private boolean showOnlineOnly;
+
+ /**
+ * Create a ContactListAdapter.
+ * @param c the android context
+ */
+ public ContactListAdapter(final Context c) {
+ mCurrentList = allContacts;
+ context = c;
+ mInflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ @Override
+ public int getCount() {
+ return mCurrentList.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mCurrentList.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mCurrentList.get(position).hashCode();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View v = convertView;
+ if (convertView == null) {
+ v = mInflater.inflate(R.layout.contactlistcontact, null);
+ }
+ Contact c = mCurrentList.get(position);
+ bindView(v, c);
+ return v;
+ }
+
+ /**
+ * Put a contact in the list.
+ * @param c the contact
+ */
+ public void put(Contact c) {
+ put(c, allContacts);
+ if (Status.statusOnline(c.getStatus()))
+ put(c, onlineContacts);
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Remove a contact from the list.
+ *
+ * @param c the contact
+ */
+ public void remove(Contact c) {
+ allContacts.remove(c);
+ onlineContacts.remove(c);
+ notifyDataSetChanged();
+ }
+
+ /**
+ * Clear the contact list.
+ */
+ public void clear() {
+ allContacts.clear();
+ onlineContacts.clear();
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public Filter getFilter() {
+ return mFilter;
+ }
+
+ /**
+ * Bind a contact to the view.
+ * @param view the row view.
+ * @param curContact the contact.
+ */
+ private void bindView(View view, Contact curContact) {
+ if (curContact != null) {
+ TextView v = (TextView) view.findViewById(R.id.contactlistpseudo);
+ SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
+ if (settings.getBoolean(BeemApplication.SHOW_JID, false))
+ v.setText(curContact.getJID());
+ else
+ v.setText(curContact.getName());
+ v = (TextView) view.findViewById(R.id.contactlistmsgperso);
+ v.setText(curContact.getMsgState());
+ ImageView img = (ImageView) view.findViewById(R.id.avatar);
+ String avatarId = curContact.getAvatarId();
+ int contactStatus = curContact.getStatus();
+ Drawable avatar = getAvatarStatusDrawable(avatarId);
+ img.setImageDrawable(avatar);
+ img.setImageLevel(contactStatus);
+ }
+ }
+
+ /**
+ * Get a LayerDrawable containing the avatar and the status icon.
+ * The status icon will change with the level of the drawable.
+ * @param avatarId the avatar id to retrieve or null to get default
+ * @return a LayerDrawable
+ */
+ private Drawable getAvatarStatusDrawable(String avatarId) {
+ Drawable avatarDrawable = null;
+ if (avatarId != null) {
+ Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build();
+ InputStream in = null;
+ try {
+ try {
+ in = context.getContentResolver().openInputStream(uri);
+ avatarDrawable = Drawable.createFromStream(in, avatarId);
+ } finally {
+ if (in != null)
+ in.close();
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Error while setting the avatar " + avatarId, e);
+ }
+ }
+ if (avatarDrawable == null)
+ avatarDrawable = context.getResources().getDrawable(R.drawable.beem_launcher_icon_silver);
+ LayerDrawable ld = (LayerDrawable) context.getResources().getDrawable(R.drawable.avatar_status);
+ ld.setLayerInset(1, 36, 36, 0, 0);
+ ld.setDrawableByLayerId(R.id.avatar, avatarDrawable);
+ return ld;
+ }
+
+ /**
+ * Put a contact in a list.
+ * Helper method.
+ *
+ * @param c the contact
+ * @param list the list
+ */
+ private void put(Contact c, List<Contact> list) {
+ list.remove(c);
+ list.add(c);
+ }
+
+ /**
+ * Tell if the list display only online contacts.
+ *
+ * @return true if only online contacts are shown
+ */
+ public boolean isOnlineOnly() {
+ return showOnlineOnly;
+ }
+
+ /**
+ * Set the list to display only the online contacts.
+ *
+ * @param online true to display only online contacts
+ */
+ public void setOnlineOnly(boolean online) {
+ if (online != showOnlineOnly) {
+ showOnlineOnly = online;
+ mCurrentList = showOnlineOnly ? onlineContacts : allContacts;
+ notifyDataSetChanged();
+ }
+ }
+
+ /**
+ * A Filter which select Contact to display by searching in ther Jid.
+ */
+ private class ContactFilter extends Filter {
+
+ /**
+ * Create a ContactFilter.
+ */
+ public ContactFilter() { }
+
+ @Override
+ protected Filter.FilterResults performFiltering(CharSequence constraint) {
+ Log.d(TAG, "performFiltering");
+ List<Contact> result = mCurrentList;
+ if (constraint.length() > 0) {
+ result = new LinkedList<Contact>();
+ for (Contact c : mCurrentList) {
+ if (c.getJID().contains(constraint))
+ result.add(c);
+ }
+ }
+ Filter.FilterResults fr = new Filter.FilterResults();
+ fr.values = result;
+ fr.count = result.size();
+ return fr;
+ }
+
+ @Override
+ protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
+ Log.d(TAG, "publishResults");
+ List<Contact> contacts = (List<Contact>) results.values;
+ mCurrentList = contacts;
+ notifyDataSetChanged();
+ }
+ }
+
+ /**
+ * Comparator Contact by status and name.
+ */
+ private static class ComparatorContactListByStatusAndName<T> implements Comparator<T> {
+ /**
+ * Constructor.
+ */
+ public ComparatorContactListByStatusAndName() {
+ }
+
+ @Override
+ public int compare(T c1, T c2) {
+ if (((Contact) c1).getStatus() < ((Contact) c2).getStatus()) {
+ return 1;
+ } else if (((Contact) c1).getStatus() > ((Contact) c2).getStatus()) {
+ return -1;
+ } else
+ return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName());
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/ui/ContactListFragment.java Tue Jun 05 16:44:38 2012 +0200
@@ -0,0 +1,182 @@
+/*
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2011 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM 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 BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+*/
+package com.beem.project.beem.ui;
+
+import java.util.List;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.ContextMenu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import com.beem.project.beem.R;
+import com.beem.project.beem.service.Contact;
+
+/**
+ * A Fragment which display a list of contacts.
+ */
+public class ContactListFragment extends ListFragment {
+ private String group;
+ private ContactList hostActivity;
+ private Contact mSelectedContact;
+
+ /**
+ * Create a ContactListFragment.
+ * @param group the group name
+ * @return the ContactListFragment
+ */
+ public static ContactListFragment newInstance(String group) {
+ ContactListFragment f = new ContactListFragment();
+ Bundle b = new Bundle();
+ b.putString("group", group);
+ f.setArguments(b);
+ return f;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ parseArguments();
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ hostActivity = (ContactList) activity;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ ListAdapter adapter = hostActivity.getContactListAdapter(group);
+ setListAdapter(adapter);
+ registerForContextMenu(getListView());
+ }
+
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ ContactListAdapter a = (ContactListAdapter) getListAdapter();
+ Contact c = (Contact) a.getItem(position);
+ Intent i = new Intent(getActivity(), Chat.class);
+ i.setData(c.toUri());
+ startActivity(i);
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ MenuInflater inflater = hostActivity.getMenuInflater();
+ inflater.inflate(R.menu.contactlist_context, menu);
+ AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
+ mSelectedContact = (Contact) getListAdapter().getItem(info.position);
+ menu.setHeaderTitle(mSelectedContact.getJID());
+ }
+
+ /**
+ * Parse the arguments submit to the Fragment.
+ */
+ private void parseArguments() {
+ Bundle b = getArguments();
+ if (b == null)
+ return;
+ group = b.getString("group");
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ Intent in;
+ boolean result = false;
+ if (mSelectedContact != null) {
+ switch (item.getItemId()) {
+ case R.id.contact_list_context_menu_chat_item:
+ List<String> res = mSelectedContact.getMRes();
+ if (res.isEmpty()) {
+ break;
+ }
+ for (String resv : res) {
+ in = new Intent(hostActivity, Chat.class);
+ in.setData(mSelectedContact.toUri(resv));
+ item.getSubMenu().add(resv).setIntent(in);
+ }
+ result = true;
+ break;
+ case R.id.contact_list_context_menu_call_item:
+ res = mSelectedContact.getMRes();
+ if (res.isEmpty()) {
+ break;
+ }
+ for (String resv : res) {
+ in = new Intent(hostActivity, Call.class);
+ in.setData(mSelectedContact.toUri(resv));
+ in.putExtra("isCaller", true);
+ item.getSubMenu().add(resv).setIntent(in);
+ }
+ result = true;
+ break;
+ case R.id.contact_list_context_menu_user_info:
+ item.getSubMenu().setHeaderTitle(mSelectedContact.getJID());
+ result = true;
+ break;
+ case R.id.contact_list_context_menu_userinfo_alias:
+ hostActivity.doContextMenuAction(item.getItemId(), mSelectedContact);
+ result = true;
+ break;
+ case R.id.contact_list_context_menu_userinfo_group:
+ in = new Intent(hostActivity, GroupList.class);
+ in.putExtra("contact", mSelectedContact);
+ startActivity(in);
+ result = true;
+ break;
+ case R.id.contact_list_context_menu_userinfo_subscription:
+ hostActivity.doContextMenuAction(item.getItemId(), mSelectedContact);
+ result = true;
+ break;
+ case R.id.contact_list_context_menu_userinfo_block:
+ result = true;
+ break;
+ case R.id.contact_list_context_menu_userinfo_delete:
+ hostActivity.doContextMenuAction(item.getItemId(), mSelectedContact);
+ result = true;
+ break;
+ default:
+ result = super.onContextItemSelected(item);
+ break;
+ }
+ return result;
+ }
+ return super.onContextItemSelected(item);
+ }
+
+}
--- a/src/com/beem/project/beem/ui/Login.java Tue Jun 05 16:29:25 2012 +0200
+++ b/src/com/beem/project/beem/ui/Login.java Tue Jun 05 16:44:38 2012 +0200
@@ -51,6 +51,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
+import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -82,6 +83,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
Application app = getApplication();
if (app instanceof BeemApplication) {
mBeemApplication = (BeemApplication) app;
--- a/src/com/beem/project/beem/ui/Settings.java Tue Jun 05 16:29:25 2012 +0200
+++ b/src/com/beem/project/beem/ui/Settings.java Tue Jun 05 16:44:38 2012 +0200
@@ -73,7 +73,7 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.layout.preferences);
+ addPreferencesFromResource(R.xml.preferences);
}
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/ui/views/SectionTextView.java Tue Jun 05 16:44:38 2012 +0200
@@ -0,0 +1,220 @@
+/*
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2011 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM 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 BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+*/
+package com.beem.project.beem.ui.views;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import com.beem.project.beem.R;
+
+/**
+ * This class implements a custom TextView with an underscore section line.
+ * It can be used to make tabs.
+ *
+ */
+public class SectionTextView extends TextView {
+ private static final int DEFAULT_PRINCIPAL_COLOR = 0xffffffff;
+ private static final int DEFAULT_PRINCIPAL_LINE_SIZE = 8;
+ private static final int DEFAULT_NON_PRINCIPAL_COLOR = 0xff555555;
+ private static final int DEFAULT_NON_PRINCIPAL_LINE_SIZE = 3;
+ private static final int SECTION_SPACE_SIZE = 5;
+ private boolean principal;
+ private int principalColor;
+ private int nonPrincipalColor;
+ private float principalLineSize;
+ private float nonPrincipalLineSize;
+ private float density;
+
+ private Paint sectionPaint;
+
+
+ /**
+ * Create a SectionTextView.
+ *
+ * @param context the android context
+ * @param attrs the android attributes
+ */
+ public SectionTextView(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+ initSectionTextView();
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SectionTextView);
+
+ principalColor = a.getColor(R.styleable.SectionTextView_principalColor, DEFAULT_PRINCIPAL_COLOR);
+ principalLineSize = a.getDimension(R.styleable.SectionTextView_principalLineSize,
+ DEFAULT_PRINCIPAL_LINE_SIZE * density);
+ nonPrincipalColor = a.getColor(R.styleable.SectionTextView_nonPrincipalColor, DEFAULT_NON_PRINCIPAL_COLOR);
+ nonPrincipalLineSize = a.getDimension(R.styleable.SectionTextView_nonPrincipalLineSize,
+ DEFAULT_NON_PRINCIPAL_LINE_SIZE * density);
+
+ a.recycle();
+ }
+
+ /**
+ * Create a SectionTextView.
+ *
+ * @param context the android context
+ */
+ public SectionTextView(final Context context) {
+ super(context);
+ initSectionTextView();
+ }
+
+ /**
+ * Set the textview in principal mode.
+ * It will show up with a distinctive color.
+ *
+ * @param principal the mode
+ */
+ public void setPrincipal(boolean principal) {
+ this.principal = principal;
+ }
+
+ /**
+ * Get the principal mode of the view.
+ *
+ * @return the mode
+ */
+ public boolean isPrincipal() {
+ return principal;
+ }
+
+
+ /**
+ * Get the color used to show the view in principal mode.
+ *
+ * @return the color
+ */
+ public int getPrincipalColor() {
+ return principalColor;
+ }
+
+ /**
+ * Set the color used to show the view in principal mode.
+ *
+ * @param principalColor the color
+ */
+ public void setPrincipalColor(int principalColor) {
+ this.principalColor = principalColor;
+ }
+
+ /**
+ * Get the color used to show the view when not in principal mode.
+ *
+ * @return the color
+ */
+ public int getNonPrincipalColor() {
+ return nonPrincipalColor;
+ }
+
+ /**
+ * Set the color used to show the view when not in principal mode.
+ *
+ * @param nonPrincipalColor the color
+ */
+ public void setNonPrincipalColor(int nonPrincipalColor) {
+ this.nonPrincipalColor = nonPrincipalColor;
+ }
+
+ /**
+ * Get the size of the line section in principal mode.
+ *
+ * @return the size of the line
+ */
+ public float getPrincipalLineSize() {
+ return principalLineSize;
+ }
+
+ /**
+ * Set the size of the line section in principal mode.
+ *
+ * @param principalLineSize the size of the line
+ */
+ public void setPrincipalLineSize(float principalLineSize) {
+ this.principalLineSize = principalLineSize;
+ }
+
+ /**
+ * Get the size of the line section when not in principal mode.
+ *
+ * @return the size of the line
+ */
+ public float getNonPrincipalLineSize() {
+ return nonPrincipalLineSize;
+ }
+
+ /**
+ * Set the size of the line section when not in principal mode.
+ *
+ * @param nonPrincipalLineSize the size of the line
+ */
+ public void setNonPrincipalLineSize(float nonPrincipalLineSize) {
+ this.nonPrincipalLineSize = nonPrincipalLineSize;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int height = getMeasuredHeight();
+ height += Math.max(principalLineSize, nonPrincipalLineSize)
+ + SECTION_SPACE_SIZE * density; // line width + space
+ setMeasuredDimension(getMeasuredWidth(), height);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (isPrincipal()) {
+ sectionPaint.setColor(principalColor);
+ sectionPaint.setStrokeWidth(principalLineSize);
+ canvas.drawLine(0, getHeight() - principalLineSize / 2,
+ getWidth(), getHeight() - principalLineSize / 2, sectionPaint);
+ } else {
+ sectionPaint.setColor(nonPrincipalColor);
+ sectionPaint.setStrokeWidth(nonPrincipalLineSize);
+ canvas.drawLine(0, getHeight() - nonPrincipalLineSize / 2, getWidth(),
+ getHeight() - nonPrincipalLineSize / 2, sectionPaint);
+ }
+ }
+
+ /**
+ * Initialize the SectionTextView with the default value.
+ */
+ private void initSectionTextView() {
+ density = getResources().getDisplayMetrics().density;
+ sectionPaint = new Paint();
+ principalColor = DEFAULT_PRINCIPAL_COLOR;
+ principalLineSize = DEFAULT_PRINCIPAL_LINE_SIZE * density;
+ nonPrincipalColor = DEFAULT_NON_PRINCIPAL_COLOR;
+ nonPrincipalLineSize = DEFAULT_NON_PRINCIPAL_LINE_SIZE * density;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/ui/views/package-info.java Tue Jun 05 16:44:38 2012 +0200
@@ -0,0 +1,31 @@
+/*
+ BEEM is a videoconference application on the Android Platform.
+
+ Copyright (C) 2009-2011 by Frederic-Charles Barthelery,
+ Nikita Kozlov,
+ Vincent Veronis.
+
+ This file is part of BEEM.
+
+ BEEM is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ BEEM 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 BEEM. If not, see <http://www.gnu.org/licenses/>.
+
+ Please send bug reports with examples or suggestions to
+ contact@beem-project.com or http://www.beem-project.com/
+
+*/
+/**
+ * This package contains the custom View used by Beem to make the user interfaces.
+ */
+package com.beem.project.beem.ui.views;
+
--- a/src/com/beem/project/beem/utils/Status.java Tue Jun 05 16:29:25 2012 +0200
+++ b/src/com/beem/project/beem/utils/Status.java Tue Jun 05 16:44:38 2012 +0200
@@ -43,6 +43,8 @@
*/
package com.beem.project.beem.utils;
+import com.beem.project.beem.R;
+
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Mode;
@@ -153,4 +155,32 @@
return status != Status.CONTACT_STATUS_DISCONNECT;
}
+ /**
+ * Get icon resource from status.
+ * @param status the status
+ * @return the resource icon
+ */
+ public static int getIconBarFromStatus(final int status) {
+ int icon = R.drawable.beem_status_icon;
+ switch (status) {
+ case Status.CONTACT_STATUS_AVAILABLE:
+ icon = R.drawable.beem_status_icon_available;
+ break;
+ case Status.CONTACT_STATUS_AVAILABLE_FOR_CHAT:
+ icon = R.drawable.beem_status_icon_available;
+ break;
+ case Status.CONTACT_STATUS_AWAY:
+ icon = R.drawable.beem_status_icon_away;
+ break;
+ case Status.CONTACT_STATUS_BUSY:
+ icon = R.drawable.beem_status_icon_busy;
+ break;
+ case Status.CONTACT_STATUS_UNAVAILABLE:
+ icon = R.drawable.beem_status_icon_gray;
+ break;
+ default:
+ icon = R.drawable.beem_status_icon;
+ }
+ return icon;
+ }
}
--- a/src/de/duenndns/ssl/MemorizingTrustManager.java Tue Jun 05 16:29:25 2012 +0200
+++ b/src/de/duenndns/ssl/MemorizingTrustManager.java Tue Jun 05 16:44:38 2012 +0200
@@ -31,12 +31,9 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
-import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
@@ -47,7 +44,7 @@
import java.security.cert.*;
import java.security.KeyStore;
import java.security.KeyStoreException;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.security.MessageDigest;
import java.util.HashMap;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
@@ -80,9 +77,10 @@
static String KEYSTORE_FILE = "KeyStore.bks";
Context master;
+ Activity foregroundAct;
NotificationManager notificationManager;
private static int decisionId = 0;
- private static HashMap<Integer,MTMDecision> openDecisions = new HashMap();
+ private static HashMap<Integer, MTMDecision> openDecisions = new HashMap<Integer, MTMDecision>();
Handler masterHandler;
private File keyStoreFile;
@@ -92,15 +90,25 @@
/** Creates an instance of the MemorizingTrustManager class.
*
- * @param m Activity or Service to show the Dialog / Notification
+ * You need to supply the application context. This has to be one of:
+ * - Application
+ * - Activity
+ * - Service
+ *
+ * The context is used for file management, to display the dialog /
+ * notification and for obtaining translated strings.
+ *
+ * @param m Context for the application.
*/
- private MemorizingTrustManager(Context m) {
+ public MemorizingTrustManager(Context m) {
master = m;
masterHandler = new Handler();
notificationManager = (NotificationManager)master.getSystemService(Context.NOTIFICATION_SERVICE);
Application app;
- if (m instanceof Service) {
+ if (m instanceof Application) {
+ app = (Application)m;
+ } else if (m instanceof Service) {
app = ((Service)m).getApplication();
} else if (m instanceof Activity) {
app = ((Activity)m).getApplication();
@@ -134,6 +142,36 @@
}
/**
+ * Binds an Activity to the MTM for displaying the query dialog.
+ *
+ * This is useful if your connection is run from a service that is
+ * triggered by user interaction -- in such cases the activity is
+ * visible and the user tends to ignore the service notification.
+ *
+ * You should never have a hidden activity bound to MTM! Use this
+ * function in onResume() and @see unbindDisplayActivity in onPause().
+ *
+ * @param act Activity to be bound
+ */
+ public void bindDisplayActivity(Activity act) {
+ foregroundAct = act;
+ }
+
+ /**
+ * Removes an Activity from the MTM display stack.
+ *
+ * Always call this function when the Activity added with
+ * @see bindDisplayActivity is hidden.
+ *
+ * @param act Activity to be unbound
+ */
+ public void unbindDisplayActivity(Activity act) {
+ // do not remove if it was overridden by a different activity
+ if (foregroundAct == act)
+ foregroundAct = null;
+ }
+
+ /**
* Changes the path for the KeyStore file.
*
* The actual filename relative to the app's directory will be
@@ -207,6 +245,15 @@
}
}
+ // if the certificate is stored in the app key store, it is considered "known"
+ private boolean isCertKnown(X509Certificate cert) {
+ try {
+ return appKeyStore.getCertificateAlias(cert) != null;
+ } catch (KeyStoreException e) {
+ return false;
+ }
+ }
+
private boolean isExpiredException(Throwable e) {
do {
if (e instanceof CertificateExpiredException)
@@ -233,6 +280,10 @@
Log.i(TAG, "checkCertTrusted: accepting expired certificate from keystore");
return;
}
+ if (isCertKnown(chain[0])) {
+ Log.i(TAG, "checkCertTrusted: accepting cert already stored in keystore");
+ return;
+ }
try {
Log.d(TAG, "checkCertTrusted: trying defaultTrustManager");
if (isServer)
@@ -274,6 +325,28 @@
return myId;
}
+ private static String hexString(byte[] data) {
+ StringBuffer si = new StringBuffer();
+ for (int i = 0; i < data.length; i++) {
+ si.append(String.format("%02x", data[i]));
+ if (i < data.length - 1)
+ si.append(":");
+ }
+ return si.toString();
+ }
+
+ private static String certHash(final X509Certificate cert, String digest) {
+ try {
+ MessageDigest md = MessageDigest.getInstance(digest);
+ md.update(cert.getEncoded());
+ return hexString(md.digest());
+ } catch (java.security.cert.CertificateEncodingException e) {
+ return e.getMessage();
+ } catch (java.security.NoSuchAlgorithmException e) {
+ return e.getMessage();
+ }
+ }
+
private String certChainMessage(final X509Certificate[] chain, CertificateException cause) {
Throwable e = cause;
Log.d(TAG, "certChainMessage for " + e);
@@ -281,14 +354,17 @@
if (e.getCause() != null) {
e = e.getCause();
si.append(e.getLocalizedMessage());
- si.append("\n");
+ //si.append("\n");
}
for (X509Certificate c : chain) {
- si.append("\n");
+ si.append("\n\n");
si.append(c.getSubjectDN().toString());
- si.append(" (");
+ si.append("\nMD5: ");
+ si.append(certHash(c, "MD5"));
+ si.append("\nSHA1: ");
+ si.append(certHash(c, "SHA-1"));
+ si.append("\nSigned by: ");
si.append(c.getIssuerDN().toString());
- si.append(")");
}
return si.toString();
}
@@ -305,7 +381,16 @@
notificationManager.notify(NOTIFICATION_ID, n);
}
- void launchServiceMode(Intent activityIntent, final String certMessage) {
+ /**
+ * Returns the top-most entry of the activity stack.
+ *
+ * @return the Context of the currently bound UI or the master context if none is bound
+ */
+ Context getUI() {
+ return (foregroundAct != null) ? foregroundAct : master;
+ }
+
+ BroadcastReceiver launchServiceMode(Intent activityIntent, final String certMessage) {
BroadcastReceiver launchNotifReceiver= new BroadcastReceiver() {
public void onReceive(Context ctx, Intent i) {
Log.i(TAG, "Interception not done by the application. Send notification");
@@ -318,7 +403,7 @@
Intent ni = new Intent(INTERCEPT_DECISION_INTENT + "/" + master.getPackageName());
ni.putExtra(INTERCEPT_DECISION_INTENT_LAUNCH, call);
master.sendOrderedBroadcast(ni, null);
-
+ return launchNotifReceiver;
}
void interact(final X509Certificate[] chain, String authType, CertificateException cause)
@@ -327,29 +412,13 @@
/* prepare the MTMDecision blocker object */
MTMDecision choice = new MTMDecision();
final int myId = createDecisionId(choice);
- final String certTitle = chain[0].getSubjectDN().toString();
final String certMessage = certChainMessage(chain, cause);
-
BroadcastReceiver decisionReceiver = new BroadcastReceiver() {
public void onReceive(Context ctx, Intent i) { interactResult(i); }
};
master.registerReceiver(decisionReceiver, new IntentFilter(DECISION_INTENT + "/" + master.getPackageName()));
- masterHandler.post(new Runnable() {
- public void run() {
- Intent ni = new Intent(master, MemorizingActivity.class);
- ni.setData(Uri.parse(MemorizingTrustManager.class.getName() + "/" + myId));
- ni.putExtra(DECISION_INTENT_APP, master.getPackageName());
- ni.putExtra(DECISION_INTENT_ID, myId);
- ni.putExtra(DECISION_INTENT_CERT, certMessage);
-
- try {
- master.startActivity(ni);
- } catch (Exception e) {
- Log.e(TAG, "startActivity: " + e);
- launchServiceMode(ni, certMessage);
- }
- }
- });
+ LaunchRunnable lr = new LaunchRunnable(myId, certMessage);
+ masterHandler.post(lr);
Log.d(TAG, "openDecisions: " + openDecisions);
Log.d(TAG, "waiting on " + myId);
@@ -359,6 +428,8 @@
e.printStackTrace();
}
master.unregisterReceiver(decisionReceiver);
+ if (lr.launchNotifReceiver != null)
+ master.unregisterReceiver(lr.launchNotifReceiver);
Log.d(TAG, "finished wait on " + myId + ": " + choice.state);
switch (choice.state) {
case MTMDecision.DECISION_ALWAYS:
@@ -381,10 +452,42 @@
d = openDecisions.get(decisionId);
openDecisions.remove(decisionId);
}
+ if (d == null) {
+ Log.e(TAG, "interactResult: aborting due to stale decision reference!");
+ return;
+ }
synchronized(d) {
d.state = choice;
d.notify();
}
}
+ private class LaunchRunnable implements Runnable {
+ private int myId;
+ private String certMessage;
+ BroadcastReceiver launchNotifReceiver;
+
+ public LaunchRunnable(final int id, final String certMsg) {
+ myId = id;
+ certMessage = certMsg;
+ }
+
+ public void run() {
+ Intent ni = new Intent(master, MemorizingActivity.class);
+ ni.setData(Uri.parse(MemorizingTrustManager.class.getName() + "/" + myId));
+ ni.putExtra(DECISION_INTENT_APP, master.getPackageName());
+ ni.putExtra(DECISION_INTENT_ID, myId);
+ ni.putExtra(DECISION_INTENT_CERT, certMessage);
+
+ // we try to directly start the activity and fall back to
+ // making a notification
+ try {
+ getUI().startActivity(ni);
+ } catch (Exception e) {
+ Log.e(TAG, "startActivity: " + e);
+ launchNotifReceiver = launchServiceMode(ni, certMessage);
+ }
+ }
+ }
+
}