Merge branch 'development'
This commit is contained in:
		
						commit
						15c05dc3c3
					
				|  | @ -1,8 +1,8 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="eu.siacs.conversations" | ||||
|     android:versionCode="28" | ||||
|     android:versionName="0.7.2" > | ||||
|     android:versionCode="31" | ||||
|     android:versionName="0.7.3" > | ||||
| 
 | ||||
|     <uses-sdk | ||||
|         android:minSdkVersion="14" | ||||
|  | @ -40,7 +40,6 @@ | |||
| 
 | ||||
|         <activity | ||||
|             android:name="eu.siacs.conversations.ui.ConversationActivity" | ||||
|             android:configChanges="orientation|screenSize" | ||||
|             android:label="@string/title_activity_conversations" | ||||
|             android:launchMode="singleTask" | ||||
|             android:windowSoftInputMode="stateHidden" > | ||||
|  | @ -63,6 +62,14 @@ | |||
|                 <data android:scheme="imto" /> | ||||
|                 <data android:host="jabber" /> | ||||
|             </intent-filter> | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.intent.action.VIEW" /> | ||||
| 
 | ||||
|                 <category android:name="android.intent.category.DEFAULT" /> | ||||
|                 <category android:name="android.intent.category.BROWSABLE" /> | ||||
| 
 | ||||
|                 <data android:scheme="xmpp" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|         <activity | ||||
|             android:name="eu.siacs.conversations.ui.SettingsActivity" | ||||
|  |  | |||
|  | @ -1,5 +1,10 @@ | |||
| ###Changelog | ||||
| 
 | ||||
| ####Version 0.7.3 | ||||
| * revised tablet ui | ||||
| * internal rewrites | ||||
| * bug fixes | ||||
| 
 | ||||
| ####Version 0.7.2 | ||||
| * show full timestamp in messages | ||||
| * brought back option to use JID to identify conferences | ||||
|  |  | |||
|  | @ -69,6 +69,7 @@ These XEPs are - as of now: | |||
| * [Ilia Rostovtsev](https://github.com/qooob) (Russian) | ||||
| * [Jelmer Vernooij](https://github.com/jelmer) (Dutch) | ||||
| * [Anders Sandblad](https://github.com/andersruneson) (Swedish) | ||||
| * [Aizaz AZ](http://www.linkedin.com/in/aizazhaider) (Chinese) | ||||
| 
 | ||||
| ##FAQ | ||||
| ###General | ||||
|  | @ -81,7 +82,7 @@ The more convenient way - which not only gives you automatic updates but also | |||
| supports the further development of Conversations - is to buy the App in the Google | ||||
| [Play Store](https://play.google.com/store/apps/details?id=eu.siacs.conversations). | ||||
| ####I don't have a Google Account but I would still like to make a contribution | ||||
| I accept donations over PayPal and BitCoin. For donations via PayPal you can use the email address donate@siacs.eu or the button below. | ||||
| I accept donations over PayPal, BitCoin and Flattr. For donations via PayPal you can use the email address donate@siacs.eu or the button below. | ||||
| 
 | ||||
| [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CW3SYT3KG5PDL) | ||||
| 
 | ||||
|  | @ -91,6 +92,9 @@ transfer (SEPA). | |||
| 
 | ||||
| My Bitcoin Address is: 1NxSU1YxYzJVDpX1rcESAA3NJki7kRgeeu | ||||
| 
 | ||||
| 
 | ||||
| [](https://flattr.com/submit/auto?user_id=inputmice&url=https%3A%2F%2Fgithub.com%2Fsiacs%2FConversations) | ||||
| 
 | ||||
| ####How do I create an account? | ||||
| XMPP like email for example is a federated protocol which means that there is | ||||
| not one company you can create your 'official xmpp account' with but there are | ||||
|  |  | |||
|  | @ -0,0 +1,108 @@ | |||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| 
 | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="128" | ||||
|    height="128" | ||||
|    id="svg4066" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.48.5 r10040" | ||||
|    sodipodi:docname="ic_action_copy.svg"> | ||||
|   <defs | ||||
|      id="defs4068" /> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#000000" | ||||
|      borderopacity="0.54117647" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="2.67" | ||||
|      inkscape:cx="51.750573" | ||||
|      inkscape:cy="57.547291" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      borderlayer="false" | ||||
|      inkscape:window-width="1035" | ||||
|      inkscape:window-height="853" | ||||
|      inkscape:window-x="369" | ||||
|      inkscape:window-y="3" | ||||
|      inkscape:window-maximized="0" /> | ||||
|   <metadata | ||||
|      id="metadata4071"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(0,-924.36218)"> | ||||
|     <rect | ||||
|        ry="0" | ||||
|        height="91.708199" | ||||
|        width="71.625328" | ||||
|        stroke-miterlimit="4" | ||||
|        y="952.36743" | ||||
|        x="42.730034" | ||||
|        id="rect10" | ||||
|        style="fill:none;stroke:#000000;stroke-width:8.6679945;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.54117647;stroke-dasharray:none" | ||||
|        inkscape:transform-center-x="-21.391573" | ||||
|        inkscape:transform-center-y="28.294015" /> | ||||
|     <path | ||||
|        style="fill:#000000;fill-opacity:0.5411765;fill-rule:evenodd;stroke:#000000;stroke-width:0.41999999999999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.54117649999999995;stroke-miterlimit:4;stroke-dasharray:none" | ||||
|        d="m 20.552281,933.36985 0,0.0209 -0.128276,0 -0.399078,99.83215 0.213792,0 0,0.1463 13.212333,-0.021 0.05701,-8.1392 -4.076297,0.011 0.327814,-84.87039 58.436429,0 0.0285,3.427 11.10293,0 -0.0855,-9.25707 -0.057,0 0,-1.1493 -78.63263,0 z" | ||||
|        id="rect12-6" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|     <rect | ||||
|        height="4.7259107" | ||||
|        width="37.242958" | ||||
|        y="967.49921" | ||||
|        x="50.137043" | ||||
|        id="rect12" | ||||
|        style="fill:#000000;fill-opacity:0.54117647;fill-rule:evenodd;stroke:#000000;stroke-width:0.23799089px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.54117647" /> | ||||
|     <rect | ||||
|        style="fill:#000000;fill-opacity:0.54117647000000002;fill-rule:evenodd;stroke:#000000;stroke-width:0.274;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.54117647000000002;stroke-miterlimit:4;stroke-dasharray:none" | ||||
|        id="rect4272" | ||||
|        x="50.137043" | ||||
|        y="982.49921" | ||||
|        width="49.452484" | ||||
|        height="4.7259107" /> | ||||
|     <rect | ||||
|        height="4.7259107" | ||||
|        width="43.542446" | ||||
|        y="997.49921" | ||||
|        x="50.137043" | ||||
|        id="rect4274" | ||||
|        style="fill:#000000;fill-opacity:0.54117647;fill-rule:evenodd;stroke:#000000;stroke-width:0.2573325px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.54117647" /> | ||||
|     <rect | ||||
|        style="fill:#000000;fill-opacity:0.54117647;fill-rule:evenodd;stroke:#000000;stroke-width:0.25050664px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.54117647" | ||||
|        id="rect4276" | ||||
|        x="50.137043" | ||||
|        y="1012.4992" | ||||
|        width="41.263123" | ||||
|        height="4.7259107" /> | ||||
|     <rect | ||||
|        height="4.7259107" | ||||
|        width="49.397911" | ||||
|        y="1027.4993" | ||||
|        x="50.137043" | ||||
|        id="rect4278" | ||||
|        style="fill:#000000;fill-opacity:0.54117647;fill-rule:evenodd;stroke:#000000;stroke-width:0.27408957px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.54117647" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 4.1 KiB | 
|  | @ -1,6 +1,6 @@ | |||
| #!/bin/env ruby | ||||
| resolutions={'mdpi'=> 1, 'hdpi' => 1.5, 'xhdpi' => 2, 'xxhdpi' => 3} | ||||
| images = { 'conversations.svg' => ['ic_launcher',48], 'conversations_baloon.svg' => ['ic_activity', 32], 'conversations_mono.svg' => ['ic_notification',24], 'ic_received_indicator.svg' => ['ic_received_indicator',12] } | ||||
| images = { 'conversations.svg' => ['ic_launcher', 48], 'conversations_baloon.svg' => ['ic_activity', 32], 'conversations_mono.svg' => ['ic_notification', 24], 'ic_received_indicator.svg' => ['ic_received_indicator', 12], 'ic_action_copy.svg' => ['ic_action_copy', 32] } | ||||
| images.each do |source, result| | ||||
| 	resolutions.each do |name, factor| | ||||
| 		size = factor * result[1] | ||||
|  |  | |||
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 717 B | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 585 B | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 763 B | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.0 KiB | 
|  | @ -1,11 +1,11 @@ | |||
| <android.support.v4.widget.SlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:id="@+id/slidingpanelayout" | ||||
|     android:id="@+id/content_view_spl" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" > | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|         android:layout_width="324dp" | ||||
|         android:layout_width="300dp" | ||||
|         android:layout_height="match_parent" | ||||
|         android:background="@color/primarybackground" | ||||
|         android:orientation="vertical" > | ||||
|  | @ -1,5 +1,5 @@ | |||
| <android.support.v4.widget.SlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:id="@+id/slidingpanelayout" | ||||
|     android:id="@+id/content_view_spl" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" > | ||||
| 
 | ||||
|  | @ -1,11 +1,11 @@ | |||
| <android.support.v4.widget.SlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:id="@+id/slidingpanelayout" | ||||
|     android:id="@+id/content_view_spl" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" > | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|         android:layout_width="240dp" | ||||
|         android:layout_width="400dp" | ||||
|         android:layout_height="match_parent" | ||||
|         android:background="@color/primarybackground" | ||||
|         android:orientation="vertical" > | ||||
|  | @ -1,12 +1,14 @@ | |||
| <android.support.v4.widget.SlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:id="@+id/slidingpanelayout" | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:id="@+id/content_view_ll" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" > | ||||
|     android:layout_height="match_parent" | ||||
|     android:orientation="horizontal" | ||||
|     android:baselineAligned="false"> | ||||
| 
 | ||||
|     <LinearLayout | ||||
|         xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|         android:layout_width="288dp" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="match_parent" | ||||
|         android:layout_weight="1" | ||||
|         android:background="@color/primarybackground" | ||||
|         android:orientation="vertical" > | ||||
| 
 | ||||
|  | @ -21,10 +23,10 @@ | |||
| 
 | ||||
|     <LinearLayout | ||||
|         android:id="@+id/selected_conversation" | ||||
|         android:layout_width="fill_parent" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_weight="2" | ||||
|         android:layout_height="match_parent" | ||||
|         android:layout_weight="1" | ||||
|         android:orientation="vertical" > | ||||
|     </LinearLayout> | ||||
| 
 | ||||
| </android.support.v4.widget.SlidingPaneLayout> | ||||
| </LinearLayout> | ||||
|  | @ -180,13 +180,38 @@ | |||
|                     android:textSize="?attr/TextSizeHeadline" | ||||
|                     android:textStyle="bold" /> | ||||
| 
 | ||||
|                 <TextView | ||||
|                     android:id="@+id/otr_fingerprint" | ||||
|                 <RelativeLayout | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_marginTop="8dp" | ||||
|                     android:textSize="?attr/TextSizeBody" | ||||
|                     android:typeface="monospace" /> | ||||
|                     android:layout_height="match_parent" | ||||
|                     android:layout_marginTop="8dp"> | ||||
|                     <LinearLayout | ||||
|                         android:layout_width="wrap_content" | ||||
|                         android:layout_height="wrap_content" | ||||
|                         android:layout_alignParentLeft="true" | ||||
|                         android:layout_toLeftOf="@+id/action_copy_to_clipboard" | ||||
|                         android:orientation="vertical" | ||||
|                         android:layout_centerVertical="true"> | ||||
| 
 | ||||
|                         <TextView | ||||
|                             android:id="@+id/otr_fingerprint" | ||||
|                             android:layout_width="wrap_content" | ||||
|                             android:layout_height="wrap_content" | ||||
|                             android:textSize="?attr/TextSizeBody" | ||||
|                             android:typeface="monospace" /> | ||||
|                     </LinearLayout> | ||||
| 
 | ||||
|                     <ImageButton | ||||
|                         android:id="@+id/action_copy_to_clipboard" | ||||
|                         android:layout_width="32dp" | ||||
|                         android:layout_height="32dp" | ||||
|                         android:background="?android:selectableItemBackground" | ||||
|                         android:layout_alignParentRight="true" | ||||
|                         android:layout_centerVertical="true" | ||||
|                         android:padding="4dp" | ||||
|                         android:scaleType="fitXY" | ||||
|                         android:src="@drawable/ic_action_copy" | ||||
|                         android:visibility="invisible" /> | ||||
|                 </RelativeLayout> | ||||
|             </LinearLayout> | ||||
|         </LinearLayout> | ||||
|     </ScrollView> | ||||
|  | @ -226,4 +251,4 @@ | |||
|             android:textColor="@color/secondarytext" /> | ||||
|     </LinearLayout> | ||||
| 
 | ||||
| </RelativeLayout> | ||||
| </RelativeLayout> | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ | |||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:paddingTop="8dp" | ||||
|         android:text="Jabber ID" | ||||
|         android:text="@string/account_settings_jabber_id" | ||||
|         android:textColor="@color/primarytext" | ||||
|         android:textSize="?attr/TextSizeHeadline" /> | ||||
| 
 | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ | |||
|             android:layout_toLeftOf="@+id/textSendButton" | ||||
|             android:background="@color/primarybackground" | ||||
|             android:ems="10" | ||||
|             android:imeOptions="flagNoExtractUi" | ||||
|             android:imeOptions="flagNoExtractUi|actionSend" | ||||
|             android:inputType="textShortMessage|textMultiLine|textCapSentences" | ||||
|             android:minHeight="48dp" | ||||
|             android:minLines="1" | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| <android.support.v4.widget.SlidingPaneLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:id="@+id/slidingpanelayout" | ||||
|     android:id="@+id/content_view_spl" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" > | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:layout_width="fill_parent" | ||||
|     android:layout_height="wrap_content" > | ||||
|     android:layout_height="0dp" | ||||
|     android:background="#00000000"> | ||||
| 
 | ||||
| </RelativeLayout> | ||||
|  | @ -54,7 +54,7 @@ | |||
|                 android:text="@string/download_image" | ||||
|                 android:visibility="gone" /> | ||||
| 
 | ||||
|            <LinearLayout | ||||
|             <LinearLayout | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:orientation="horizontal" | ||||
|  | @ -65,12 +65,10 @@ | |||
|                     android:layout_width="?attr/TextSizeInfo" | ||||
|                     android:layout_height="?attr/TextSizeInfo" | ||||
|                     android:layout_gravity="center_vertical" | ||||
|                     android:gravity="center_vertical" | ||||
|                     android:src="@drawable/ic_secure_indicator" | ||||
|                     android:layout_marginRight="4sp" | ||||
|                     android:alpha="0.54"/> | ||||
|                  | ||||
|                | ||||
|                     android:alpha="0.54" | ||||
|                     android:gravity="center_vertical" | ||||
|                     android:src="@drawable/ic_secure_indicator" /> | ||||
| 
 | ||||
|                 <TextView | ||||
|                     android:id="@+id/message_time" | ||||
|  |  | |||
|  | @ -63,27 +63,25 @@ | |||
|                     android:textColor="@color/secondarytext" | ||||
|                     android:textSize="?attr/TextSizeInfo" /> | ||||
| 
 | ||||
|                  <ImageView | ||||
|                 <ImageView | ||||
|                     android:id="@+id/security_indicator" | ||||
|                     android:layout_width="?attr/TextSizeInfo" | ||||
|                     android:layout_height="?attr/TextSizeInfo" | ||||
|                     android:layout_gravity="center_vertical" | ||||
|                     android:gravity="center_vertical" | ||||
|                     android:src="@drawable/ic_secure_indicator" | ||||
|                     android:layout_marginLeft="4sp" | ||||
|                     android:alpha="0.54"/> | ||||
|                  | ||||
|                     android:alpha="0.54" | ||||
|                     android:gravity="center_vertical" | ||||
|                     android:src="@drawable/ic_secure_indicator" /> | ||||
| 
 | ||||
|                 <ImageView | ||||
|                     android:id="@+id/indicator_received" | ||||
|                     android:layout_width="?attr/TextSizeInfo" | ||||
|                     android:layout_height="?attr/TextSizeInfo" | ||||
|                     android:layout_gravity="center_vertical" | ||||
|                     android:gravity="center_vertical" | ||||
|                     android:src="@drawable/ic_received_indicator" | ||||
|                     android:layout_marginLeft="4sp" | ||||
|                     android:alpha="0.54"/> | ||||
| 
 | ||||
|                 | ||||
|                     android:alpha="0.54" | ||||
|                     android:gravity="center_vertical" | ||||
|                     android:src="@drawable/ic_received_indicator" /> | ||||
|             </LinearLayout> | ||||
|         </LinearLayout> | ||||
|     </LinearLayout> | ||||
|  | @ -99,4 +97,4 @@ | |||
|         android:scaleType="fitXY" | ||||
|         android:src="@drawable/ic_profile" /> | ||||
| 
 | ||||
| </RelativeLayout> | ||||
| </RelativeLayout> | ||||
|  | @ -20,5 +20,12 @@ | |||
|         <item>524288</item> | ||||
|         <item>1048576</item> | ||||
|     </string-array> | ||||
|     <string-array name="mute_options_descriptions"> | ||||
|         <item>30 Minuten</item> | ||||
|         <item>eine Stunde</item> | ||||
|         <item>2 Stunden</item> | ||||
|         <item>8 Stunden</item> | ||||
|         <item>bis auf Widerruf</item> | ||||
|     </string-array> | ||||
| 
 | ||||
| </resources> | ||||
|  | @ -259,5 +259,11 @@ | |||
|     <string name="pref_use_send_button_to_indicate_status">Absende-Knopf zeigt Online-Status an</string> | ||||
|     <string name="pref_use_send_button_to_indicate_status_summary">Absende-Knopf einfärben, um den Online-Status des Kontakts zu signalisieren</string> | ||||
|     <string name="pref_expert_options_other">Sonstiges</string> | ||||
|     <string name="pref_conference_name">Konferenz-Name</string> | ||||
|     <string name="pref_conference_name_summary">Konferenz-Thema statt Raum-JID als Name verwenden</string> | ||||
|     <string name="toast_message_otr_fingerprint">OTR Fingerabdruck in die Zwischenablage kopiert!</string> | ||||
|     <string name="conference_banned">Du wurdest aus dem Konferenzraum verbannt</string> | ||||
|     <string name="conference_members_only">Der Konferenzraum ist nur für Mitglieder</string> | ||||
|     <string name="conference_kicked">Du wurdest aus dem Konferenzraum geworfen</string> | ||||
| 
 | ||||
| </resources> | ||||
|  |  | |||
|  | @ -254,5 +254,16 @@ | |||
|     <string name="pref_expert_options_summary">Por favor, cuidado con estas opciones</string> | ||||
|     <string name="pref_use_larger_font">Incrementar tamaño de fuente</string> | ||||
|     <string name="pref_use_larger_font_summary">Usar fuentes grandes en toda la aplicación</string> | ||||
|     <string name="pref_use_send_button_to_indicate_status">Botón enviar indica estado</string> | ||||
|     <string name="pref_use_indicate_received">Solicitar entrega de mensaje</string> | ||||
|     <string name="pref_use_indicate_received_summary">Cuando el contacto reciba el mensaje será indicado con una marca verde. Cuidado, esto podría no funcionar en todos los casos.</string> | ||||
|     <string name="pref_use_send_button_to_indicate_status_summary">El color del botón enviar indica el estado del contacto</string> | ||||
|     <string name="pref_expert_options_other">Otros</string> | ||||
|     <string name="pref_conference_name">Nombre de conferencia</string> | ||||
|     <string name="pref_conference_name_summary">Usar el asunto de la conferencia en lugar del identificador jabber como nombre de conferencia</string> | ||||
|     <string name="toast_message_otr_fingerprint">¡Clave OTR copiada en el portapapeles!</string> | ||||
|     <string name="conference_banned">Tu entrada a esta conferencia ha sido prohibida</string> | ||||
|     <string name="conference_members_only">Esta conferencia es solo para miembros</string> | ||||
|     <string name="conference_kicked">Has sido expulsado de esta conferencia</string> | ||||
| 
 | ||||
| </resources> | ||||
|  | @ -26,8 +26,9 @@ | |||
|         <item>2 ordu</item> | ||||
|         <item>8 ordu</item> | ||||
|         <item>abisatu arte</item> | ||||
|         </string-array> | ||||
|         <integer-array name="mute_options_durations"> | ||||
|     </string-array> | ||||
| 
 | ||||
|     <integer-array name="mute_options_durations"> | ||||
|         <item>1800</item> | ||||
|         <item>3600</item> | ||||
|         <item>7200</item> | ||||
|  | @ -35,4 +36,4 @@ | |||
|         <item>-1</item> | ||||
|     </integer-array> | ||||
| 
 | ||||
| </resources> | ||||
| </resources> | ||||
|  | @ -256,5 +256,5 @@ | |||
|     <string name="pref_use_larger_font_summary">Letra tamaina handiagoa erabili aplikazio osoan zehar</string> | ||||
|     <string name="pref_use_send_button_to_indicate_status">Bidaltze botoiak egoera adierazten du</string> | ||||
|     <string name="pref_use_send_button_to_indicate_status_summary">Bidaltze botoia koloreztatu kontaktu baten egoera adierazteko</string> | ||||
|      | ||||
| </resources> | ||||
| 
 | ||||
| </resources> | ||||
|  | @ -0,0 +1,39 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
| 
 | ||||
|     <string-array name="resources"> | ||||
|         <item>手机</item> | ||||
|         <item>电话</item> | ||||
|         <item>平板电脑</item> | ||||
|         <item>Conversations</item> | ||||
|         <item>Android</item> | ||||
|     </string-array> | ||||
|     <string-array name="filesizes"> | ||||
|         <item>永不</item> | ||||
|         <item>256 KB</item> | ||||
|         <item>512 KB</item> | ||||
|         <item>1 MB</item> | ||||
|     </string-array> | ||||
|     <string-array name="filesizes_values"> | ||||
|         <item>0</item> | ||||
|         <item>262144</item> | ||||
|         <item>524288</item> | ||||
|         <item>1048576</item> | ||||
|     </string-array> | ||||
|     <string-array name="mute_options_descriptions"> | ||||
|         <item>30 分钟</item> | ||||
|         <item>1 小时</item> | ||||
|         <item>2 小时</item> | ||||
|         <item>8 小时</item> | ||||
|         <item>直至另行取消</item> | ||||
|     </string-array> | ||||
| 
 | ||||
|     <integer-array name="mute_options_durations"> | ||||
|         <item>1800</item> | ||||
|         <item>3600</item> | ||||
|         <item>7200</item> | ||||
|         <item>28800</item> | ||||
|         <item>-1</item> | ||||
|     </integer-array> | ||||
| 
 | ||||
| </resources> | ||||
|  | @ -0,0 +1,39 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
| 
 | ||||
|     <string-array name="resources"> | ||||
|         <item>手機</item> | ||||
|         <item>電話</item> | ||||
|         <item>平板電腦</item> | ||||
|         <item>Conversations</item> | ||||
|         <item>Android</item> | ||||
|     </string-array> | ||||
|     <string-array name="filesizes"> | ||||
|         <item>永不</item> | ||||
|         <item>256 KB</item> | ||||
|         <item>512 KB</item> | ||||
|         <item>1 MB</item> | ||||
|     </string-array> | ||||
|     <string-array name="filesizes_values"> | ||||
|         <item>0</item> | ||||
|         <item>262144</item> | ||||
|         <item>524288</item> | ||||
|         <item>1048576</item> | ||||
|     </string-array> | ||||
|     <string-array name="mute_options_descriptions"> | ||||
|         <item>30 分鐘</item> | ||||
|         <item>1 小時</item> | ||||
|         <item>2 小時</item> | ||||
|         <item>8 小時</item> | ||||
|         <item>直至另行取消</item> | ||||
|     </string-array> | ||||
| 
 | ||||
|     <integer-array name="mute_options_durations"> | ||||
|         <item>1800</item> | ||||
|         <item>3600</item> | ||||
|         <item>7200</item> | ||||
|         <item>28800</item> | ||||
|         <item>-1</item> | ||||
|     </integer-array> | ||||
| 
 | ||||
| </resources> | ||||
|  | @ -0,0 +1,263 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
| 
 | ||||
|     <string name="app_name">Conversations</string> | ||||
|     <string name="action_settings">設定</string> | ||||
|     <string name="action_add">新對話</string> | ||||
|     <string name="action_accounts">管理帳戶</string> | ||||
|     <string name="action_end_conversation">結束對話</string> | ||||
|     <string name="action_contact_details">聯絡人詳情</string> | ||||
|     <string name="action_secure">安全對話</string> | ||||
|     <string name="action_add_account">新增帳戶</string> | ||||
|     <string name="action_edit_contact">編輯姓名</string> | ||||
|     <string name="action_add_phone_book">新增到手機通訊錄</string> | ||||
|     <string name="action_delete_contact">從列表中刪除</string> | ||||
|     <string name="title_activity_manage_accounts">管理帳戶</string> | ||||
|     <string name="title_activity_conference_details">群組詳情</string> | ||||
|     <string name="title_activity_contact_details">聯絡人詳情</string> | ||||
|     <string name="title_activity_conversations">對話</string> | ||||
|     <string name="title_activity_sharewith">分享對話</string> | ||||
|     <string name="title_activity_start_conversation">開始對話</string> | ||||
|     <string name="title_activity_choose_contact">選擇聯絡人</string> | ||||
|     <string name="just_now">剛剛</string> | ||||
|     <string name="minute_ago">1 分鐘前</string> | ||||
|     <string name="minutes_ago">%d 分鐘前</string> | ||||
|     <string name="unread_conversations">未讀對話</string> | ||||
|     <string name="sending">正在發送…</string> | ||||
|     <string name="encrypted_message">正在解密訊息中,請稍候…</string> | ||||
|     <string name="nick_in_use">該用戶名稱已被使用</string> | ||||
|     <string name="admin">管理員</string> | ||||
|     <string name="owner">擁有人</string> | ||||
|     <string name="moderator">版主</string> | ||||
|     <string name="participant">成員</string> | ||||
|     <string name="visitor">訪客</string> | ||||
|     <string name="remove_contact_text">你確定要將 %s 從聯絡人清單中移除嗎?與該聯絡人的對話將不會被清除。</string> | ||||
|     <string name="remove_bookmark_text">你確定要將 %s 從書籤清單中移除嗎?與該聯絡人的對話將不會被清除。</string> | ||||
|     <string name="register_account">在伺服器上註冊新帳戶</string> | ||||
|     <string name="share_with">分享</string> | ||||
|     <string name="start_conversation">開始對話</string> | ||||
|     <string name="invite_contact">邀請聯絡人</string> | ||||
|     <string name="contacts">聯絡人</string> | ||||
|     <string name="cancel">取消</string> | ||||
|     <string name="add">新增</string> | ||||
|     <string name="edit">編輯</string> | ||||
|     <string name="delete">刪除</string> | ||||
|     <string name="save">儲存</string> | ||||
|     <string name="ok">好的</string> | ||||
|     <string name="crash_report_title">Conversations 停止運行</string> | ||||
|     <string name="crash_report_message">發送「堆疊追蹤」給 Conversations 的開發人員能幫助改進本程式。\n<b>警告:</b> 你的 XMPP 帳戶將被用作發送有關訊息之用。</string> | ||||
|     <string name="send_now">現在發送</string> | ||||
|     <string name="send_never">不再詢問</string> | ||||
|     <string name="problem_connecting_to_account">無法連接至帳戶</string> | ||||
|     <string name="problem_connecting_to_accounts">無法連接至多個帳戶</string> | ||||
|     <string name="touch_to_fix">點擊此處管理帳戶。</string> | ||||
|     <string name="attach_file">附件</string> | ||||
|     <string name="not_in_roster">該聯絡人不在你的聯絡人清單上,需要加為聯絡人嗎?</string> | ||||
|     <string name="add_contact">新增聯絡人</string> | ||||
|     <string name="send_failed">傳遞失敗</string> | ||||
|     <string name="send_rejected">拒絕</string> | ||||
|     <string name="receiving_image">接收圖片文件中,請稍候…</string> | ||||
|     <string name="preparing_image">準備傳輸圖片</string> | ||||
|     <string name="action_clear_history">清除歷史記錄</string> | ||||
|     <string name="clear_conversation_history">清除對話記錄</string> | ||||
|     <string name="clear_histor_msg">你確定要刪除該對話中所有訊息嗎?\n\n<b>警告:</b> 這將不會影響其他設備或伺服器儲存的訊息。</string> | ||||
|     <string name="delete_messages">刪除訊息</string> | ||||
|     <string name="also_end_conversation">之後結束這對話</string> | ||||
|     <string name="choose_presence">選擇狀態訊息</string> | ||||
|     <string name="send_plain_text_message">發送純文字訊息</string> | ||||
|     <string name="send_otr_message">發送 OTR 加密訊息</string> | ||||
|     <string name="send_pgp_message">發送 OpenPGP 加密訊息</string> | ||||
|     <string name="your_nick_has_been_changed">用戶名稱修改成功</string> | ||||
|     <string name="download_image">下載圖片</string> | ||||
|     <string name="image_offered_for_download"><i>可供下載的圖像文件</i></string> | ||||
|     <string name="send_unencrypted">不加密發送</string> | ||||
|     <string name="decryption_failed">解密失敗,可能是私鑰不正確。</string> | ||||
|     <string name="openkeychain_required">OpenKeychain</string> | ||||
|     <string name="openkeychain_required_long">Conversations 使用一個名為 <b>OpenKeychain</b> 的第三方程式來加密、解碼訊息以及管理您的公鑰。\n\nOpenKeychain 以 GPLv3 釋出,並可在 F-Droid 和 Google Play 上下載。\n\n<small>(之後請重新啟動 Conversations。)</small></string> | ||||
|     <string name="restart">重新啟動</string> | ||||
| 	<string name="install">安裝</string> | ||||
|     <string name="offering">提供中…</string> | ||||
|     <string name="waiting">等待中…</string> | ||||
|     <string name="no_pgp_key">找不到 OpenPGP 鑰匙</string> | ||||
|     <string name="contact_has_no_pgp_key">Conversations 不能將你的訊息加密,因為聯絡人沒有公佈他/她的公鑰。\n\n<small>請通知聯絡人設定 OpenPGP。</small></string> | ||||
|     <string name="no_pgp_keys">找不到多條 OpenPGP 鑰匙</string> | ||||
|     <string name="contacts_have_no_pgp_keys">Conversations 不能將你的訊息加密,因為多位聯絡人沒有公佈他/她的公鑰。\n\n<small>請通知聯絡人設定 OpenPGP。</small></string> | ||||
|     <string name="encrypted_message_received"><i>已收到加密訊息,點擊進行解密和查看。</i></string> | ||||
|     <string name="encrypted_image_received"><i>已收到加密圖片,點擊進行解密和查看。</i></string> | ||||
|     <string name="image_file"><i>已收到圖片,點擊查看</i></string> | ||||
|     <string name="pref_general">一般</string> | ||||
|     <string name="pref_xmpp_resource">XMPP 資源</string> | ||||
|     <string name="pref_xmpp_resource_summary">客戶端標示名稱</string> | ||||
|     <string name="pref_accept_files">接收文件</string> | ||||
|     <string name="pref_accept_files_summary">自動接收小於 … 的文件</string> | ||||
|     <string name="pref_notification_settings">通知設定</string> | ||||
|     <string name="pref_notifications">通知</string> | ||||
|     <string name="pref_notifications_summary">收到新訊息時通知</string> | ||||
|     <string name="pref_vibrate">震動</string> | ||||
|     <string name="pref_vibrate_summary">收到新訊息時震動</string> | ||||
|     <string name="pref_sound">聲音</string> | ||||
|     <string name="pref_sound_summary">收到新訊息時播放鈴聲</string> | ||||
|     <string name="pref_conference_notifications">群組通知</string> | ||||
|     <string name="pref_conference_notifications_summary">當有新訊息時總是通知,而不是被標記時才通知</string> | ||||
|     <string name="pref_notification_grace_period">通知限期</string> | ||||
|     <string name="pref_notification_grace_period_summary">收到副本後,關閉通知一小段時間</string> | ||||
|     <string name="pref_advanced_options">進階選項</string> | ||||
|     <string name="pref_never_send_crash">總是不發送故障報告</string> | ||||
|     <string name="pref_never_send_crash_summary">發送「堆疊追蹤」給 Conversations 的開發人員能幫助改進本程式</string> | ||||
|     <string name="pref_confirm_messages">確認訊息</string> | ||||
|     <string name="pref_confirm_messages_summary">讓你的聯絡人知道你已收到及閱讀訊息</string> | ||||
|     <string name="pref_ui_options">介面選項</string> | ||||
|     <string name="openpgp_error">OpenKeychain 回報了一個錯誤</string> | ||||
|     <string name="error_decrypting_file">解密文件時出現 I/O 錯誤</string> | ||||
|     <string name="accept">接受</string> | ||||
|     <string name="error">發生了一個錯誤</string> | ||||
|     <string name="pref_grant_presence_updates">同意更新狀態訊息</string> | ||||
|     <string name="pref_grant_presence_updates_summary">預先更新狀態訊息並關注聯絡人的狀態訊息</string> | ||||
|     <string name="subscriptions">關注</string> | ||||
|     <string name="your_account">你的帳戶</string> | ||||
|     <string name="keys">鑰匙</string> | ||||
|     <string name="send_presence_updates">發送狀態訊息</string> | ||||
|     <string name="receive_presence_updates">接收狀態訊息</string> | ||||
|     <string name="ask_for_presence_updates">關注狀態訊息</string> | ||||
|     <string name="attach_choose_picture">選擇圖片</string> | ||||
|     <string name="attach_take_picture">拍照</string> | ||||
|     <string name="preemptively_grant">預先同意關注請求</string> | ||||
|     <string name="error_not_an_image_file">您選擇的文件不是圖片</string> | ||||
|     <string name="error_compressing_image">轉換圖片時發生錯誤</string> | ||||
|     <string name="error_file_not_found">找不到文件</string> | ||||
|     <string name="error_io_exception">一般的 I/O 錯誤。是存儲空間不足嗎?</string> | ||||
|     <string name="error_security_exception_during_image_copy">你用來選擇圖片的 app 沒有給予足夠權限我們去讀取文件。\n\n<small>請使用另一文件管理器來選擇圖片</small></string> | ||||
|     <string name="account_status_unknown">未知</string> | ||||
|     <string name="account_status_disabled">暫時停用</string> | ||||
|     <string name="account_status_online">在線</string> | ||||
|     <string name="account_status_connecting">連接中\u2026</string> | ||||
|     <string name="account_status_offline">離線</string> | ||||
|     <string name="account_status_unauthorized">未授權</string> | ||||
|     <string name="account_status_not_found">未找到伺服器</string> | ||||
|     <string name="account_status_no_internet">未連接網絡</string> | ||||
|     <string name="account_status_regis_fail">註冊失敗</string> | ||||
|     <string name="account_status_regis_conflict">該用戶名稱已被使用</string> | ||||
|     <string name="account_status_regis_success">註冊完成</string> | ||||
|     <string name="account_status_regis_not_sup">伺服器不支持註冊</string> | ||||
|     <string name="encryption_choice_none">純文字內容</string> | ||||
|     <string name="encryption_choice_otr">OTR</string> | ||||
|     <string name="encryption_choice_pgp">OpenPGP</string> | ||||
|     <string name="mgmt_account_edit">編輯帳戶</string> | ||||
|     <string name="mgmt_account_delete">刪除帳戶</string> | ||||
|     <string name="mgmt_account_disable">暫時停用</string> | ||||
|     <string name="mgmt_account_publish_avatar">發佈頭像</string> | ||||
|     <string name="mgmt_account_publish_pgp">發布 OpenPGP 公共鑰匙</string> | ||||
|     <string name="mgmt_account_enable">啟用帳戶</string> | ||||
|     <string name="mgmt_account_are_you_sure">你確定嗎?</string> | ||||
|     <string name="mgmt_account_delete_confirm_text">如果刪除帳戶,則所有對話訊息將會被刪除</string> | ||||
|     <string name="attach_record_voice">錄音</string> | ||||
|     <string name="account_settings_jabber_id">Jabber ID</string> | ||||
|     <string name="account_settings_password">密碼</string> | ||||
|     <string name="account_settings_example_jabber_id">username@example.com</string> | ||||
|     <string name="account_settings_confirm_password">確認密碼</string> | ||||
|     <string name="password">密碼</string> | ||||
|     <string name="confirm_password">確認密碼</string> | ||||
|     <string name="passwords_do_not_match">密碼不一致</string> | ||||
|     <string name="invalid_jid">該 Jabber ID 無效</string> | ||||
|     <string name="error_out_of_memory">空間不足,圖片過大</string> | ||||
|     <string name="add_phone_book_text">你確定要新增 %s 為聯絡人嗎?</string> | ||||
|     <string name="contact_status_online">線上</string> | ||||
|     <string name="contact_status_free_to_chat">目前有空</string> | ||||
|     <string name="contact_status_away">離開</string> | ||||
|     <string name="contact_status_extended_away">長時間離開</string> | ||||
|     <string name="contact_status_do_not_disturb">請勿打擾</string> | ||||
|     <string name="contact_status_offline">離線</string> | ||||
|     <string name="muc_details_conference">群組</string> | ||||
|     <string name="muc_details_other_members">其他成員</string> | ||||
|     <string name="server_info_carbon_messages">XEP-0280: Message Carbons</string> | ||||
|     <string name="server_info_stream_management">XEP-0198: Stream Management</string> | ||||
|     <string name="server_info_pep">XEP-0163: PEP (Avatars)</string> | ||||
|     <string name="server_info_available">支援</string> | ||||
|     <string name="server_info_unavailable">不支援</string> | ||||
|     <string name="missing_public_keys">沒有公佈公鑰訊息。</string> | ||||
|     <string name="last_seen_now">剛剛曾在線上</string> | ||||
|     <string name="last_seen_min">一分鐘前曾在線上</string> | ||||
|     <string name="last_seen_mins">%d 分鐘前曾在線上</string> | ||||
|     <string name="last_seen_hour">一小時前曾在線上</string> | ||||
|     <string name="last_seen_hours">%d 小時前曾在線上</string> | ||||
|     <string name="last_seen_day">一天前曾在線上</string> | ||||
|     <string name="last_seen_days">%d 天前曾在線上</string> | ||||
|     <string name="never_seen">未曾上線</string> | ||||
|     <string name="install_openkeychain">加密的訊息。請安裝 OpenKeychain 以解密。</string> | ||||
|     <string name="unknown_otr_fingerprint">未知的 OTR 指紋</string> | ||||
|     <string name="openpgp_messages_found">發現以 OpenPGP 加密的訊息</string> | ||||
|     <string name="reception_failed">接收失敗</string> | ||||
|     <string name="your_fingerprint">你的指紋</string> | ||||
|     <string name="otr_fingerprint">OTR 指紋</string> | ||||
|     <string name="verify">驗證</string> | ||||
|     <string name="decrypt">解密</string> | ||||
|     <string name="conferences">群組</string> | ||||
|     <string name="search">查找</string> | ||||
|     <string name="create_contact">新增聯絡人</string> | ||||
|     <string name="join_conference">加入群組</string> | ||||
|     <string name="delete_contact">刪除聯絡人</string> | ||||
|     <string name="view_contact_details">查看聯絡人詳細訊息</string> | ||||
|     <string name="create">新增</string> | ||||
|     <string name="contact_already_exists">聯絡人已存在</string> | ||||
|     <string name="join">加入</string> | ||||
|     <string name="conference_address">群組地址</string> | ||||
|     <string name="conference_address_example">room@conference.example.com</string> | ||||
|     <string name="save_as_bookmark">儲存為書籤</string> | ||||
|     <string name="delete_bookmark">刪除書籤</string> | ||||
|     <string name="bookmark_already_exists">該書籤已存在</string> | ||||
|     <string name="you">你</string> | ||||
|     <string name="action_edit_subject">編輯群組主題</string> | ||||
|     <string name="conference_not_found">群組未找到</string> | ||||
|     <string name="leave">離開</string> | ||||
|     <string name="contact_added_you">聯絡人已新增你到聯絡人列表</string> | ||||
|     <string name="add_back">新增為聯絡人</string> | ||||
|     <string name="contact_has_read_up_to_this_point">%s 讀到此處</string> | ||||
|     <string name="publish">發佈</string> | ||||
|     <string name="touch_to_choose_picture">點擊頭像可選擇頭像</string> | ||||
|     <string name="publish_avatar_explanation">請注意: 所有關注你狀態訊息的人將看到該圖像。</string> | ||||
|     <string name="publishing">發佈中…</string> | ||||
|     <string name="error_publish_avatar_server_reject">伺服器拒絕了你的發佈請求</string> | ||||
|     <string name="error_publish_avatar_converting">發佈頭像時發生錯誤</string> | ||||
|     <string name="error_saving_avatar">將頭像儲存至硬碟時發生錯誤</string> | ||||
|     <string name="or_long_press_for_default">(或長按以回復預設頭像)</string> | ||||
|     <string name="error_publish_avatar_no_server_support">你的伺服器不支持發佈頭像</string> | ||||
|     <string name="private_message">私密聊天</string> | ||||
|     <string name="private_message_to">給 %s</string> | ||||
|     <string name="send_private_message_to">發送私密消息給 %s</string> | ||||
|     <string name="connect">連接</string> | ||||
|     <string name="account_already_exists">該帳戶已存在</string> | ||||
|     <string name="next">下一步</string> | ||||
|     <string name="server_info_session_established">已建立連接</string> | ||||
|     <string name="additional_information">其他訊息</string> | ||||
|     <string name="skip">略過</string> | ||||
|     <string name="disable_notifications">關閉通知</string> | ||||
|     <string name="disable_notifications_for_this_conversation">關閉該對話消息</string> | ||||
|     <string name="notifications_disabled">通知已關閉</string> | ||||
|     <string name="enable">打開通知</string> | ||||
|     <string name="conference_requires_password">群組設有密碼</string> | ||||
|     <string name="enter_password">輸入密碼</string> | ||||
|     <string name="missing_presence_updates">缺少聯絡人狀態訊息</string> | ||||
|     <string name="request_presence_updates">請先發送關注狀態訊息請求。\n\n<small>這將用來判斷您的聯絡人所用的客戶端類型。</small></string> | ||||
|     <string name="request_now">現在發送請求</string> | ||||
|     <string name="delete_fingerprint">刪除指紋</string> | ||||
|     <string name="sure_delete_fingerprint">你確定刪除該指紋嗎?</string> | ||||
|     <string name="ignore">忽略</string> | ||||
|     <string name="without_mutual_presence_updates"><b>警告:</b> 在沒有互相關注狀態訊息的情況下發送或會引起不能預計的問題。\n\n<small>請檢視聯絡人詳情頁面以確認你們的關注狀態。</small></string> | ||||
|     <string name="pref_encryption_settings">加密設定</string> | ||||
|     <string name="pref_force_encryption">強制要求端到端加密</string> | ||||
|     <string name="pref_force_encryption_summary">總是發送加密訊息 (群組訊息除外)</string> | ||||
|     <string name="pref_dont_save_encrypted">不儲存加密訊息</string> | ||||
|     <string name="pref_dont_save_encrypted_summary">警告: 此操作或會導致訊息丟失</string> | ||||
|     <string name="pref_expert_options">專家選項</string> | ||||
|     <string name="pref_expert_options_summary">請小心設定</string> | ||||
|     <string name="pref_use_larger_font">增加字體大小</string> | ||||
|     <string name="pref_use_larger_font_summary">讓整個 app 界面使用更大號的字體</string> | ||||
|     <string name="pref_use_send_button_to_indicate_status">用「發送」按鈕顯示狀態訊息</string> | ||||
|     <string name="pref_use_indicate_received">要求讀取收據</string> | ||||
|     <string name="pref_use_indicate_received_summary">已被讀取的訊息會以綠色勾號表示。請注意,這個功能未必每次有效。</string> | ||||
|     <string name="pref_use_send_button_to_indicate_status_summary">將「發送」按鈕設成不同顏色,以表示不同的狀態訊息。</string> | ||||
|     <string name="pref_expert_options_other">其他</string> | ||||
|     <string name="pref_conference_name">群組名稱</string> | ||||
|     <string name="pref_conference_name_summary">使用群組的名稱而不是 JID 來識別之。 </string> | ||||
| 
 | ||||
| </resources> | ||||
|  | @ -261,5 +261,9 @@ | |||
|     <string name="pref_expert_options_other">Other</string> | ||||
|     <string name="pref_conference_name">Conference name</string> | ||||
|     <string name="pref_conference_name_summary">Use room’s subject instead of JID to identify conferences</string> | ||||
|     <string name="toast_message_otr_fingerprint">OTR fingerprint copied to clipboard!</string> | ||||
|     <string name="conference_banned">You are banned from this conference</string> | ||||
|     <string name="conference_members_only">This conference is members only</string> | ||||
|     <string name="conference_kicked">You have been kicked from this conference</string> | ||||
| 
 | ||||
| </resources> | ||||
| </resources> | ||||
|  |  | |||
|  | @ -52,15 +52,9 @@ | |||
| 
 | ||||
|         <CheckBoxPreference | ||||
|             android:dependency="show_notification" | ||||
|             android:key="notify_in_conversation_when_highlighted" | ||||
|             android:key="always_notify_in_conference" | ||||
|             android:summary="@string/pref_conference_notifications_summary" | ||||
|             android:title="@string/pref_conference_notifications" /> | ||||
|         <CheckBoxPreference | ||||
|             android:defaultValue="true" | ||||
|             android:dependency="show_notification" | ||||
|             android:key="notification_grace_period_after_carbon_received" | ||||
|             android:summary="@string/pref_notification_grace_period_summary" | ||||
|             android:title="@string/pref_notification_grace_period" /> | ||||
|     </PreferenceCategory> | ||||
|     <PreferenceCategory android:title="@string/pref_ui_options" > | ||||
|         <CheckBoxPreference | ||||
|  | @ -95,13 +89,13 @@ | |||
|                     android:summary="@string/pref_dont_save_encrypted_summary" | ||||
|                     android:title="@string/pref_dont_save_encrypted" /> | ||||
|             </PreferenceCategory> | ||||
|                 <PreferenceCategory android:title="@string/pref_expert_options_other" > | ||||
|                     <CheckBoxPreference | ||||
|                         android:defaultValue="false" | ||||
|                         android:key="indicate_received" | ||||
|                         android:summary="@string/pref_use_indicate_received_summary" | ||||
|                         android:title="@string/pref_use_indicate_received" /> | ||||
|                 </PreferenceCategory> | ||||
|             <PreferenceCategory android:title="@string/pref_expert_options_other" > | ||||
|                 <CheckBoxPreference | ||||
|                     android:defaultValue="false" | ||||
|                     android:key="indicate_received" | ||||
|                     android:summary="@string/pref_use_indicate_received_summary" | ||||
|                     android:title="@string/pref_use_indicate_received" /> | ||||
|             </PreferenceCategory> | ||||
|         </PreferenceScreen> | ||||
| 
 | ||||
|         <CheckBoxPreference | ||||
|  | @ -111,4 +105,4 @@ | |||
|             android:title="@string/pref_never_send_crash" /> | ||||
|     </PreferenceCategory> | ||||
| 
 | ||||
| </PreferenceScreen> | ||||
| </PreferenceScreen> | ||||
|  | @ -10,7 +10,7 @@ public final class Config { | |||
| 	public static final int PING_MIN_INTERVAL = 30; | ||||
| 	public static final int PING_TIMEOUT = 10; | ||||
| 	public static final int CONNECT_TIMEOUT = 90; | ||||
| 	public static final int CARBON_GRACE_PERIOD = 60; | ||||
| 	public static final int CARBON_GRACE_PERIOD = 120; | ||||
| 
 | ||||
| 	public static final int AVATAR_SIZE = 192; | ||||
| 	public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP; | ||||
|  |  | |||
|  | @ -7,46 +7,35 @@ import android.graphics.Bitmap; | |||
| import eu.siacs.conversations.utils.UIHelper; | ||||
| import eu.siacs.conversations.xml.Element; | ||||
| 
 | ||||
| public class Bookmark implements ListItem { | ||||
| public class Bookmark extends Element implements ListItem { | ||||
| 
 | ||||
| 	private Account account; | ||||
| 	private String jid; | ||||
| 	private String nick; | ||||
| 	private String name; | ||||
| 	private String password; | ||||
| 	private boolean autojoin; | ||||
| 	private boolean providePassword; | ||||
| 	private Conversation mJoinedConversation; | ||||
| 
 | ||||
| 	public Bookmark(Account account, String jid) { | ||||
| 		super("conference"); | ||||
| 		this.setAttribute("jid", jid); | ||||
| 		this.account = account; | ||||
| 	} | ||||
| 
 | ||||
| 	private Bookmark(Account account) { | ||||
| 		super("conference"); | ||||
| 		this.account = account; | ||||
| 		this.jid = jid; | ||||
| 	} | ||||
| 
 | ||||
| 	public static Bookmark parse(Element element, Account account) { | ||||
| 		Bookmark bookmark = new Bookmark(account, element.getAttribute("jid")); | ||||
| 		bookmark.setName(element.getAttribute("name")); | ||||
| 		String autojoin = element.getAttribute("autojoin"); | ||||
| 		if (autojoin != null | ||||
| 				&& (autojoin.equals("true") || autojoin.equals("1"))) { | ||||
| 			bookmark.setAutojoin(true); | ||||
| 		} else { | ||||
| 			bookmark.setAutojoin(false); | ||||
| 		} | ||||
| 		Element nick = element.findChild("nick"); | ||||
| 		if (nick != null) { | ||||
| 			bookmark.setNick(nick.getContent()); | ||||
| 		} | ||||
| 		Element password = element.findChild("password"); | ||||
| 		if (password != null) { | ||||
| 			bookmark.setPassword(password.getContent()); | ||||
| 			bookmark.setProvidePassword(true); | ||||
| 		} | ||||
| 		Bookmark bookmark = new Bookmark(account); | ||||
| 		bookmark.setAttributes(element.getAttributes()); | ||||
| 		bookmark.setChildren(element.getChildren()); | ||||
| 		return bookmark; | ||||
| 	} | ||||
| 
 | ||||
| 	public void setAutojoin(boolean autojoin) { | ||||
| 		this.autojoin = autojoin; | ||||
| 		if (autojoin) { | ||||
| 			this.setAttribute("autojoin", "true"); | ||||
| 		} else { | ||||
| 			this.setAttribute("autojoin", "false"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void setName(String name) { | ||||
|  | @ -54,15 +43,18 @@ public class Bookmark implements ListItem { | |||
| 	} | ||||
| 
 | ||||
| 	public void setNick(String nick) { | ||||
| 		this.nick = nick; | ||||
| 		Element element = this.findChild("nick"); | ||||
| 		if (element == null) { | ||||
| 			element = this.addChild("nick"); | ||||
| 		} | ||||
| 		element.setContent(nick); | ||||
| 	} | ||||
| 
 | ||||
| 	public void setPassword(String password) { | ||||
| 		this.password = password; | ||||
| 	} | ||||
| 
 | ||||
| 	private void setProvidePassword(boolean providePassword) { | ||||
| 		this.providePassword = providePassword; | ||||
| 		Element element = this.findChild("password"); | ||||
| 		if (element != null) { | ||||
| 			element.setContent(password); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
|  | @ -76,32 +68,45 @@ public class Bookmark implements ListItem { | |||
| 		if (this.mJoinedConversation != null | ||||
| 				&& (this.mJoinedConversation.getMucOptions().getSubject() != null)) { | ||||
| 			return this.mJoinedConversation.getMucOptions().getSubject(); | ||||
| 		} else if (name != null) { | ||||
| 			return name; | ||||
| 		} else if (getName() != null) { | ||||
| 			return getName(); | ||||
| 		} else { | ||||
| 			return this.jid.split("@")[0]; | ||||
| 			return this.getJid().split("@")[0]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public String getJid() { | ||||
| 		return this.jid.toLowerCase(Locale.US); | ||||
| 		String jid = this.getAttribute("jid"); | ||||
| 		if (jid != null) { | ||||
| 			return jid.toLowerCase(Locale.US); | ||||
| 		} else { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public String getNick() { | ||||
| 		return this.nick; | ||||
| 		Element nick = this.findChild("nick"); | ||||
| 		if (nick != null) { | ||||
| 			return nick.getContent(); | ||||
| 		} else { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean autojoin() { | ||||
| 		return autojoin; | ||||
| 		String autojoin = this.getAttribute("autojoin"); | ||||
| 		return (autojoin != null && (autojoin.equalsIgnoreCase("true") || autojoin | ||||
| 				.equalsIgnoreCase("1"))); | ||||
| 	} | ||||
| 
 | ||||
| 	public String getPassword() { | ||||
| 		return this.password; | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean isProvidePassword() { | ||||
| 		return this.providePassword; | ||||
| 		Element password = this.findChild("password"); | ||||
| 		if (password != null) { | ||||
| 			return password.getContent(); | ||||
| 		} else { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean match(String needle) { | ||||
|  | @ -131,27 +136,7 @@ public class Bookmark implements ListItem { | |||
| 	} | ||||
| 
 | ||||
| 	public String getName() { | ||||
| 		return name; | ||||
| 	} | ||||
| 
 | ||||
| 	public Element toElement() { | ||||
| 		Element element = new Element("conference"); | ||||
| 		element.setAttribute("jid", this.getJid()); | ||||
| 		if (this.getName() != null) { | ||||
| 			element.setAttribute("name", this.getName()); | ||||
| 		} | ||||
| 		if (this.autojoin) { | ||||
| 			element.setAttribute("autojoin", "true"); | ||||
| 		} else { | ||||
| 			element.setAttribute("autojoin", "false"); | ||||
| 		} | ||||
| 		if (this.nick != null) { | ||||
| 			element.addChild("nick").setContent(this.nick); | ||||
| 		} | ||||
| 		if (this.password != null && isProvidePassword()) { | ||||
| 			element.addChild("password").setContent(this.password); | ||||
| 		} | ||||
| 		return element; | ||||
| 		return this.getAttribute("name"); | ||||
| 	} | ||||
| 
 | ||||
| 	public void unregisterConversation() { | ||||
|  |  | |||
|  | @ -156,6 +156,7 @@ public class Contact implements ListItem { | |||
| 
 | ||||
| 	public void clearPresences() { | ||||
| 		this.presences.clearPresences(); | ||||
| 		this.resetOption(Options.PENDING_SUBSCRIPTION_REQUEST); | ||||
| 	} | ||||
| 
 | ||||
| 	public int getMostAvailableStatus() { | ||||
|  |  | |||
|  | @ -4,6 +4,9 @@ import java.security.interfaces.DSAPublicKey; | |||
| import java.util.List; | ||||
| import java.util.concurrent.CopyOnWriteArrayList; | ||||
| 
 | ||||
| import org.json.JSONException; | ||||
| import org.json.JSONObject; | ||||
| 
 | ||||
| import eu.siacs.conversations.services.XmppConnectionService; | ||||
| import eu.siacs.conversations.utils.UIHelper; | ||||
| 
 | ||||
|  | @ -36,6 +39,11 @@ public class Conversation extends AbstractEntity { | |||
| 	public static final String STATUS = "status"; | ||||
| 	public static final String CREATED = "created"; | ||||
| 	public static final String MODE = "mode"; | ||||
| 	public static final String ATTRIBUTES = "attributes"; | ||||
| 
 | ||||
| 	public static final String ATTRIBUTE_NEXT_ENCRYPTION = "next_encryption"; | ||||
| 	public static final String ATTRIBUTE_MUC_PASSWORD = "muc_password"; | ||||
| 	public static final String ATTRIBUTE_MUTED_TILL = "muted_till"; | ||||
| 
 | ||||
| 	private String name; | ||||
| 	private String contactUuid; | ||||
|  | @ -45,7 +53,7 @@ public class Conversation extends AbstractEntity { | |||
| 	private long created; | ||||
| 	private int mode; | ||||
| 
 | ||||
| 	private long mutedTill = 0; | ||||
| 	private JSONObject attributes = new JSONObject(); | ||||
| 
 | ||||
| 	private String nextPresence; | ||||
| 
 | ||||
|  | @ -56,12 +64,11 @@ public class Conversation extends AbstractEntity { | |||
| 
 | ||||
| 	private transient String otrFingerprint = null; | ||||
| 
 | ||||
| 	private int nextMessageEncryption = -1; | ||||
| 	private String nextMessage; | ||||
| 
 | ||||
| 	private transient MucOptions mucOptions = null; | ||||
| 
 | ||||
| 	private transient String latestMarkableMessageId; | ||||
| 	//private transient String latestMarkableMessageId; | ||||
| 
 | ||||
| 	private byte[] symmetricKey; | ||||
| 
 | ||||
|  | @ -73,13 +80,13 @@ public class Conversation extends AbstractEntity { | |||
| 			int mode) { | ||||
| 		this(java.util.UUID.randomUUID().toString(), name, null, account | ||||
| 				.getUuid(), contactJid, System.currentTimeMillis(), | ||||
| 				STATUS_AVAILABLE, mode); | ||||
| 				STATUS_AVAILABLE, mode, ""); | ||||
| 		this.account = account; | ||||
| 	} | ||||
| 
 | ||||
| 	public Conversation(String uuid, String name, String contactUuid, | ||||
| 			String accountUuid, String contactJid, long created, int status, | ||||
| 			int mode) { | ||||
| 			int mode, String attributes) { | ||||
| 		this.uuid = uuid; | ||||
| 		this.name = name; | ||||
| 		this.contactUuid = contactUuid; | ||||
|  | @ -88,6 +95,14 @@ public class Conversation extends AbstractEntity { | |||
| 		this.created = created; | ||||
| 		this.status = status; | ||||
| 		this.mode = mode; | ||||
| 		try { | ||||
| 			if (attributes == null) { | ||||
| 				attributes = new String(); | ||||
| 			} | ||||
| 			this.attributes = new JSONObject(attributes); | ||||
| 		} catch (JSONException e) { | ||||
| 			this.attributes = new JSONObject(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public List<Message> getMessages() { | ||||
|  | @ -123,10 +138,20 @@ public class Conversation extends AbstractEntity { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public String popLatestMarkableMessageId() { | ||||
| 		String id = this.latestMarkableMessageId; | ||||
| 		this.latestMarkableMessageId = null; | ||||
| 		return id; | ||||
| 	public String getLatestMarkableMessageId() { | ||||
| 		if (this.messages == null) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		for(int i = this.messages.size() - 1; i >= 0; --i) { | ||||
| 			if (this.messages.get(i).getStatus() <= Message.STATUS_RECEIVED && this.messages.get(i).markable) { | ||||
| 				if (this.messages.get(i).isRead()) { | ||||
| 					return null; | ||||
| 				} else { | ||||
| 					return this.messages.get(i).getRemoteMsgId(); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return null; | ||||
| 	} | ||||
| 
 | ||||
| 	public Message getLatestMessage() { | ||||
|  | @ -198,6 +223,7 @@ public class Conversation extends AbstractEntity { | |||
| 		values.put(CREATED, created); | ||||
| 		values.put(STATUS, status); | ||||
| 		values.put(MODE, mode); | ||||
| 		values.put(ATTRIBUTES, attributes.toString()); | ||||
| 		return values; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -209,7 +235,8 @@ public class Conversation extends AbstractEntity { | |||
| 				cursor.getString(cursor.getColumnIndex(CONTACTJID)), | ||||
| 				cursor.getLong(cursor.getColumnIndex(CREATED)), | ||||
| 				cursor.getInt(cursor.getColumnIndex(STATUS)), | ||||
| 				cursor.getInt(cursor.getColumnIndex(MODE))); | ||||
| 				cursor.getInt(cursor.getColumnIndex(MODE)), | ||||
| 				cursor.getString(cursor.getColumnIndex(ATTRIBUTES))); | ||||
| 	} | ||||
| 
 | ||||
| 	public void setStatus(int status) { | ||||
|  | @ -229,8 +256,8 @@ public class Conversation extends AbstractEntity { | |||
| 		if (this.otrSession != null) { | ||||
| 			return this.otrSession; | ||||
| 		} else { | ||||
| 			SessionID sessionId = new SessionID( | ||||
| 					this.getContactJid().split("/",2)[0], presence, "xmpp"); | ||||
| 			SessionID sessionId = new SessionID(this.getContactJid().split("/", | ||||
| 					2)[0], presence, "xmpp"); | ||||
| 			this.otrSession = new SessionImpl(sessionId, getAccount() | ||||
| 					.getOtrEngine(service)); | ||||
| 			try { | ||||
|  | @ -345,7 +372,8 @@ public class Conversation extends AbstractEntity { | |||
| 	} | ||||
| 
 | ||||
| 	public int getNextEncryption(boolean force) { | ||||
| 		if (this.nextMessageEncryption == -1) { | ||||
| 		int next = this.getIntAttribute(ATTRIBUTE_NEXT_ENCRYPTION, -1); | ||||
| 		if (next == -1) { | ||||
| 			int latest = this.getLatestEncryption(); | ||||
| 			if (latest == Message.ENCRYPTION_NONE) { | ||||
| 				if (force && getMode() == MODE_SINGLE) { | ||||
|  | @ -363,16 +391,16 @@ public class Conversation extends AbstractEntity { | |||
| 				return latest; | ||||
| 			} | ||||
| 		} | ||||
| 		if (this.nextMessageEncryption == Message.ENCRYPTION_NONE && force | ||||
| 		if (next == Message.ENCRYPTION_NONE && force | ||||
| 				&& getMode() == MODE_SINGLE) { | ||||
| 			return Message.ENCRYPTION_OTR; | ||||
| 		} else { | ||||
| 			return this.nextMessageEncryption; | ||||
| 			return next; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void setNextEncryption(int encryption) { | ||||
| 		this.nextMessageEncryption = encryption; | ||||
| 		this.setAttribute(ATTRIBUTE_NEXT_ENCRYPTION, String.valueOf(encryption)); | ||||
| 	} | ||||
| 
 | ||||
| 	public String getNextMessage() { | ||||
|  | @ -387,12 +415,6 @@ public class Conversation extends AbstractEntity { | |||
| 		this.nextMessage = message; | ||||
| 	} | ||||
| 
 | ||||
| 	public void setLatestMarkableMessageId(String id) { | ||||
| 		if (id != null) { | ||||
| 			this.latestMarkableMessageId = id; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void setSymmetricKey(byte[] key) { | ||||
| 		this.symmetricKey = key; | ||||
| 	} | ||||
|  | @ -433,11 +455,55 @@ public class Conversation extends AbstractEntity { | |||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	public void setMutedTill(long mutedTill) { | ||||
| 		this.mutedTill = mutedTill; | ||||
| 	public void setMutedTill(long value) { | ||||
| 		this.setAttribute(ATTRIBUTE_MUTED_TILL, String.valueOf(value)); | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean isMuted() { | ||||
| 		return SystemClock.elapsedRealtime() < this.mutedTill; | ||||
| 		return SystemClock.elapsedRealtime() < this.getLongAttribute( | ||||
| 				ATTRIBUTE_MUTED_TILL, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean setAttribute(String key, String value) { | ||||
| 		try { | ||||
| 			this.attributes.put(key, value); | ||||
| 			return true; | ||||
| 		} catch (JSONException e) { | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public String getAttribute(String key) { | ||||
| 		try { | ||||
| 			return this.attributes.getString(key); | ||||
| 		} catch (JSONException e) { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public int getIntAttribute(String key, int defaultValue) { | ||||
| 		String value = this.getAttribute(key); | ||||
| 		if (value == null) { | ||||
| 			return defaultValue; | ||||
| 		} else { | ||||
| 			try { | ||||
| 				return Integer.parseInt(value); | ||||
| 			} catch (NumberFormatException e) { | ||||
| 				return defaultValue; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public long getLongAttribute(String key, long defaultValue) { | ||||
| 		String value = this.getAttribute(key); | ||||
| 		if (value == null) { | ||||
| 			return defaultValue; | ||||
| 		} else { | ||||
| 			try { | ||||
| 				return Long.parseLong(value); | ||||
| 			} catch (NumberFormatException e) { | ||||
| 				return defaultValue; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -57,9 +57,9 @@ public class Message extends AbstractEntity { | |||
| 	protected boolean read = true; | ||||
| 	protected String remoteMsgId = null; | ||||
| 
 | ||||
| 	protected transient Conversation conversation = null; | ||||
| 
 | ||||
| 	protected transient Downloadable downloadable = null; | ||||
| 	protected Conversation conversation = null; | ||||
| 	protected Downloadable downloadable = null; | ||||
| 	public boolean markable = false; | ||||
| 
 | ||||
| 	private Message() { | ||||
| 
 | ||||
|  |  | |||
|  | @ -15,6 +15,13 @@ public class MucOptions { | |||
| 	public static final int ERROR_NICK_IN_USE = 1; | ||||
| 	public static final int ERROR_ROOM_NOT_FOUND = 2; | ||||
| 	public static final int ERROR_PASSWORD_REQUIRED = 3; | ||||
| 	public static final int ERROR_BANNED = 4; | ||||
| 	public static final int ERROR_MEMBERS_ONLY = 5; | ||||
| 
 | ||||
| 	public static final int KICKED_FROM_ROOM = 9; | ||||
| 
 | ||||
| 	public static final String STATUS_CODE_BANNED = "301"; | ||||
| 	public static final String STATUS_CODE_KICKED = "307"; | ||||
| 
 | ||||
| 	public interface OnRenameListener { | ||||
| 		public void onRename(boolean success); | ||||
|  | @ -108,7 +115,6 @@ public class MucOptions { | |||
| 	private String subject = null; | ||||
| 	private String joinnick; | ||||
| 	private String password = null; | ||||
| 	private boolean passwordChanged = false; | ||||
| 
 | ||||
| 	public MucOptions(Account account) { | ||||
| 		this.account = account; | ||||
|  | @ -134,7 +140,7 @@ public class MucOptions { | |||
| 	} | ||||
| 
 | ||||
| 	public void processPacket(PresencePacket packet, PgpEngine pgp) { | ||||
| 		String[] fromParts = packet.getFrom().split("/",2); | ||||
| 		String[] fromParts = packet.getFrom().split("/", 2); | ||||
| 		if (fromParts.length >= 2) { | ||||
| 			String name = fromParts[1]; | ||||
| 			String type = packet.getAttribute("type"); | ||||
|  | @ -158,10 +164,6 @@ public class MucOptions { | |||
| 						} | ||||
| 						aboutToRename = false; | ||||
| 					} | ||||
| 					if (conversation.getBookmark() != null | ||||
| 							&& conversation.getBookmark().isProvidePassword()) { | ||||
| 						this.passwordChanged = false; | ||||
| 					} | ||||
| 				} else { | ||||
| 					addUser(user); | ||||
| 				} | ||||
|  | @ -179,11 +181,27 @@ public class MucOptions { | |||
| 								x.getContent())); | ||||
| 					} | ||||
| 				} | ||||
| 			} else if (type.equals("unavailable") && name.equals(this.joinnick)) { | ||||
| 				Element x = packet.findChild("x", | ||||
| 						"http://jabber.org/protocol/muc#user"); | ||||
| 				if (x != null) { | ||||
| 					Element status = x.findChild("status"); | ||||
| 					if (status != null) { | ||||
| 						String code = status.getAttribute("code"); | ||||
| 						if (STATUS_CODE_KICKED.equals(code)) { | ||||
| 							this.isOnline = false; | ||||
| 							this.error = KICKED_FROM_ROOM; | ||||
| 						} else if (STATUS_CODE_BANNED.equals(code)) { | ||||
| 							this.isOnline = false; | ||||
| 							this.error = ERROR_BANNED; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} else if (type.equals("unavailable")) { | ||||
| 				deleteUser(packet.getAttribute("from").split("/",2)[1]); | ||||
| 				deleteUser(packet.getAttribute("from").split("/", 2)[1]); | ||||
| 			} else if (type.equals("error")) { | ||||
| 				Element error = packet.findChild("error"); | ||||
| 				if (error.hasChild("conflict")) { | ||||
| 				if (error != null && error.hasChild("conflict")) { | ||||
| 					if (aboutToRename) { | ||||
| 						if (renameListener != null) { | ||||
| 							renameListener.onRename(false); | ||||
|  | @ -193,12 +211,13 @@ public class MucOptions { | |||
| 					} else { | ||||
| 						this.error = ERROR_NICK_IN_USE; | ||||
| 					} | ||||
| 				} else if (error.hasChild("not-authorized")) { | ||||
| 					if (conversation.getBookmark() != null | ||||
| 							&& conversation.getBookmark().isProvidePassword()) { | ||||
| 						this.passwordChanged = true; | ||||
| 					} | ||||
| 				} else if (error != null && error.hasChild("not-authorized")) { | ||||
| 					this.error = ERROR_PASSWORD_REQUIRED; | ||||
| 				} else if (error != null && error.hasChild("forbidden")) { | ||||
| 					this.error = ERROR_BANNED; | ||||
| 				} else if (error != null | ||||
| 						&& error.hasChild("registration-required")) { | ||||
| 					this.error = ERROR_MEMBERS_ONLY; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | @ -209,7 +228,7 @@ public class MucOptions { | |||
| 	} | ||||
| 
 | ||||
| 	public String getProposedNick() { | ||||
| 		String[] mucParts = conversation.getContactJid().split("/",2); | ||||
| 		String[] mucParts = conversation.getContactJid().split("/", 2); | ||||
| 		if (conversation.getBookmark() != null | ||||
| 				&& conversation.getBookmark().getNick() != null) { | ||||
| 			return conversation.getBookmark().getNick(); | ||||
|  | @ -309,7 +328,7 @@ public class MucOptions { | |||
| 	} | ||||
| 
 | ||||
| 	public String getJoinJid() { | ||||
| 		return this.conversation.getContactJid().split("/",2)[0] + "/" | ||||
| 		return this.conversation.getContactJid().split("/", 2)[0] + "/" | ||||
| 				+ this.joinnick; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -323,7 +342,9 @@ public class MucOptions { | |||
| 	} | ||||
| 
 | ||||
| 	public String getPassword() { | ||||
| 		if (conversation.getBookmark() != null | ||||
| 		this.password = conversation | ||||
| 				.getAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD); | ||||
| 		if (this.password == null && conversation.getBookmark() != null | ||||
| 				&& conversation.getBookmark().getPassword() != null) { | ||||
| 			return conversation.getBookmark().getPassword(); | ||||
| 		} else { | ||||
|  | @ -332,16 +353,12 @@ public class MucOptions { | |||
| 	} | ||||
| 
 | ||||
| 	public void setPassword(String password) { | ||||
| 		if (conversation.getBookmark() != null | ||||
| 				&& conversation.getBookmark().isProvidePassword()) { | ||||
| 		if (conversation.getBookmark() != null) { | ||||
| 			conversation.getBookmark().setPassword(password); | ||||
| 		} else { | ||||
| 			this.password = password; | ||||
| 		} | ||||
| 		conversation | ||||
| 				.setAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD, password); | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean isPasswordChanged() { | ||||
| 		return this.passwordChanged; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -14,13 +14,18 @@ public class Roster { | |||
| 		this.account = account; | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean hasContact(String jid) { | ||||
| 		String cleanJid = jid.split("/",2)[0]; | ||||
| 		return contacts.containsKey(cleanJid); | ||||
| 	public Contact getContactAsShownInRoster(String jid) { | ||||
| 		String cleanJid = jid.split("/", 2)[0]; | ||||
| 		Contact contact = contacts.get(cleanJid); | ||||
| 		if (contact != null && contact.showInRoster()) { | ||||
| 			return contact; | ||||
| 		} else { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public Contact getContact(String jid) { | ||||
| 		String cleanJid = jid.split("/",2)[0].toLowerCase(Locale.getDefault()); | ||||
| 		String cleanJid = jid.split("/", 2)[0].toLowerCase(Locale.getDefault()); | ||||
| 		if (contacts.containsKey(cleanJid)) { | ||||
| 			return contacts.get(cleanJid); | ||||
| 		} else { | ||||
|  |  | |||
|  | @ -21,9 +21,9 @@ public abstract class AbstractGenerator { | |||
| 			"urn:xmpp:avatar:metadata+notify" }; | ||||
| 	public final String IDENTITY_NAME = "Conversations 0.7"; | ||||
| 	public final String IDENTITY_TYPE = "phone"; | ||||
| 	 | ||||
| 
 | ||||
| 	protected XmppConnectionService mXmppConnectionService; | ||||
| 	 | ||||
| 
 | ||||
| 	protected AbstractGenerator(XmppConnectionService service) { | ||||
| 		this.mXmppConnectionService = service; | ||||
| 	} | ||||
|  |  | |||
|  | @ -34,7 +34,7 @@ public class MessageGenerator extends AbstractGenerator { | |||
| 			packet.setTo(message.getCounterpart()); | ||||
| 			packet.setType(MessagePacket.TYPE_CHAT); | ||||
| 		} else { | ||||
| 			packet.setTo(message.getCounterpart().split("/",2)[0]); | ||||
| 			packet.setTo(message.getCounterpart().split("/", 2)[0]); | ||||
| 			packet.setType(MessagePacket.TYPE_GROUPCHAT); | ||||
| 		} | ||||
| 		packet.setFrom(account.getFullJid()); | ||||
|  | @ -134,7 +134,7 @@ public class MessageGenerator extends AbstractGenerator { | |||
| 			String subject) { | ||||
| 		MessagePacket packet = new MessagePacket(); | ||||
| 		packet.setType(MessagePacket.TYPE_GROUPCHAT); | ||||
| 		packet.setTo(conversation.getContactJid().split("/",2)[0]); | ||||
| 		packet.setTo(conversation.getContactJid().split("/", 2)[0]); | ||||
| 		Element subjectChild = new Element("subject"); | ||||
| 		subjectChild.setContent(subject); | ||||
| 		packet.addChild(subjectChild); | ||||
|  | @ -148,13 +148,13 @@ public class MessageGenerator extends AbstractGenerator { | |||
| 		packet.setTo(contact); | ||||
| 		packet.setFrom(conversation.getAccount().getFullJid()); | ||||
| 		Element x = packet.addChild("x", "jabber:x:conference"); | ||||
| 		x.setAttribute("jid", conversation.getContactJid().split("/",2)[0]); | ||||
| 		x.setAttribute("jid", conversation.getContactJid().split("/", 2)[0]); | ||||
| 		return packet; | ||||
| 	} | ||||
| 
 | ||||
| 	public MessagePacket invite(Conversation conversation, String contact) { | ||||
| 		MessagePacket packet = new MessagePacket(); | ||||
| 		packet.setTo(conversation.getContactJid().split("/",2)[0]); | ||||
| 		packet.setTo(conversation.getContactJid().split("/", 2)[0]); | ||||
| 		packet.setFrom(conversation.getAccount().getFullJid()); | ||||
| 		Element x = new Element("x"); | ||||
| 		x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user"); | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ public abstract class AbstractParser { | |||
| 
 | ||||
| 	protected void updateLastseen(Element packet, Account account, | ||||
| 			boolean presenceOverwrite) { | ||||
| 		String[] fromParts = packet.getAttribute("from").split("/",2); | ||||
| 		String[] fromParts = packet.getAttribute("from").split("/", 2); | ||||
| 		String from = fromParts[0]; | ||||
| 		String presence = null; | ||||
| 		if (fromParts.length >= 2) { | ||||
|  |  | |||
|  | @ -73,6 +73,9 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { | |||
| 			IqPacket response = mXmppConnectionService.getIqGenerator() | ||||
| 					.discoResponse(packet); | ||||
| 			account.getXmppConnection().sendIqPacket(response, null); | ||||
| 		} else if (packet.hasChild("ping", "urn:xmpp:ping")) { | ||||
| 			IqPacket response = packet.generateRespone(IqPacket.TYPE_RESULT); | ||||
| 			mXmppConnectionService.sendIqPacket(account, response, null); | ||||
| 		} else { | ||||
| 			if ((packet.getType() == IqPacket.TYPE_GET) | ||||
| 					|| (packet.getType() == IqPacket.TYPE_SET)) { | ||||
|  |  | |||
|  | @ -1,13 +1,12 @@ | |||
| package eu.siacs.conversations.parser; | ||||
| 
 | ||||
| import android.os.SystemClock; | ||||
| import net.java.otr4j.session.Session; | ||||
| import net.java.otr4j.session.SessionStatus; | ||||
| import eu.siacs.conversations.Config; | ||||
| import eu.siacs.conversations.entities.Account; | ||||
| import eu.siacs.conversations.entities.Contact; | ||||
| import eu.siacs.conversations.entities.Conversation; | ||||
| import eu.siacs.conversations.entities.Message; | ||||
| import eu.siacs.conversations.services.NotificationService; | ||||
| import eu.siacs.conversations.services.XmppConnectionService; | ||||
| import eu.siacs.conversations.utils.CryptoHelper; | ||||
| import eu.siacs.conversations.xml.Element; | ||||
|  | @ -17,9 +16,6 @@ import eu.siacs.conversations.xmpp.stanzas.MessagePacket; | |||
| 
 | ||||
| public class MessageParser extends AbstractParser implements | ||||
| 		OnMessagePacketReceived { | ||||
| 
 | ||||
| 	private long lastCarbonMessageReceived = -(Config.CARBON_GRACE_PERIOD * 1000); | ||||
| 
 | ||||
| 	public MessageParser(XmppConnectionService service) { | ||||
| 		super(service); | ||||
| 	} | ||||
|  | @ -28,7 +24,6 @@ public class MessageParser extends AbstractParser implements | |||
| 		String[] fromParts = packet.getFrom().split("/", 2); | ||||
| 		Conversation conversation = mXmppConnectionService | ||||
| 				.findOrCreateConversation(account, fromParts[0], false); | ||||
| 		conversation.setLatestMarkableMessageId(getMarkableMessageId(packet)); | ||||
| 		updateLastseen(packet, account, true); | ||||
| 		String pgpBody = getPgpBody(packet); | ||||
| 		Message finishedMessage; | ||||
|  | @ -41,6 +36,7 @@ public class MessageParser extends AbstractParser implements | |||
| 					Message.STATUS_RECEIVED); | ||||
| 		} | ||||
| 		finishedMessage.setRemoteMsgId(packet.getId()); | ||||
| 		finishedMessage.markable = isMarkable(packet); | ||||
| 		if (conversation.getMode() == Conversation.MODE_MULTI | ||||
| 				&& fromParts.length >= 2) { | ||||
| 			finishedMessage.setType(Message.TYPE_PRIVATE); | ||||
|  | @ -71,7 +67,7 @@ public class MessageParser extends AbstractParser implements | |||
| 		updateLastseen(packet, account, true); | ||||
| 		String body = packet.getBody(); | ||||
| 		if (body.matches("^\\?OTRv\\d*\\?")) { | ||||
| 			conversation.resetOtrSession(); | ||||
| 			conversation.endOtrIfNeeded(); | ||||
| 		} | ||||
| 		if (!conversation.hasValidOtrSession()) { | ||||
| 			if (properlyAddressed) { | ||||
|  | @ -112,13 +108,12 @@ public class MessageParser extends AbstractParser implements | |||
| 				conversation.setSymmetricKey(CryptoHelper.hexToBytes(key)); | ||||
| 				return null; | ||||
| 			} | ||||
| 			conversation | ||||
| 					.setLatestMarkableMessageId(getMarkableMessageId(packet)); | ||||
| 			Message finishedMessage = new Message(conversation, | ||||
| 					packet.getFrom(), body, Message.ENCRYPTION_OTR, | ||||
| 					Message.STATUS_RECEIVED); | ||||
| 			finishedMessage.setTime(getTimestamp(packet)); | ||||
| 			finishedMessage.setRemoteMsgId(packet.getId()); | ||||
| 			finishedMessage.markable = isMarkable(packet); | ||||
| 			return finishedMessage; | ||||
| 		} catch (Exception e) { | ||||
| 			String receivedId = packet.getId(); | ||||
|  | @ -160,7 +155,6 @@ public class MessageParser extends AbstractParser implements | |||
| 			status = Message.STATUS_RECEIVED; | ||||
| 		} | ||||
| 		String pgpBody = getPgpBody(packet); | ||||
| 		conversation.setLatestMarkableMessageId(getMarkableMessageId(packet)); | ||||
| 		Message finishedMessage; | ||||
| 		if (pgpBody == null) { | ||||
| 			finishedMessage = new Message(conversation, counterPart, | ||||
|  | @ -170,6 +164,7 @@ public class MessageParser extends AbstractParser implements | |||
| 					Message.ENCRYPTION_PGP, status); | ||||
| 		} | ||||
| 		finishedMessage.setRemoteMsgId(packet.getId()); | ||||
| 		finishedMessage.markable = isMarkable(packet); | ||||
| 		if (status == Message.STATUS_RECEIVED) { | ||||
| 			finishedMessage.setTrueCounterpart(conversation.getMucOptions() | ||||
| 					.getTrueCounterpart(counterPart)); | ||||
|  | @ -201,10 +196,24 @@ public class MessageParser extends AbstractParser implements | |||
| 			return null; | ||||
| 		} | ||||
| 		Element message = forwarded.findChild("message"); | ||||
| 		if ((message == null) || (!message.hasChild("body"))) { | ||||
| 		if (message == null) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		if (!message.hasChild("body")) { | ||||
| 			if (status == Message.STATUS_RECEIVED | ||||
| 					&& message.getAttribute("from") != null) { | ||||
| 				parseNonMessage(message, account); | ||||
| 			} else if (status == Message.STATUS_SEND | ||||
| 					&& message.hasChild("displayed", "urn:xmpp:chat-markers:0")) { | ||||
| 				String to = message.getAttribute("to"); | ||||
| 				if (to != null) { | ||||
| 					Conversation conversation = mXmppConnectionService.find( | ||||
| 							mXmppConnectionService.getConversations(), account, | ||||
| 							to.split("/")[0]); | ||||
| 					if (conversation != null) { | ||||
| 						mXmppConnectionService.markRead(conversation, false); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			return null; | ||||
| 		} | ||||
|  | @ -224,8 +233,6 @@ public class MessageParser extends AbstractParser implements | |||
| 		String[] parts = fullJid.split("/", 2); | ||||
| 		Conversation conversation = mXmppConnectionService | ||||
| 				.findOrCreateConversation(account, parts[0], false); | ||||
| 		conversation.setLatestMarkableMessageId(getMarkableMessageId(packet)); | ||||
| 
 | ||||
| 		String pgpBody = getPgpBody(message); | ||||
| 		Message finishedMessage; | ||||
| 		if (pgpBody != null) { | ||||
|  | @ -238,6 +245,7 @@ public class MessageParser extends AbstractParser implements | |||
| 		} | ||||
| 		finishedMessage.setTime(getTimestamp(message)); | ||||
| 		finishedMessage.setRemoteMsgId(message.getAttribute("id")); | ||||
| 		finishedMessage.markable = isMarkable(message); | ||||
| 		if (conversation.getMode() == Conversation.MODE_MULTI | ||||
| 				&& parts.length >= 2) { | ||||
| 			finishedMessage.setType(Message.TYPE_PRIVATE); | ||||
|  | @ -298,6 +306,8 @@ public class MessageParser extends AbstractParser implements | |||
| 						Element password = x.findChild("password"); | ||||
| 						conversation.getMucOptions().setPassword( | ||||
| 								password.getContent()); | ||||
| 						mXmppConnectionService.databaseBackend | ||||
| 								.updateConversation(conversation); | ||||
| 					} | ||||
| 					mXmppConnectionService.joinMuc(conversation); | ||||
| 					mXmppConnectionService.updateConversationUi(); | ||||
|  | @ -313,6 +323,8 @@ public class MessageParser extends AbstractParser implements | |||
| 				if (!conversation.getMucOptions().online()) { | ||||
| 					if (password != null) { | ||||
| 						conversation.getMucOptions().setPassword(password); | ||||
| 						mXmppConnectionService.databaseBackend | ||||
| 								.updateConversation(conversation); | ||||
| 					} | ||||
| 					mXmppConnectionService.joinMuc(conversation); | ||||
| 					mXmppConnectionService.updateConversationUi(); | ||||
|  | @ -371,22 +383,18 @@ public class MessageParser extends AbstractParser implements | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private String getMarkableMessageId(Element message) { | ||||
| 		if (message.hasChild("markable", "urn:xmpp:chat-markers:0")) { | ||||
| 			return message.getAttribute("id"); | ||||
| 		} else { | ||||
| 			return null; | ||||
| 		} | ||||
| 	private boolean isMarkable(Element message) { | ||||
| 		return message.hasChild("markable", "urn:xmpp:chat-markers:0"); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onMessagePacketReceived(Account account, MessagePacket packet) { | ||||
| 		Message message = null; | ||||
| 		boolean notify = true; | ||||
| 		if (mXmppConnectionService.getPreferences().getBoolean( | ||||
| 				"notification_grace_period_after_carbon_received", true)) { | ||||
| 			notify = (SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > (Config.CARBON_GRACE_PERIOD * 1000); | ||||
| 		} | ||||
| 		boolean notify = mXmppConnectionService.getPreferences().getBoolean( | ||||
| 				"show_notification", true); | ||||
| 		boolean alwaysNotifyInConference = notify | ||||
| 				&& mXmppConnectionService.getPreferences().getBoolean( | ||||
| 						"always_notify_in_conference", false); | ||||
| 
 | ||||
| 		this.parseNick(packet, account); | ||||
| 
 | ||||
|  | @ -397,7 +405,9 @@ public class MessageParser extends AbstractParser implements | |||
| 				if (message != null) { | ||||
| 					message.markUnread(); | ||||
| 				} | ||||
| 			} else if (packet.hasChild("body")) { | ||||
| 			} else if (packet.hasChild("body") | ||||
| 					&& !(packet.hasChild("x", | ||||
| 							"http://jabber.org/protocol/muc#user"))) { | ||||
| 				message = this.parseChat(packet, account); | ||||
| 				if (message != null) { | ||||
| 					message.markUnread(); | ||||
|  | @ -407,10 +417,11 @@ public class MessageParser extends AbstractParser implements | |||
| 				message = this.parseCarbonMessage(packet, account); | ||||
| 				if (message != null) { | ||||
| 					if (message.getStatus() == Message.STATUS_SEND) { | ||||
| 						lastCarbonMessageReceived = SystemClock | ||||
| 								.elapsedRealtime(); | ||||
| 						mXmppConnectionService.getNotificationService() | ||||
| 								.activateGracePeriod(); | ||||
| 						notify = false; | ||||
| 						message.getConversation().markRead(); | ||||
| 						mXmppConnectionService.markRead( | ||||
| 								message.getConversation(), false); | ||||
| 					} else { | ||||
| 						message.markUnread(); | ||||
| 					} | ||||
|  | @ -423,9 +434,14 @@ public class MessageParser extends AbstractParser implements | |||
| 			if (message != null) { | ||||
| 				if (message.getStatus() == Message.STATUS_RECEIVED) { | ||||
| 					message.markUnread(); | ||||
| 					notify = alwaysNotifyInConference | ||||
| 							|| NotificationService | ||||
| 									.wasHighlightedOrPrivate(message); | ||||
| 				} else { | ||||
| 					message.getConversation().markRead(); | ||||
| 					lastCarbonMessageReceived = SystemClock.elapsedRealtime(); | ||||
| 					mXmppConnectionService.markRead(message.getConversation(), | ||||
| 							false); | ||||
| 					mXmppConnectionService.getNotificationService() | ||||
| 							.activateGracePeriod(); | ||||
| 					notify = false; | ||||
| 				} | ||||
| 			} | ||||
|  | @ -463,7 +479,10 @@ public class MessageParser extends AbstractParser implements | |||
| 			} | ||||
| 		} | ||||
| 		notify = notify && !conversation.isMuted(); | ||||
| 		mXmppConnectionService.notifyUi(conversation, notify); | ||||
| 		if (notify) { | ||||
| 			mXmppConnectionService.getNotificationService().push(message); | ||||
| 		} | ||||
| 		mXmppConnectionService.updateConversationUi(); | ||||
| 	} | ||||
| 
 | ||||
| 	private void parseHeadline(MessagePacket packet, Account account) { | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ public class PresenceParser extends AbstractParser implements | |||
| 		PgpEngine mPgpEngine = mXmppConnectionService.getPgpEngine(); | ||||
| 		if (packet.hasChild("x", "http://jabber.org/protocol/muc#user")) { | ||||
| 			Conversation muc = mXmppConnectionService.find(account, packet | ||||
| 					.getAttribute("from").split("/",2)[0]); | ||||
| 					.getAttribute("from").split("/", 2)[0]); | ||||
| 			if (muc != null) { | ||||
| 				boolean before = muc.getMucOptions().online(); | ||||
| 				muc.getMucOptions().processPacket(packet, mPgpEngine); | ||||
|  | @ -32,7 +32,7 @@ public class PresenceParser extends AbstractParser implements | |||
| 			} | ||||
| 		} else if (packet.hasChild("x", "http://jabber.org/protocol/muc")) { | ||||
| 			Conversation muc = mXmppConnectionService.find(account, packet | ||||
| 					.getAttribute("from").split("/",2)[0]); | ||||
| 					.getAttribute("from").split("/", 2)[0]); | ||||
| 			if (muc != null) { | ||||
| 				boolean before = muc.getMucOptions().online(); | ||||
| 				muc.getMucOptions().processPacket(packet, mPgpEngine); | ||||
|  | @ -58,6 +58,8 @@ public class PresenceParser extends AbstractParser implements | |||
| 							Presences.parseShow(packet.findChild("show"))); | ||||
| 				} else if (type.equals("unavailable")) { | ||||
| 					account.removePresence(fromParts[1]); | ||||
| 					mXmppConnectionService.getNotificationService() | ||||
| 							.deactivateGracePeriod(); | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { | |||
| 	private static DatabaseBackend instance = null; | ||||
| 
 | ||||
| 	private static final String DATABASE_NAME = "history"; | ||||
| 	private static final int DATABASE_VERSION = 7; | ||||
| 	private static final int DATABASE_VERSION = 8; | ||||
| 
 | ||||
| 	private static String CREATE_CONTATCS_STATEMENT = "create table " | ||||
| 			+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " | ||||
|  | @ -50,10 +50,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { | |||
| 				+ " TEXT, " + Conversation.CONTACT + " TEXT, " | ||||
| 				+ Conversation.ACCOUNT + " TEXT, " + Conversation.CONTACTJID | ||||
| 				+ " TEXT, " + Conversation.CREATED + " NUMBER, " | ||||
| 				+ Conversation.STATUS + " NUMBER," + Conversation.MODE | ||||
| 				+ " NUMBER," + "FOREIGN KEY(" + Conversation.ACCOUNT | ||||
| 				+ ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID | ||||
| 				+ ") ON DELETE CASCADE);"); | ||||
| 				+ Conversation.STATUS + " NUMBER, " + Conversation.MODE | ||||
| 				+ " NUMBER, " + Conversation.ATTRIBUTES + " TEXT, FOREIGN KEY(" | ||||
| 				+ Conversation.ACCOUNT + ") REFERENCES " + Account.TABLENAME | ||||
| 				+ "(" + Account.UUID + ") ON DELETE CASCADE);"); | ||||
| 		db.execSQL("create table " + Message.TABLENAME + "( " + Message.UUID | ||||
| 				+ " TEXT PRIMARY KEY, " + Message.CONVERSATION + " TEXT, " | ||||
| 				+ Message.TIME_SENT + " NUMBER, " + Message.COUNTERPART | ||||
|  | @ -96,6 +96,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { | |||
| 			db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " | ||||
| 					+ Account.AVATAR + " TEXT"); | ||||
| 		} | ||||
| 		if (oldVersion < 8 && newVersion >= 8) { | ||||
| 			db.execSQL("ALTER TABLE " + Conversation.TABLENAME + " ADD COLUMN " | ||||
| 					+ Conversation.ATTRIBUTES + " TEXT"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public static synchronized DatabaseBackend getInstance(Context context) { | ||||
|  | @ -206,6 +210,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { | |||
| 		while (cursor.moveToNext()) { | ||||
| 			list.add(Account.fromCursor(cursor)); | ||||
| 		} | ||||
| 		cursor.close(); | ||||
| 		return list; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -221,13 +226,15 @@ public class DatabaseBackend extends SQLiteOpenHelper { | |||
| 		String[] args = { account.getUuid() }; | ||||
| 		db.delete(Account.TABLENAME, Account.UUID + "=?", args); | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	public boolean hasEnabledAccounts() { | ||||
| 		SQLiteDatabase db = this.getReadableDatabase(); | ||||
| 		Cursor cursor= db.rawQuery("select count("+Account.UUID+")  from "+Account.TABLENAME+" where not options & (1 <<1)", null); | ||||
| 		Cursor cursor = db.rawQuery("select count(" + Account.UUID + ")  from " | ||||
| 				+ Account.TABLENAME + " where not options & (1 <<1)", null); | ||||
| 		cursor.moveToFirst(); | ||||
| 		int count = cursor.getInt(0); | ||||
| 		return (count>0); | ||||
| 		cursor.close(); | ||||
| 		return (count > 0); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
|  | @ -253,6 +260,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { | |||
| 		while (cursor.moveToNext()) { | ||||
| 			roster.initContact(Contact.fromCursor(cursor)); | ||||
| 		} | ||||
| 		cursor.close(); | ||||
| 	} | ||||
| 
 | ||||
| 	public void writeRoster(Roster roster) { | ||||
|  |  | |||
|  | @ -250,7 +250,10 @@ public class FileBackend { | |||
| 			if (!file.exists()) { | ||||
| 				file = getJingleFileLegacy(message); | ||||
| 			} | ||||
| 			Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath()); | ||||
| 			BitmapFactory.Options options = new BitmapFactory.Options(); | ||||
| 			options.inSampleSize = calcSampleSize(file, size); | ||||
| 			Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(), | ||||
| 					options); | ||||
| 			if (fullsize == null) { | ||||
| 				throw new FileNotFoundException(); | ||||
| 			} | ||||
|  | @ -414,6 +417,17 @@ public class FileBackend { | |||
| 		options.inJustDecodeBounds = true; | ||||
| 		BitmapFactory.decodeStream(context.getContentResolver() | ||||
| 				.openInputStream(image), null, options); | ||||
| 		return calcSampleSize(options, size); | ||||
| 	} | ||||
| 
 | ||||
| 	private int calcSampleSize(File image, int size) { | ||||
| 		BitmapFactory.Options options = new BitmapFactory.Options(); | ||||
| 		options.inJustDecodeBounds = true; | ||||
| 		BitmapFactory.decodeFile(image.getAbsolutePath(), options); | ||||
| 		return calcSampleSize(options, size); | ||||
| 	} | ||||
| 
 | ||||
| 	private int calcSampleSize(BitmapFactory.Options options, int size) { | ||||
| 		int height = options.outHeight; | ||||
| 		int width = options.outWidth; | ||||
| 		int inSampleSize = 1; | ||||
|  | @ -428,7 +442,6 @@ public class FileBackend { | |||
| 			} | ||||
| 		} | ||||
| 		return inSampleSize; | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	public Uri getJingleFileUri(Message message) { | ||||
|  |  | |||
|  | @ -15,7 +15,8 @@ public class EventReceiver extends BroadcastReceiver { | |||
| 		} else { | ||||
| 			mIntentForService.setAction("other"); | ||||
| 		} | ||||
| 		if (intent.getAction().equals("ui") || DatabaseBackend.getInstance(context).hasEnabledAccounts()) { | ||||
| 		if (intent.getAction().equals("ui") | ||||
| 				|| DatabaseBackend.getInstance(context).hasEnabledAccounts()) { | ||||
| 			context.startService(mIntentForService); | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ public class ImageProvider extends ContentProvider { | |||
| 			if (uuids == null) { | ||||
| 				throw new FileNotFoundException(); | ||||
| 			} | ||||
| 			String[] uuidsSplited = uuids.split("/",2); | ||||
| 			String[] uuidsSplited = uuids.split("/", 2); | ||||
| 			if (uuidsSplited.length != 3) { | ||||
| 				throw new FileNotFoundException(); | ||||
| 			} | ||||
|  |  | |||
|  | @ -0,0 +1,241 @@ | |||
| package eu.siacs.conversations.services; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| import android.app.Notification; | ||||
| import android.app.NotificationManager; | ||||
| import android.app.PendingIntent; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.SharedPreferences; | ||||
| import android.net.Uri; | ||||
| import android.os.PowerManager; | ||||
| import android.os.SystemClock; | ||||
| import android.support.v4.app.NotificationCompat; | ||||
| import android.support.v4.app.TaskStackBuilder; | ||||
| import android.text.Html; | ||||
| 
 | ||||
| import eu.siacs.conversations.Config; | ||||
| import eu.siacs.conversations.R; | ||||
| import eu.siacs.conversations.entities.Conversation; | ||||
| import eu.siacs.conversations.entities.Message; | ||||
| import eu.siacs.conversations.ui.ConversationActivity; | ||||
| 
 | ||||
| public class NotificationService { | ||||
| 
 | ||||
| 	private XmppConnectionService mXmppConnectionService; | ||||
| 	private NotificationManager mNotificationManager; | ||||
| 
 | ||||
| 	private LinkedHashMap<String, ArrayList<Message>> notifications = new LinkedHashMap<String, ArrayList<Message>>(); | ||||
| 
 | ||||
| 	public int NOTIFICATION_ID = 0x2342; | ||||
| 	private Conversation mOpenConversation; | ||||
| 	private boolean mIsInForeground; | ||||
| 
 | ||||
| 	private long mEndGracePeriod = 0L; | ||||
| 
 | ||||
| 	public NotificationService(XmppConnectionService service) { | ||||
| 		this.mXmppConnectionService = service; | ||||
| 		this.mNotificationManager = (NotificationManager) service | ||||
| 				.getSystemService(Context.NOTIFICATION_SERVICE); | ||||
| 	} | ||||
| 
 | ||||
| 	public synchronized void push(Message message) { | ||||
| 
 | ||||
| 		PowerManager pm = (PowerManager) mXmppConnectionService | ||||
| 				.getSystemService(Context.POWER_SERVICE); | ||||
| 		boolean isScreenOn = pm.isScreenOn(); | ||||
| 		if (this.mIsInForeground && isScreenOn | ||||
| 				&& this.mOpenConversation == message.getConversation()) { | ||||
| 			return; | ||||
| 		} | ||||
| 		String conversationUuid = message.getConversationUuid(); | ||||
| 		if (notifications.containsKey(conversationUuid)) { | ||||
| 			notifications.get(conversationUuid).add(message); | ||||
| 		} else { | ||||
| 			ArrayList<Message> mList = new ArrayList<Message>(); | ||||
| 			mList.add(message); | ||||
| 			notifications.put(conversationUuid, mList); | ||||
| 		} | ||||
| 		updateNotification((!(this.mIsInForeground && this.mOpenConversation == null) || !isScreenOn) | ||||
| 				&& !inGracePeriod()); | ||||
| 	} | ||||
| 
 | ||||
| 	public void clear() { | ||||
| 		notifications.clear(); | ||||
| 		updateNotification(false); | ||||
| 	} | ||||
| 
 | ||||
| 	public void clear(Conversation conversation) { | ||||
| 		notifications.remove(conversation.getUuid()); | ||||
| 		updateNotification(false); | ||||
| 	} | ||||
| 
 | ||||
| 	private void updateNotification(boolean notify) { | ||||
| 		SharedPreferences preferences = mXmppConnectionService.getPreferences(); | ||||
| 
 | ||||
| 		String ringtone = preferences.getString("notification_ringtone", null); | ||||
| 		boolean vibrate = preferences.getBoolean("vibrate_on_notification", | ||||
| 				true); | ||||
| 
 | ||||
| 		if (notifications.size() == 0) { | ||||
| 			mNotificationManager.cancel(NOTIFICATION_ID); | ||||
| 		} else { | ||||
| 			NotificationCompat.Builder mBuilder = new NotificationCompat.Builder( | ||||
| 					mXmppConnectionService); | ||||
| 			mBuilder.setSmallIcon(R.drawable.ic_notification); | ||||
| 			if (notifications.size() == 1) { | ||||
| 				ArrayList<Message> messages = notifications.values().iterator() | ||||
| 						.next(); | ||||
| 				if (messages.size() >= 1) { | ||||
| 					Conversation conversation = messages.get(0) | ||||
| 							.getConversation(); | ||||
| 					mBuilder.setLargeIcon(conversation.getImage( | ||||
| 							mXmppConnectionService, 64)); | ||||
| 					mBuilder.setContentTitle(conversation.getName()); | ||||
| 					StringBuilder text = new StringBuilder(); | ||||
| 					for (int i = 0; i < messages.size(); ++i) { | ||||
| 						text.append(messages.get(i).getReadableBody( | ||||
| 								mXmppConnectionService)); | ||||
| 						if (i != messages.size() - 1) { | ||||
| 							text.append("\n"); | ||||
| 						} | ||||
| 					} | ||||
| 					mBuilder.setStyle(new NotificationCompat.BigTextStyle() | ||||
| 							.bigText(text.toString())); | ||||
| 					mBuilder.setContentText(messages.get(0).getReadableBody( | ||||
| 							mXmppConnectionService)); | ||||
| 					if (notify) { | ||||
| 						mBuilder.setTicker(messages.get(messages.size() - 1) | ||||
| 								.getReadableBody(mXmppConnectionService)); | ||||
| 					} | ||||
| 					mBuilder.setContentIntent(createContentIntent(conversation | ||||
| 							.getUuid())); | ||||
| 				} else { | ||||
| 					mNotificationManager.cancel(NOTIFICATION_ID); | ||||
| 					return; | ||||
| 				} | ||||
| 			} else { | ||||
| 				NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle(); | ||||
| 				style.setBigContentTitle(notifications.size() | ||||
| 						+ " " | ||||
| 						+ mXmppConnectionService | ||||
| 								.getString(R.string.unread_conversations)); | ||||
| 				StringBuilder names = new StringBuilder(); | ||||
| 				Conversation conversation = null; | ||||
| 				for (ArrayList<Message> messages : notifications.values()) { | ||||
| 					if (messages.size() > 0) { | ||||
| 						conversation = messages.get(0).getConversation(); | ||||
| 						String name = conversation.getName(); | ||||
| 						style.addLine(Html.fromHtml("<b>" | ||||
| 								+ name | ||||
| 								+ "</b> " | ||||
| 								+ messages.get(0).getReadableBody( | ||||
| 										mXmppConnectionService))); | ||||
| 						names.append(name); | ||||
| 						names.append(", "); | ||||
| 					} | ||||
| 				} | ||||
| 				if (names.length() >= 2) { | ||||
| 					names.delete(names.length() - 2, names.length()); | ||||
| 				} | ||||
| 				mBuilder.setContentTitle(notifications.size() | ||||
| 						+ " " | ||||
| 						+ mXmppConnectionService | ||||
| 								.getString(R.string.unread_conversations)); | ||||
| 				mBuilder.setContentText(names.toString()); | ||||
| 				mBuilder.setStyle(style); | ||||
| 				if (conversation != null) { | ||||
| 					mBuilder.setContentIntent(createContentIntent(conversation | ||||
| 							.getUuid())); | ||||
| 				} | ||||
| 			} | ||||
| 			if (notify) { | ||||
| 				if (vibrate) { | ||||
| 					int dat = 70; | ||||
| 					long[] pattern = { 0, 3 * dat, dat, dat }; | ||||
| 					mBuilder.setVibrate(pattern); | ||||
| 				} | ||||
| 				if (ringtone != null) { | ||||
| 					mBuilder.setSound(Uri.parse(ringtone)); | ||||
| 				} | ||||
| 			} | ||||
| 			mBuilder.setDeleteIntent(createDeleteIntent()); | ||||
| 			if (!inGracePeriod()) { | ||||
| 				mBuilder.setLights(0xffffffff, 2000, 4000); | ||||
| 			} | ||||
| 			Notification notification = mBuilder.build(); | ||||
| 			mNotificationManager.notify(NOTIFICATION_ID, notification); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private PendingIntent createContentIntent(String conversationUuid) { | ||||
| 		TaskStackBuilder stackBuilder = TaskStackBuilder | ||||
| 				.create(mXmppConnectionService); | ||||
| 		stackBuilder.addParentStack(ConversationActivity.class); | ||||
| 
 | ||||
| 		Intent viewConversationIntent = new Intent(mXmppConnectionService, | ||||
| 				ConversationActivity.class); | ||||
| 		viewConversationIntent.setAction(Intent.ACTION_VIEW); | ||||
| 		viewConversationIntent.putExtra(ConversationActivity.CONVERSATION, | ||||
| 				conversationUuid); | ||||
| 		viewConversationIntent.setType(ConversationActivity.VIEW_CONVERSATION); | ||||
| 
 | ||||
| 		stackBuilder.addNextIntent(viewConversationIntent); | ||||
| 
 | ||||
| 		PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, | ||||
| 				PendingIntent.FLAG_UPDATE_CURRENT); | ||||
| 		return resultPendingIntent; | ||||
| 	} | ||||
| 
 | ||||
| 	private PendingIntent createDeleteIntent() { | ||||
| 		Intent intent = new Intent(mXmppConnectionService, | ||||
| 				XmppConnectionService.class); | ||||
| 		intent.setAction("clear_notification"); | ||||
| 		return PendingIntent.getService(mXmppConnectionService, 0, intent, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	public static boolean wasHighlightedOrPrivate(Message message) { | ||||
| 		String nick = message.getConversation().getMucOptions().getActualNick(); | ||||
| 		Pattern highlight = generateNickHighlightPattern(nick); | ||||
| 		if (message.getBody() == null || nick == null) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		Matcher m = highlight.matcher(message.getBody()); | ||||
| 		return (m.find() || message.getType() == Message.TYPE_PRIVATE); | ||||
| 	} | ||||
| 
 | ||||
| 	private static Pattern generateNickHighlightPattern(String nick) { | ||||
| 		// We expect a word boundary, i.e. space or start of string, followed by | ||||
| 		// the | ||||
| 		// nick (matched in case-insensitive manner), followed by optional | ||||
| 		// punctuation (for example "bob: i disagree" or "how are you alice?"), | ||||
| 		// followed by another word boundary. | ||||
| 		return Pattern.compile("\\b" + nick + "\\p{Punct}?\\b", | ||||
| 				Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); | ||||
| 	} | ||||
| 
 | ||||
| 	public void setOpenConversation(Conversation conversation) { | ||||
| 		this.mOpenConversation = conversation; | ||||
| 	} | ||||
| 
 | ||||
| 	public void setIsInForeground(boolean foreground) { | ||||
| 		this.mIsInForeground = foreground; | ||||
| 	} | ||||
| 
 | ||||
| 	public void activateGracePeriod() { | ||||
| 		this.mEndGracePeriod = SystemClock.elapsedRealtime() | ||||
| 				+ (Config.CARBON_GRACE_PERIOD * 1000); | ||||
| 	} | ||||
| 
 | ||||
| 	public void deactivateGracePeriod() { | ||||
| 		this.mEndGracePeriod = 0L; | ||||
| 	} | ||||
| 
 | ||||
| 	private boolean inGracePeriod() { | ||||
| 		return SystemClock.elapsedRealtime() < this.mEndGracePeriod; | ||||
| 	} | ||||
| } | ||||
|  | @ -90,9 +90,12 @@ public class XmppConnectionService extends Service { | |||
| 	public long startDate; | ||||
| 
 | ||||
| 	private static String ACTION_MERGE_PHONE_CONTACTS = "merge_phone_contacts"; | ||||
| 	public static String ACTION_CLEAR_NOTIFICATION = "clear_notification"; | ||||
| 
 | ||||
| 	private MemorizingTrustManager mMemorizingTrustManager; | ||||
| 
 | ||||
| 	private NotificationService mNotificationService; | ||||
| 
 | ||||
| 	private MessageParser mMessageParser = new MessageParser(this); | ||||
| 	private PresenceParser mPresenceParser = new PresenceParser(this); | ||||
| 	private IqParser mIqParser = new IqParser(this); | ||||
|  | @ -316,14 +319,16 @@ public class XmppConnectionService extends Service { | |||
| 
 | ||||
| 	@Override | ||||
| 	public int onStartCommand(Intent intent, int flags, int startId) { | ||||
| 		if ((intent != null) | ||||
| 				&& (ACTION_MERGE_PHONE_CONTACTS.equals(intent.getAction()))) { | ||||
| 			mergePhoneContactsWithRoster(); | ||||
| 			return START_STICKY; | ||||
| 		} else if ((intent != null) | ||||
| 				&& (Intent.ACTION_SHUTDOWN.equals(intent.getAction()))) { | ||||
| 			logoutAndSave(); | ||||
| 			return START_NOT_STICKY; | ||||
| 		if (intent != null && intent.getAction() != null) { | ||||
| 			if (intent.getAction().equals(ACTION_MERGE_PHONE_CONTACTS)) { | ||||
| 				mergePhoneContactsWithRoster(); | ||||
| 				return START_STICKY; | ||||
| 			} else if (intent.getAction().equals(Intent.ACTION_SHUTDOWN)) { | ||||
| 				logoutAndSave(); | ||||
| 				return START_NOT_STICKY; | ||||
| 			} else if (intent.getAction().equals(ACTION_CLEAR_NOTIFICATION)) { | ||||
| 				mNotificationService.clear(); | ||||
| 			} | ||||
| 		} | ||||
| 		this.wakeLock.acquire(); | ||||
| 		ConnectivityManager cm = (ConnectivityManager) getApplicationContext() | ||||
|  | @ -401,6 +406,7 @@ public class XmppConnectionService extends Service { | |||
| 		this.mRandom = new SecureRandom(); | ||||
| 		this.mMemorizingTrustManager = new MemorizingTrustManager( | ||||
| 				getApplicationContext()); | ||||
| 		this.mNotificationService = new NotificationService(this); | ||||
| 		this.databaseBackend = DatabaseBackend | ||||
| 				.getInstance(getApplicationContext()); | ||||
| 		this.fileBackend = new FileBackend(getApplicationContext()); | ||||
|  | @ -511,7 +517,8 @@ public class XmppConnectionService extends Service { | |||
| 		MessagePacket packet = null; | ||||
| 		boolean saveInDb = true; | ||||
| 		boolean send = false; | ||||
| 		if (account.getStatus() == Account.STATUS_ONLINE) { | ||||
| 		if (account.getStatus() == Account.STATUS_ONLINE | ||||
| 				&& account.getXmppConnection() != null) { | ||||
| 			if (message.getType() == Message.TYPE_IMAGE) { | ||||
| 				if (message.getPresence() != null) { | ||||
| 					if (message.getEncryption() == Message.ENCRYPTION_OTR) { | ||||
|  | @ -561,6 +568,10 @@ public class XmppConnectionService extends Service { | |||
| 					send = true; | ||||
| 				} | ||||
| 			} | ||||
| 			if (!account.getXmppConnection().getFeatures().sm() | ||||
| 					&& conv.getMode() != Conversation.MODE_MULTI) { | ||||
| 				message.setStatus(Message.STATUS_SEND); | ||||
| 			} | ||||
| 		} else { | ||||
| 			message.setStatus(Message.STATUS_WAITING); | ||||
| 			if (message.getType() == Message.TYPE_TEXT) { | ||||
|  | @ -586,10 +597,6 @@ public class XmppConnectionService extends Service { | |||
| 
 | ||||
| 		} | ||||
| 		conv.getMessages().add(message); | ||||
| 		if (!account.getXmppConnection().getFeatures().sm() | ||||
| 				&& conv.getMode() != Conversation.MODE_MULTI) { | ||||
| 			message.setStatus(Message.STATUS_SEND); | ||||
| 		} | ||||
| 		if (saveInDb) { | ||||
| 			if (message.getEncryption() == Message.ENCRYPTION_NONE | ||||
| 					|| saveEncryptedMessages()) { | ||||
|  | @ -742,7 +749,7 @@ public class XmppConnectionService extends Service { | |||
| 		Element query = iqPacket.query("jabber:iq:private"); | ||||
| 		Element storage = query.addChild("storage", "storage:bookmarks"); | ||||
| 		for (Bookmark bookmark : account.getBookmarks()) { | ||||
| 			storage.addChild(bookmark.toElement()); | ||||
| 			storage.addChild(bookmark); | ||||
| 		} | ||||
| 		sendIqPacket(account, iqPacket, null); | ||||
| 	} | ||||
|  | @ -824,7 +831,7 @@ public class XmppConnectionService extends Service { | |||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	public int loadMoreMessages(Conversation conversation, long timestamp) { | ||||
| 		List<Message> messages = databaseBackend.getMessages(conversation, 50, | ||||
| 				timestamp); | ||||
|  | @ -851,8 +858,9 @@ public class XmppConnectionService extends Service { | |||
| 	public Conversation find(List<Conversation> haystack, Account account, | ||||
| 			String jid) { | ||||
| 		for (Conversation conversation : haystack) { | ||||
| 			if ((conversation.getAccount().equals(account)) | ||||
| 					&& (conversation.getContactJid().split("/",2)[0].equals(jid))) { | ||||
| 			if ((account == null || conversation.getAccount().equals(account)) | ||||
| 					&& (conversation.getContactJid().split("/", 2)[0] | ||||
| 							.equals(jid))) { | ||||
| 				return conversation; | ||||
| 			} | ||||
| 		} | ||||
|  | @ -901,10 +909,12 @@ public class XmppConnectionService extends Service { | |||
| 
 | ||||
| 	public void archiveConversation(Conversation conversation) { | ||||
| 		if (conversation.getMode() == Conversation.MODE_MULTI) { | ||||
| 			Bookmark bookmark = conversation.getBookmark(); | ||||
| 			if (bookmark != null && bookmark.autojoin()) { | ||||
| 				bookmark.setAutojoin(false); | ||||
| 				pushBookmarks(bookmark.getAccount()); | ||||
| 			if (conversation.getAccount().getStatus() == Account.STATUS_ONLINE) { | ||||
| 				Bookmark bookmark = conversation.getBookmark(); | ||||
| 				if (bookmark != null && bookmark.autojoin()) { | ||||
| 					bookmark.setAutojoin(false); | ||||
| 					pushBookmarks(bookmark.getAccount()); | ||||
| 				} | ||||
| 			} | ||||
| 			leaveMuc(conversation); | ||||
| 		} else { | ||||
|  | @ -963,10 +973,12 @@ public class XmppConnectionService extends Service { | |||
| 
 | ||||
| 	public void setOnConversationListChangedListener( | ||||
| 			OnConversationUpdate listener) { | ||||
| 		this.mNotificationService.deactivateGracePeriod(); | ||||
| 		if (checkListeners()) { | ||||
| 			switchToForeground(); | ||||
| 		} | ||||
| 		this.mOnConversationUpdate = listener; | ||||
| 		this.mNotificationService.setIsInForeground(true); | ||||
| 		this.convChangedListenerCount++; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -974,6 +986,7 @@ public class XmppConnectionService extends Service { | |||
| 		this.convChangedListenerCount--; | ||||
| 		if (this.convChangedListenerCount == 0) { | ||||
| 			this.mOnConversationUpdate = null; | ||||
| 			this.mNotificationService.setIsInForeground(false); | ||||
| 			if (checkListeners()) { | ||||
| 				switchToBackground(); | ||||
| 			} | ||||
|  | @ -981,6 +994,7 @@ public class XmppConnectionService extends Service { | |||
| 	} | ||||
| 
 | ||||
| 	public void setOnAccountListChangedListener(OnAccountUpdate listener) { | ||||
| 		this.mNotificationService.deactivateGracePeriod(); | ||||
| 		if (checkListeners()) { | ||||
| 			switchToForeground(); | ||||
| 		} | ||||
|  | @ -999,6 +1013,7 @@ public class XmppConnectionService extends Service { | |||
| 	} | ||||
| 
 | ||||
| 	public void setOnRosterUpdateListener(OnRosterUpdate listener) { | ||||
| 		this.mNotificationService.deactivateGracePeriod(); | ||||
| 		if (checkListeners()) { | ||||
| 			switchToForeground(); | ||||
| 		} | ||||
|  | @ -1111,13 +1126,11 @@ public class XmppConnectionService extends Service { | |||
| 	public void providePasswordForMuc(Conversation conversation, String password) { | ||||
| 		if (conversation.getMode() == Conversation.MODE_MULTI) { | ||||
| 			conversation.getMucOptions().setPassword(password); | ||||
| 			if (conversation.getBookmark() != null | ||||
| 					&& conversation.getMucOptions().isPasswordChanged()) { | ||||
| 				if (!conversation.getBookmark().autojoin()) { | ||||
| 					conversation.getBookmark().setAutojoin(true); | ||||
| 				} | ||||
| 			if (conversation.getBookmark() != null) { | ||||
| 				conversation.getBookmark().setAutojoin(true); | ||||
| 				pushBookmarks(conversation.getAccount()); | ||||
| 			} | ||||
| 			databaseBackend.updateConversation(conversation); | ||||
| 			joinMuc(conversation); | ||||
| 		} | ||||
| 	} | ||||
|  | @ -1266,7 +1279,7 @@ public class XmppConnectionService extends Service { | |||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		notifyUi(conversation, false); | ||||
| 		updateConversationUi(); | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean renewSymmetricKey(Conversation conversation) { | ||||
|  | @ -1498,6 +1511,9 @@ public class XmppConnectionService extends Service { | |||
| 					thread.start(); | ||||
| 					scheduleWakeupCall((int) (Config.CONNECT_TIMEOUT * 1.2), | ||||
| 							false); | ||||
| 				} else { | ||||
| 					account.getRoster().clearPresences(); | ||||
| 					account.setXmppConnection(null); | ||||
| 				} | ||||
| 			} | ||||
| 		}).start(); | ||||
|  | @ -1523,24 +1539,34 @@ public class XmppConnectionService extends Service { | |||
| 
 | ||||
| 	public boolean markMessage(Account account, String recipient, String uuid, | ||||
| 			int status) { | ||||
| 		for (Conversation conversation : getConversations()) { | ||||
| 			if (conversation.getContactJid().equals(recipient) | ||||
| 					&& conversation.getAccount().equals(account)) { | ||||
| 				return markMessage(conversation, uuid, status); | ||||
| 		if (uuid == null) { | ||||
| 			return false; | ||||
| 		} else { | ||||
| 			for (Conversation conversation : getConversations()) { | ||||
| 				if (conversation.getContactJid().equals(recipient) | ||||
| 						&& conversation.getAccount().equals(account)) { | ||||
| 					return markMessage(conversation, uuid, status); | ||||
| 				} | ||||
| 			} | ||||
| 			return false; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean markMessage(Conversation conversation, String uuid, | ||||
| 			int status) { | ||||
| 		for (Message message : conversation.getMessages()) { | ||||
| 			if (message.getUuid().equals(uuid)) { | ||||
| 				markMessage(message, status); | ||||
| 				return true; | ||||
| 		if (uuid == null) { | ||||
| 			return false; | ||||
| 		} else { | ||||
| 			for (Message message : conversation.getMessages()) { | ||||
| 				if (uuid.equals(message.getUuid()) | ||||
| 						|| (message.getStatus() >= Message.STATUS_SEND && uuid | ||||
| 								.equals(message.getRemoteMsgId()))) { | ||||
| 					markMessage(message, status); | ||||
| 					return true; | ||||
| 				} | ||||
| 			} | ||||
| 			return false; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	public void markMessage(Message message, int status) { | ||||
|  | @ -1575,15 +1601,6 @@ public class XmppConnectionService extends Service { | |||
| 		return getPreferences().getBoolean("indicate_received", false); | ||||
| 	} | ||||
| 
 | ||||
| 	public void notifyUi(Conversation conversation, boolean notify) { | ||||
| 		if (mOnConversationUpdate != null) { | ||||
| 			mOnConversationUpdate.onConversationUpdate(); | ||||
| 		} else { | ||||
| 			UIHelper.updateNotification(getApplicationContext(), | ||||
| 					getConversations(), conversation, notify); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void updateConversationUi() { | ||||
| 		if (mOnConversationUpdate != null) { | ||||
| 			mOnConversationUpdate.onConversationUpdate(); | ||||
|  | @ -1620,15 +1637,21 @@ public class XmppConnectionService extends Service { | |||
| 		return null; | ||||
| 	} | ||||
| 
 | ||||
| 	public void markRead(Conversation conversation) { | ||||
| 	public void markRead(Conversation conversation, boolean calledByUi) { | ||||
| 		mNotificationService.clear(conversation); | ||||
| 		String id = conversation.getLatestMarkableMessageId(); | ||||
| 		conversation.markRead(); | ||||
| 		String id = conversation.popLatestMarkableMessageId(); | ||||
| 		if (confirmMessages() && id != null) { | ||||
| 		if (confirmMessages() && id != null && calledByUi) { | ||||
| 			Log.d(Config.LOGTAG, conversation.getAccount().getJid() | ||||
| 					+ ": sending read marker for " + conversation.getName()); | ||||
| 			Account account = conversation.getAccount(); | ||||
| 			String to = conversation.getContactJid(); | ||||
| 			this.sendMessagePacket(conversation.getAccount(), | ||||
| 					mMessageGenerator.confirm(account, to, id)); | ||||
| 		} | ||||
| 		if (!calledByUi) { | ||||
| 			updateConversationUi(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void failWaitingOtrMessages(Conversation conversation) { | ||||
|  | @ -1703,16 +1726,25 @@ public class XmppConnectionService extends Service { | |||
| 	} | ||||
| 
 | ||||
| 	public void sendMessagePacket(Account account, MessagePacket packet) { | ||||
| 		account.getXmppConnection().sendMessagePacket(packet); | ||||
| 		XmppConnection connection = account.getXmppConnection(); | ||||
| 		if (connection != null) { | ||||
| 			connection.sendMessagePacket(packet); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void sendPresencePacket(Account account, PresencePacket packet) { | ||||
| 		account.getXmppConnection().sendPresencePacket(packet); | ||||
| 		XmppConnection connection = account.getXmppConnection(); | ||||
| 		if (connection != null) { | ||||
| 			connection.sendPresencePacket(packet); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void sendIqPacket(Account account, IqPacket packet, | ||||
| 			OnIqPacketReceived callback) { | ||||
| 		account.getXmppConnection().sendIqPacket(packet, callback); | ||||
| 		XmppConnection connection = account.getXmppConnection(); | ||||
| 		if (connection != null) { | ||||
| 			connection.sendIqPacket(packet, callback); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public MessageGenerator getMessageGenerator() { | ||||
|  | @ -1742,4 +1774,22 @@ public class XmppConnectionService extends Service { | |||
| 	public interface OnRosterUpdate { | ||||
| 		public void onRosterUpdate(); | ||||
| 	} | ||||
| 
 | ||||
| 	public List<Contact> findContacts(String jid) { | ||||
| 		ArrayList<Contact> contacts = new ArrayList<Contact>(); | ||||
| 		for (Account account : getAccounts()) { | ||||
| 			if (!account.isOptionSet(Account.OPTION_DISABLED)) { | ||||
| 				Contact contact = account.getRoster() | ||||
| 						.getContactAsShownInRoster(jid); | ||||
| 				if (contact != null) { | ||||
| 					contacts.add(contact); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return contacts; | ||||
| 	} | ||||
| 
 | ||||
| 	public NotificationService getNotificationService() { | ||||
| 		return this.mNotificationService; | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -201,7 +201,7 @@ public class ConferenceDetailsActivity extends XmppActivity { | |||
| 	private void populateView() { | ||||
| 		mYourPhoto.setImageBitmap(conversation.getAccount().getImage(this, 48)); | ||||
| 		setTitle(conversation.getName()); | ||||
| 		mFullJid.setText(conversation.getContactJid().split("/",2)[0]); | ||||
| 		mFullJid.setText(conversation.getContactJid().split("/", 2)[0]); | ||||
| 		mYourNick.setText(conversation.getMucOptions().getActualNick()); | ||||
| 		mRoleAffiliaton = (TextView) findViewById(R.id.muc_role); | ||||
| 		if (conversation.getMucOptions().online()) { | ||||
|  |  | |||
|  | @ -39,8 +39,6 @@ import eu.siacs.conversations.utils.UIHelper; | |||
| public class ContactDetailsActivity extends XmppActivity { | ||||
| 	public static final String ACTION_VIEW_CONTACT = "view_contact"; | ||||
| 
 | ||||
| 	protected ContactDetailsActivity activity = this; | ||||
| 
 | ||||
| 	private Contact contact; | ||||
| 
 | ||||
| 	private String accountJid; | ||||
|  | @ -58,8 +56,8 @@ public class ContactDetailsActivity extends XmppActivity { | |||
| 
 | ||||
| 		@Override | ||||
| 		public void onClick(DialogInterface dialog, int which) { | ||||
| 			activity.xmppConnectionService.deleteContactOnServer(contact); | ||||
| 			activity.finish(); | ||||
| 			ContactDetailsActivity.this.xmppConnectionService.deleteContactOnServer(contact); | ||||
| 			ContactDetailsActivity.this.finish(); | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
|  | @ -73,14 +71,14 @@ public class ContactDetailsActivity extends XmppActivity { | |||
| 			intent.putExtra(Intents.Insert.IM_PROTOCOL, | ||||
| 					CommonDataKinds.Im.PROTOCOL_JABBER); | ||||
| 			intent.putExtra("finishActivityOnSaveCompleted", true); | ||||
| 			activity.startActivityForResult(intent, 0); | ||||
| 			ContactDetailsActivity.this.startActivityForResult(intent, 0); | ||||
| 		} | ||||
| 	}; | ||||
| 	private OnClickListener onBadgeClick = new OnClickListener() { | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void onClick(View v) { | ||||
| 			AlertDialog.Builder builder = new AlertDialog.Builder(activity); | ||||
| 			AlertDialog.Builder builder = new AlertDialog.Builder(ContactDetailsActivity.this); | ||||
| 			builder.setTitle(getString(R.string.action_add_phone_book)); | ||||
| 			builder.setMessage(getString(R.string.add_phone_book_text, | ||||
| 					contact.getJid())); | ||||
|  | @ -206,7 +204,7 @@ public class ContactDetailsActivity extends XmppActivity { | |||
| 					@Override | ||||
| 					public void onValueEdited(String value) { | ||||
| 						contact.setServerName(value); | ||||
| 						activity.xmppConnectionService | ||||
| 						ContactDetailsActivity.this.xmppConnectionService | ||||
| 								.pushContactToServer(contact); | ||||
| 						populateView(); | ||||
| 					} | ||||
|  | @ -354,7 +352,7 @@ public class ContactDetailsActivity extends XmppActivity { | |||
| 
 | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					PgpEngine pgp = activity.xmppConnectionService | ||||
| 					PgpEngine pgp = ContactDetailsActivity.this.xmppConnectionService | ||||
| 							.getPgpEngine(); | ||||
| 					if (pgp != null) { | ||||
| 						PendingIntent intent = pgp.getIntentForKey(contact); | ||||
|  |  | |||
|  | @ -12,11 +12,11 @@ import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdat | |||
| import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; | ||||
| import eu.siacs.conversations.ui.adapter.ConversationAdapter; | ||||
| import eu.siacs.conversations.utils.ExceptionHelper; | ||||
| import eu.siacs.conversations.utils.UIHelper; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.os.SystemClock; | ||||
| import android.provider.MediaStore; | ||||
| import android.annotation.SuppressLint; | ||||
| import android.app.ActionBar; | ||||
| import android.app.AlertDialog; | ||||
| import android.app.FragmentTransaction; | ||||
|  | @ -59,8 +59,13 @@ public class ConversationActivity extends XmppActivity implements | |||
| 	private static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301; | ||||
| 	private static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302; | ||||
| 	private static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0303; | ||||
| 	private static final String STATE_OPEN_CONVERSATION = "state_open_conversation"; | ||||
| 	private static final String STATE_PANEL_OPEN = "state_panel_open"; | ||||
| 
 | ||||
| 	protected SlidingPaneLayout spl; | ||||
| 	private String mOpenConverstaion = null; | ||||
| 	private boolean mPanelOpen = true; | ||||
| 
 | ||||
| 	private View mContentView; | ||||
| 
 | ||||
| 	private List<Conversation> conversationList = new ArrayList<Conversation>(); | ||||
| 	private Conversation selectedConversation = null; | ||||
|  | @ -69,7 +74,6 @@ public class ConversationActivity extends XmppActivity implements | |||
| 	private boolean paneShouldBeOpen = true; | ||||
| 	private ArrayAdapter<Conversation> listAdapter; | ||||
| 
 | ||||
| 	protected ConversationActivity activity = this; | ||||
| 	private Toast prepareImageToast; | ||||
| 
 | ||||
| 	private Uri pendingImageUri = null; | ||||
|  | @ -90,18 +94,52 @@ public class ConversationActivity extends XmppActivity implements | |||
| 		return this.listView; | ||||
| 	} | ||||
| 
 | ||||
| 	public SlidingPaneLayout getSlidingPaneLayout() { | ||||
| 		return this.spl; | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean shouldPaneBeOpen() { | ||||
| 		return paneShouldBeOpen; | ||||
| 	} | ||||
| 
 | ||||
| 	public void showConversationsOverview() { | ||||
| 		if (mContentView instanceof SlidingPaneLayout) { | ||||
| 			SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; | ||||
| 			mSlidingPaneLayout.openPane(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void hideConversationsOverview() { | ||||
| 		if (mContentView instanceof SlidingPaneLayout) { | ||||
| 			SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; | ||||
| 			mSlidingPaneLayout.closePane(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean isConversationsOverviewHideable() { | ||||
| 		if (mContentView instanceof SlidingPaneLayout) { | ||||
| 			SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; | ||||
| 			return mSlidingPaneLayout.isSlideable(); | ||||
| 		} else { | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean isConversationsOverviewVisable() { | ||||
| 		if (mContentView instanceof SlidingPaneLayout) { | ||||
| 			SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; | ||||
| 			return mSlidingPaneLayout.isOpen(); | ||||
| 		} else { | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	protected void onCreate(Bundle savedInstanceState) { | ||||
| 		super.onCreate(savedInstanceState); | ||||
| 
 | ||||
| 		if (savedInstanceState != null) { | ||||
| 			mOpenConverstaion = savedInstanceState.getString( | ||||
| 					STATE_OPEN_CONVERSATION, null); | ||||
| 			mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true); | ||||
| 		} | ||||
| 
 | ||||
| 		setContentView(R.layout.fragment_conversations_overview); | ||||
| 
 | ||||
| 		listView = (ListView) findViewById(R.id.list); | ||||
|  | @ -122,63 +160,80 @@ public class ConversationActivity extends XmppActivity implements | |||
| 					setSelectedConversation(conversationList.get(position)); | ||||
| 					swapConversationFragment(); | ||||
| 				} else { | ||||
| 					spl.closePane(); | ||||
| 					hideConversationsOverview(); | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
| 		spl = (SlidingPaneLayout) findViewById(R.id.slidingpanelayout); | ||||
| 		spl.setParallaxDistance(150); | ||||
| 		spl.setShadowResource(R.drawable.es_slidingpane_shadow); | ||||
| 		spl.setSliderFadeColor(0); | ||||
| 		spl.setPanelSlideListener(new PanelSlideListener() { | ||||
| 		mContentView = findViewById(R.id.content_view_spl); | ||||
| 		if (mContentView == null) { | ||||
| 			mContentView = findViewById(R.id.content_view_ll); | ||||
| 		} | ||||
| 		if (mContentView instanceof SlidingPaneLayout) { | ||||
| 			SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; | ||||
| 			mSlidingPaneLayout.setParallaxDistance(150); | ||||
| 			mSlidingPaneLayout | ||||
| 					.setShadowResource(R.drawable.es_slidingpane_shadow); | ||||
| 			mSlidingPaneLayout.setSliderFadeColor(0); | ||||
| 			mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() { | ||||
| 
 | ||||
| 			@Override | ||||
| 			public void onPanelOpened(View arg0) { | ||||
| 				paneShouldBeOpen = true; | ||||
| 				ActionBar ab = getActionBar(); | ||||
| 				if (ab != null) { | ||||
| 					ab.setDisplayHomeAsUpEnabled(false); | ||||
| 					ab.setHomeButtonEnabled(false); | ||||
| 					ab.setTitle(R.string.app_name); | ||||
| 				} | ||||
| 				invalidateOptionsMenu(); | ||||
| 				hideKeyboard(); | ||||
| 			} | ||||
| 
 | ||||
| 			@Override | ||||
| 			public void onPanelClosed(View arg0) { | ||||
| 				paneShouldBeOpen = false; | ||||
| 				if ((conversationList.size() > 0) | ||||
| 						&& (getSelectedConversation() != null)) { | ||||
| 				@Override | ||||
| 				public void onPanelOpened(View arg0) { | ||||
| 					paneShouldBeOpen = true; | ||||
| 					ActionBar ab = getActionBar(); | ||||
| 					if (ab != null) { | ||||
| 						ab.setDisplayHomeAsUpEnabled(true); | ||||
| 						ab.setHomeButtonEnabled(true); | ||||
| 						if (getSelectedConversation().getMode() == Conversation.MODE_SINGLE | ||||
| 								|| activity.useSubjectToIdentifyConference()) { | ||||
| 							ab.setTitle(getSelectedConversation().getName()); | ||||
| 						} else { | ||||
| 							ab.setTitle(getSelectedConversation() | ||||
| 									.getContactJid().split("/")[0]); | ||||
| 						} | ||||
| 						ab.setDisplayHomeAsUpEnabled(false); | ||||
| 						ab.setHomeButtonEnabled(false); | ||||
| 						ab.setTitle(R.string.app_name); | ||||
| 					} | ||||
| 					invalidateOptionsMenu(); | ||||
| 					if (!getSelectedConversation().isRead()) { | ||||
| 						xmppConnectionService | ||||
| 								.markRead(getSelectedConversation()); | ||||
| 						UIHelper.updateNotification(getApplicationContext(), | ||||
| 								getConversationList(), null, false); | ||||
| 						listView.invalidateViews(); | ||||
| 					hideKeyboard(); | ||||
| 					if (xmppConnectionServiceBound) { | ||||
| 						xmppConnectionService.getNotificationService() | ||||
| 								.setOpenConversation(null); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			@Override | ||||
| 			public void onPanelSlide(View arg0, float arg1) { | ||||
| 				// TODO Auto-generated method stub | ||||
| 				@Override | ||||
| 				public void onPanelClosed(View arg0) { | ||||
| 					paneShouldBeOpen = false; | ||||
| 					if ((conversationList.size() > 0) | ||||
| 							&& (getSelectedConversation() != null)) { | ||||
| 						openConversation(getSelectedConversation()); | ||||
| 						if (!getSelectedConversation().isRead()) { | ||||
| 							xmppConnectionService.markRead( | ||||
| 									getSelectedConversation(), true); | ||||
| 							listView.invalidateViews(); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				@Override | ||||
| 				public void onPanelSlide(View arg0, float arg1) { | ||||
| 					// TODO Auto-generated method stub | ||||
| 
 | ||||
| 				} | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public void openConversation(Conversation conversation) { | ||||
| 		ActionBar ab = getActionBar(); | ||||
| 		if (ab != null) { | ||||
| 			ab.setDisplayHomeAsUpEnabled(true); | ||||
| 			ab.setHomeButtonEnabled(true); | ||||
| 			if (getSelectedConversation().getMode() == Conversation.MODE_SINGLE | ||||
| 					|| ConversationActivity.this.useSubjectToIdentifyConference()) { | ||||
| 				ab.setTitle(getSelectedConversation().getName()); | ||||
| 			} else { | ||||
| 				ab.setTitle(getSelectedConversation().getContactJid() | ||||
| 						.split("/")[0]); | ||||
| 			} | ||||
| 		}); | ||||
| 		} | ||||
| 		invalidateOptionsMenu(); | ||||
| 		if (xmppConnectionServiceBound) { | ||||
| 			xmppConnectionService.getNotificationService().setOpenConversation( | ||||
| 					conversation); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
|  | @ -198,7 +253,8 @@ public class ConversationActivity extends XmppActivity implements | |||
| 				.findItem(R.id.action_invite); | ||||
| 		MenuItem menuMute = (MenuItem) menu.findItem(R.id.action_mute); | ||||
| 
 | ||||
| 		if ((spl.isOpen() && (spl.isSlideable()))) { | ||||
| 		if (isConversationsOverviewVisable() | ||||
| 				&& isConversationsOverviewHideable()) { | ||||
| 			menuArchive.setVisible(false); | ||||
| 			menuMucDetails.setVisible(false); | ||||
| 			menuContactDetails.setVisible(false); | ||||
|  | @ -208,7 +264,7 @@ public class ConversationActivity extends XmppActivity implements | |||
| 			menuClearHistory.setVisible(false); | ||||
| 			menuMute.setVisible(false); | ||||
| 		} else { | ||||
| 			menuAdd.setVisible(!spl.isSlideable()); | ||||
| 			menuAdd.setVisible(!isConversationsOverviewHideable()); | ||||
| 			if (this.getSelectedConversation() != null) { | ||||
| 				if (this.getSelectedConversation().getLatestMessage() | ||||
| 						.getEncryption() != Message.ENCRYPTION_NONE) { | ||||
|  | @ -296,6 +352,8 @@ public class ConversationActivity extends XmppActivity implements | |||
| 											int which) { | ||||
| 										conversation | ||||
| 												.setNextEncryption(Message.ENCRYPTION_NONE); | ||||
| 										xmppConnectionService.databaseBackend | ||||
| 												.updateConversation(conversation); | ||||
| 										selectPresenceToAttachFile(attachmentChoice); | ||||
| 									} | ||||
| 								}); | ||||
|  | @ -315,7 +373,7 @@ public class ConversationActivity extends XmppActivity implements | |||
| 	@Override | ||||
| 	public boolean onOptionsItemSelected(MenuItem item) { | ||||
| 		if (item.getItemId() == android.R.id.home) { | ||||
| 			spl.openPane(); | ||||
| 			showConversationsOverview(); | ||||
| 			return true; | ||||
| 		} else if (item.getItemId() == R.id.action_add) { | ||||
| 			startActivity(new Intent(this, StartConversationActivity.class)); | ||||
|  | @ -367,7 +425,7 @@ public class ConversationActivity extends XmppActivity implements | |||
| 	public void endConversation(Conversation conversation) { | ||||
| 		conversation.setStatus(Conversation.STATUS_ARCHIVED); | ||||
| 		paneShouldBeOpen = true; | ||||
| 		spl.openPane(); | ||||
| 		showConversationsOverview(); | ||||
| 		xmppConnectionService.archiveConversation(conversation); | ||||
| 		if (conversationList.size() > 0) { | ||||
| 			setSelectedConversation(conversationList.get(0)); | ||||
|  | @ -376,6 +434,7 @@ public class ConversationActivity extends XmppActivity implements | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@SuppressLint("InflateParams") | ||||
| 	protected void clearHistoryDialog(final Conversation conversation) { | ||||
| 		AlertDialog.Builder builder = new AlertDialog.Builder(this); | ||||
| 		builder.setTitle(getString(R.string.clear_conversation_history)); | ||||
|  | @ -390,7 +449,7 @@ public class ConversationActivity extends XmppActivity implements | |||
| 
 | ||||
| 					@Override | ||||
| 					public void onClick(DialogInterface dialog, int which) { | ||||
| 						activity.xmppConnectionService | ||||
| 						ConversationActivity.this.xmppConnectionService | ||||
| 								.clearConversationHistory(conversation); | ||||
| 						if (endConversationCheckBox.isChecked()) { | ||||
| 							endConversation(conversation); | ||||
|  | @ -399,7 +458,7 @@ public class ConversationActivity extends XmppActivity implements | |||
| 				}); | ||||
| 		builder.create().show(); | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	protected void attachFileDialog() { | ||||
| 		View menuAttachFile = findViewById(R.id.action_attach_file); | ||||
| 		if (menuAttachFile == null) { | ||||
|  | @ -470,6 +529,8 @@ public class ConversationActivity extends XmppActivity implements | |||
| 						conversation.setNextEncryption(Message.ENCRYPTION_NONE); | ||||
| 						break; | ||||
| 					} | ||||
| 					xmppConnectionService.databaseBackend | ||||
| 							.updateConversation(conversation); | ||||
| 					fragment.updateChatMsgHint(); | ||||
| 					return true; | ||||
| 				} | ||||
|  | @ -523,6 +584,8 @@ public class ConversationActivity extends XmppActivity implements | |||
| 									+ (durations[which] * 1000); | ||||
| 						} | ||||
| 						conversation.setMutedTill(till); | ||||
| 						ConversationActivity.this.xmppConnectionService.databaseBackend | ||||
| 								.updateConversation(conversation); | ||||
| 						ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager() | ||||
| 								.findFragmentByTag("conversation"); | ||||
| 						if (selectedFragment != null) { | ||||
|  | @ -550,8 +613,8 @@ public class ConversationActivity extends XmppActivity implements | |||
| 	@Override | ||||
| 	public boolean onKeyDown(int keyCode, KeyEvent event) { | ||||
| 		if (keyCode == KeyEvent.KEYCODE_BACK) { | ||||
| 			if (!spl.isOpen()) { | ||||
| 				spl.openPane(); | ||||
| 			if (!isConversationsOverviewVisable()) { | ||||
| 				showConversationsOverview(); | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
|  | @ -599,62 +662,75 @@ public class ConversationActivity extends XmppActivity implements | |||
| 			xmppConnectionService.removeOnConversationListChangedListener(); | ||||
| 			xmppConnectionService.removeOnAccountListChangedListener(); | ||||
| 			xmppConnectionService.removeOnRosterUpdateListener(); | ||||
| 			xmppConnectionService.getNotificationService().setOpenConversation( | ||||
| 					null); | ||||
| 		} | ||||
| 		super.onStop(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onSaveInstanceState(Bundle savedInstanceState) { | ||||
| 		Conversation conversation = getSelectedConversation(); | ||||
| 		if (conversation != null) { | ||||
| 			savedInstanceState.putString(STATE_OPEN_CONVERSATION, | ||||
| 					conversation.getUuid()); | ||||
| 		} | ||||
| 		savedInstanceState.putBoolean(STATE_PANEL_OPEN, | ||||
| 				isConversationsOverviewVisable()); | ||||
| 		super.onSaveInstanceState(savedInstanceState); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	void onBackendConnected() { | ||||
| 		this.registerListener(); | ||||
| 		if (conversationList.size() == 0) { | ||||
| 			updateConversationList(); | ||||
| 		updateConversationList(); | ||||
| 
 | ||||
| 		if (xmppConnectionService.getAccounts().size() == 0) { | ||||
| 			startActivity(new Intent(this, EditAccountActivity.class)); | ||||
| 		} else if (conversationList.size() <= 0) { | ||||
| 			startActivity(new Intent(this, StartConversationActivity.class)); | ||||
| 			finish(); | ||||
| 		} else if (mOpenConverstaion != null) { | ||||
| 			selectConversationByUuid(mOpenConverstaion); | ||||
| 			paneShouldBeOpen = mPanelOpen; | ||||
| 			if (paneShouldBeOpen) { | ||||
| 				showConversationsOverview(); | ||||
| 			} | ||||
| 			swapConversationFragment(); | ||||
| 			mOpenConverstaion = null; | ||||
| 		} else if (getIntent() != null | ||||
| 				&& VIEW_CONVERSATION.equals(getIntent().getType())) { | ||||
| 			String uuid = (String) getIntent().getExtras().get(CONVERSATION); | ||||
| 			String text = getIntent().getExtras().getString(TEXT, null); | ||||
| 			selectConversationByUuid(uuid); | ||||
| 			paneShouldBeOpen = false; | ||||
| 			swapConversationFragment().setText(text); | ||||
| 			setIntent(null); | ||||
| 		} else { | ||||
| 			showConversationsOverview(); | ||||
| 			ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager() | ||||
| 					.findFragmentByTag("conversation"); | ||||
| 			if (selectedFragment != null) { | ||||
| 				selectedFragment.onBackendConnected(); | ||||
| 			} else { | ||||
| 				pendingImageUri = null; | ||||
| 				setSelectedConversation(conversationList.get(0)); | ||||
| 				swapConversationFragment(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (getSelectedConversation() != null && pendingImageUri != null) { | ||||
| 		if (pendingImageUri != null) { | ||||
| 			attachImageToConversation(getSelectedConversation(), | ||||
| 					pendingImageUri); | ||||
| 			pendingImageUri = null; | ||||
| 		} else { | ||||
| 			pendingImageUri = null; | ||||
| 		} | ||||
| 		ExceptionHelper.checkForCrash(this, this.xmppConnectionService); | ||||
| 	} | ||||
| 
 | ||||
| 		if ((getIntent().getAction() != null) | ||||
| 				&& (getIntent().getAction().equals(Intent.ACTION_VIEW) && (!handledViewIntent))) { | ||||
| 			if (getIntent().getType().equals( | ||||
| 					ConversationActivity.VIEW_CONVERSATION)) { | ||||
| 				handledViewIntent = true; | ||||
| 
 | ||||
| 				String convToView = (String) getIntent().getExtras().get( | ||||
| 						CONVERSATION); | ||||
| 
 | ||||
| 				for (int i = 0; i < conversationList.size(); ++i) { | ||||
| 					if (conversationList.get(i).getUuid().equals(convToView)) { | ||||
| 						setSelectedConversation(conversationList.get(i)); | ||||
| 					} | ||||
| 				} | ||||
| 				paneShouldBeOpen = false; | ||||
| 				String text = getIntent().getExtras().getString(TEXT, null); | ||||
| 				swapConversationFragment().setText(text); | ||||
| 			} | ||||
| 		} else { | ||||
| 			if (xmppConnectionService.getAccounts().size() == 0) { | ||||
| 				startActivity(new Intent(this, EditAccountActivity.class)); | ||||
| 			} else if (conversationList.size() <= 0) { | ||||
| 				// add no history | ||||
| 				startActivity(new Intent(this, StartConversationActivity.class)); | ||||
| 				finish(); | ||||
| 			} else { | ||||
| 				spl.openPane(); | ||||
| 				// find currently loaded fragment | ||||
| 				ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager() | ||||
| 						.findFragmentByTag("conversation"); | ||||
| 				if (selectedFragment != null) { | ||||
| 					selectedFragment.onBackendConnected(); | ||||
| 				} else { | ||||
| 					setSelectedConversation(conversationList.get(0)); | ||||
| 					swapConversationFragment(); | ||||
| 				} | ||||
| 				ExceptionHelper.checkForCrash(this, this.xmppConnectionService); | ||||
| 	private void selectConversationByUuid(String uuid) { | ||||
| 		for (int i = 0; i < conversationList.size(); ++i) { | ||||
| 			if (conversationList.get(i).getUuid().equals(uuid)) { | ||||
| 				setSelectedConversation(conversationList.get(i)); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -778,7 +854,7 @@ public class ConversationActivity extends XmppActivity implements | |||
| 					@Override | ||||
| 					public void userInputRequried(PendingIntent pi, | ||||
| 							Message message) { | ||||
| 						activity.runIntent(pi, | ||||
| 						ConversationActivity.this.runIntent(pi, | ||||
| 								ConversationActivity.REQUEST_SEND_MESSAGE); | ||||
| 					} | ||||
| 
 | ||||
|  |  | |||
|  | @ -76,10 +76,11 @@ public class ConversationFragment extends Fragment { | |||
| 
 | ||||
| 		@Override | ||||
| 		public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { | ||||
| 			if (actionId == EditorInfo.IME_ACTION_DONE) { | ||||
| 			if (actionId == EditorInfo.IME_ACTION_SEND) { | ||||
| 				InputMethodManager imm = (InputMethodManager) v.getContext() | ||||
| 						.getSystemService(Context.INPUT_METHOD_SERVICE); | ||||
| 				imm.hideSoftInputFromWindow(v.getWindowToken(), 0); | ||||
| 				sendMessage(); | ||||
| 				return true; | ||||
| 			} else { | ||||
| 				return false; | ||||
|  | @ -131,6 +132,14 @@ public class ConversationFragment extends Fragment { | |||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	private OnClickListener joinMuc = new OnClickListener() { | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void onClick(View v) { | ||||
| 			activity.xmppConnectionService.joinMuc(conversation); | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	private OnClickListener enterPassword = new OnClickListener() { | ||||
| 
 | ||||
| 		@Override | ||||
|  | @ -169,6 +178,7 @@ public class ConversationFragment extends Fragment { | |||
| 						conversation, timestamp); | ||||
| 				messageList.clear(); | ||||
| 				messageList.addAll(conversation.getMessages()); | ||||
| 				updateStatusMessages(); | ||||
| 				messageListAdapter.notifyDataSetChanged(); | ||||
| 				if (size != 0) { | ||||
| 					messagesLoaded = true; | ||||
|  | @ -244,9 +254,7 @@ public class ConversationFragment extends Fragment { | |||
| 
 | ||||
| 			@Override | ||||
| 			public void onClick(View v) { | ||||
| 				if (activity.getSlidingPaneLayout().isSlideable()) { | ||||
| 					activity.getSlidingPaneLayout().closePane(); | ||||
| 				} | ||||
| 				activity.hideConversationsOverview(); | ||||
| 			} | ||||
| 		}); | ||||
| 		mEditMessage.setOnEditorActionListener(mEditorActionListener); | ||||
|  | @ -375,17 +383,10 @@ public class ConversationFragment extends Fragment { | |||
| 		int position = mEditMessage.length(); | ||||
| 		Editable etext = mEditMessage.getText(); | ||||
| 		Selection.setSelection(etext, position); | ||||
| 		if (activity.getSlidingPaneLayout().isSlideable()) { | ||||
| 		if (activity.isConversationsOverviewHideable()) { | ||||
| 			if (!activity.shouldPaneBeOpen()) { | ||||
| 				activity.getSlidingPaneLayout().closePane(); | ||||
| 				activity.getActionBar().setDisplayHomeAsUpEnabled(true); | ||||
| 				activity.getActionBar().setHomeButtonEnabled(true); | ||||
| 				if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) { | ||||
| 					activity.getActionBar().setTitle(conversation.getName()); | ||||
| 				} else { | ||||
| 					activity.getActionBar().setTitle(conversation.getContactJid().split("/")[0]); | ||||
| 				} | ||||
| 				activity.invalidateOptionsMenu(); | ||||
| 				activity.hideConversationsOverview(); | ||||
| 				activity.openConversation(conversation); | ||||
| 			} | ||||
| 		} | ||||
| 		if (this.conversation.getMode() == Conversation.MODE_MULTI) { | ||||
|  | @ -437,6 +438,8 @@ public class ConversationFragment extends Fragment { | |||
| 							@Override | ||||
| 							public void onClick(View v) { | ||||
| 								conversation.setMutedTill(0); | ||||
| 								activity.xmppConnectionService.databaseBackend | ||||
| 										.updateConversation(conversation); | ||||
| 								updateMessages(); | ||||
| 							} | ||||
| 						}); | ||||
|  | @ -492,6 +495,18 @@ public class ConversationFragment extends Fragment { | |||
| 						showSnackbar(R.string.conference_requires_password, | ||||
| 								R.string.enter_password, enterPassword); | ||||
| 						break; | ||||
| 					case MucOptions.ERROR_BANNED: | ||||
| 						showSnackbar(R.string.conference_banned, | ||||
| 								R.string.leave, leaveMuc); | ||||
| 						break; | ||||
| 					case MucOptions.ERROR_MEMBERS_ONLY: | ||||
| 						showSnackbar(R.string.conference_members_only, | ||||
| 								R.string.leave, leaveMuc); | ||||
| 						break; | ||||
| 					case MucOptions.KICKED_FROM_ROOM: | ||||
| 						showSnackbar(R.string.conference_kicked, R.string.join, | ||||
| 								joinMuc); | ||||
| 						break; | ||||
| 					default: | ||||
| 						break; | ||||
| 					} | ||||
|  | @ -500,9 +515,7 @@ public class ConversationFragment extends Fragment { | |||
| 			getActivity().invalidateOptionsMenu(); | ||||
| 			updateChatMsgHint(); | ||||
| 			if (!activity.shouldPaneBeOpen()) { | ||||
| 				activity.xmppConnectionService.markRead(conversation); | ||||
| 				UIHelper.updateNotification(getActivity(), | ||||
| 						activity.getConversationList(), null, false); | ||||
| 				activity.xmppConnectionService.markRead(conversation, true); | ||||
| 				activity.updateConversationList(); | ||||
| 			} | ||||
| 			this.updateSendButton(); | ||||
|  | @ -511,9 +524,7 @@ public class ConversationFragment extends Fragment { | |||
| 
 | ||||
| 	private void messageSent() { | ||||
| 		int size = this.messageList.size(); | ||||
| 		if (size >= 1 && this.messagesView.getLastVisiblePosition() != size - 1) { | ||||
| 			messagesView.setSelection(size - 1); | ||||
| 		} | ||||
| 		messagesView.setSelection(size - 1); | ||||
| 		mEditMessage.setText(""); | ||||
| 		updateChatMsgHint(); | ||||
| 	} | ||||
|  | @ -667,6 +678,8 @@ public class ConversationFragment extends Fragment { | |||
| 										int which) { | ||||
| 									conversation | ||||
| 											.setNextEncryption(Message.ENCRYPTION_NONE); | ||||
| 									xmppService.databaseBackend | ||||
| 											.updateConversation(conversation); | ||||
| 									message.setEncryption(Message.ENCRYPTION_NONE); | ||||
| 									xmppService.sendMessage(message); | ||||
| 									messageSent(); | ||||
|  | @ -695,6 +708,8 @@ public class ConversationFragment extends Fragment { | |||
| 									conversation | ||||
| 											.setNextEncryption(Message.ENCRYPTION_NONE); | ||||
| 									message.setEncryption(Message.ENCRYPTION_NONE); | ||||
| 									xmppService.databaseBackend | ||||
| 											.updateConversation(conversation); | ||||
| 									xmppService.sendMessage(message); | ||||
| 									messageSent(); | ||||
| 								} | ||||
|  |  | |||
|  | @ -1,8 +1,12 @@ | |||
| package eu.siacs.conversations.ui; | ||||
| 
 | ||||
| import android.app.PendingIntent; | ||||
| import android.content.ClipData; | ||||
| import android.content.ClipboardManager; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.text.Editable; | ||||
| import android.text.TextWatcher; | ||||
| import android.view.View; | ||||
| import android.view.View.OnClickListener; | ||||
| import android.widget.AutoCompleteTextView; | ||||
|  | @ -10,9 +14,11 @@ import android.widget.Button; | |||
| import android.widget.CheckBox; | ||||
| import android.widget.CompoundButton; | ||||
| import android.widget.EditText; | ||||
| import android.widget.ImageButton; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.CompoundButton.OnCheckedChangeListener; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| import eu.siacs.conversations.R; | ||||
| import eu.siacs.conversations.entities.Account; | ||||
| import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; | ||||
|  | @ -38,6 +44,7 @@ public class EditAccountActivity extends XmppActivity { | |||
| 	private TextView mSessionEst; | ||||
| 	private TextView mOtrFingerprint; | ||||
| 	private TextView mOtrFingerprintHeadline; | ||||
| 	private ImageButton mOtrFingerprintToClipboardButton; | ||||
| 
 | ||||
| 	private String jidToEdit; | ||||
| 	private Account mAccount; | ||||
|  | @ -48,6 +55,12 @@ public class EditAccountActivity extends XmppActivity { | |||
| 
 | ||||
| 		@Override | ||||
| 		public void onClick(View v) { | ||||
| 			if (mAccount != null | ||||
| 					&& mAccount.getStatus() == Account.STATUS_DISABLED) { | ||||
| 				mAccount.setOption(Account.OPTION_DISABLED, false); | ||||
| 				xmppConnectionService.updateAccount(mAccount); | ||||
| 				return; | ||||
| 			} | ||||
| 			if (!Validator.isValidJid(mAccountJid.getText().toString())) { | ||||
| 				mAccountJid.setError(getString(R.string.invalid_jid)); | ||||
| 				mAccountJid.requestFocus(); | ||||
|  | @ -157,6 +170,25 @@ public class EditAccountActivity extends XmppActivity { | |||
| 		} | ||||
| 	}; | ||||
| 	private KnownHostsAdapter mKnownHostsAdapter; | ||||
| 	private TextWatcher mTextWatcher = new TextWatcher() { | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void onTextChanged(CharSequence s, int start, int before, | ||||
| 				int count) { | ||||
| 			updateSaveButton(); | ||||
| 		} | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void beforeTextChanged(CharSequence s, int start, int count, | ||||
| 				int after) { | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void afterTextChanged(Editable s) { | ||||
| 
 | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	protected void finishInitialSetup(final Avatar avatar) { | ||||
| 		runOnUiThread(new Runnable() { | ||||
|  | @ -197,6 +229,11 @@ public class EditAccountActivity extends XmppActivity { | |||
| 			this.mSaveButton.setEnabled(false); | ||||
| 			this.mSaveButton.setTextColor(getSecondaryTextColor()); | ||||
| 			this.mSaveButton.setText(R.string.account_status_connecting); | ||||
| 		} else if (mAccount != null | ||||
| 				&& mAccount.getStatus() == Account.STATUS_DISABLED) { | ||||
| 			this.mSaveButton.setEnabled(true); | ||||
| 			this.mSaveButton.setTextColor(getPrimaryTextColor()); | ||||
| 			this.mSaveButton.setText(R.string.enable); | ||||
| 		} else { | ||||
| 			this.mSaveButton.setEnabled(true); | ||||
| 			this.mSaveButton.setTextColor(getPrimaryTextColor()); | ||||
|  | @ -204,6 +241,10 @@ public class EditAccountActivity extends XmppActivity { | |||
| 				if (mAccount != null | ||||
| 						&& mAccount.getStatus() == Account.STATUS_ONLINE) { | ||||
| 					this.mSaveButton.setText(R.string.save); | ||||
| 					if (!accountInfoEdited()) { | ||||
| 						this.mSaveButton.setEnabled(false); | ||||
| 						this.mSaveButton.setTextColor(getSecondaryTextColor()); | ||||
| 					} | ||||
| 				} else { | ||||
| 					this.mSaveButton.setText(R.string.connect); | ||||
| 				} | ||||
|  | @ -213,12 +254,21 @@ public class EditAccountActivity extends XmppActivity { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	protected boolean accountInfoEdited() { | ||||
| 		return (!this.mAccount.getJid().equals( | ||||
| 				this.mAccountJid.getText().toString())) | ||||
| 				|| (!this.mAccount.getPassword().equals( | ||||
| 						this.mPassword.getText().toString())); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	protected void onCreate(Bundle savedInstanceState) { | ||||
| 		super.onCreate(savedInstanceState); | ||||
| 		setContentView(R.layout.activity_edit_account); | ||||
| 		this.mAccountJid = (AutoCompleteTextView) findViewById(R.id.account_jid); | ||||
| 		this.mAccountJid.addTextChangedListener(this.mTextWatcher); | ||||
| 		this.mPassword = (EditText) findViewById(R.id.account_password); | ||||
| 		this.mPassword.addTextChangedListener(this.mTextWatcher); | ||||
| 		this.mPasswordConfirm = (EditText) findViewById(R.id.account_password_confirm); | ||||
| 		this.mRegisterNew = (CheckBox) findViewById(R.id.account_register_new); | ||||
| 		this.mStats = (LinearLayout) findViewById(R.id.stats); | ||||
|  | @ -228,6 +278,7 @@ public class EditAccountActivity extends XmppActivity { | |||
| 		this.mServerInfoPep = (TextView) findViewById(R.id.server_info_pep); | ||||
| 		this.mOtrFingerprint = (TextView) findViewById(R.id.otr_fingerprint); | ||||
| 		this.mOtrFingerprintHeadline = (TextView) findViewById(R.id.otr_fingerprint_headline); | ||||
| 		this.mOtrFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_to_clipboard); | ||||
| 		this.mSaveButton = (Button) findViewById(R.id.save_button); | ||||
| 		this.mCancelButton = (Button) findViewById(R.id.cancel_button); | ||||
| 		this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener); | ||||
|  | @ -255,7 +306,7 @@ public class EditAccountActivity extends XmppActivity { | |||
| 			this.jidToEdit = getIntent().getStringExtra("jid"); | ||||
| 			if (this.jidToEdit != null) { | ||||
| 				this.mRegisterNew.setVisibility(View.GONE); | ||||
| 				getActionBar().setTitle(R.string.mgmt_account_edit); | ||||
| 				getActionBar().setTitle(jidToEdit); | ||||
| 			} else { | ||||
| 				getActionBar().setTitle(R.string.action_add_account); | ||||
| 			} | ||||
|  | @ -324,13 +375,30 @@ public class EditAccountActivity extends XmppActivity { | |||
| 			} else { | ||||
| 				this.mServerInfoPep.setText(R.string.server_info_unavailable); | ||||
| 			} | ||||
| 			String fingerprint = this.mAccount | ||||
| 			final String fingerprint = this.mAccount | ||||
| 					.getOtrFingerprint(xmppConnectionService); | ||||
| 			if (fingerprint != null) { | ||||
| 				this.mOtrFingerprintHeadline.setVisibility(View.VISIBLE); | ||||
| 				this.mOtrFingerprint.setVisibility(View.VISIBLE); | ||||
| 				this.mOtrFingerprint.setText(fingerprint); | ||||
| 				this.mOtrFingerprintToClipboardButton | ||||
| 						.setVisibility(View.VISIBLE); | ||||
| 				this.mOtrFingerprintToClipboardButton | ||||
| 						.setOnClickListener(new View.OnClickListener() { | ||||
| 
 | ||||
| 							@Override | ||||
| 							public void onClick(View v) { | ||||
| 
 | ||||
| 								if (OtrFingerprintToClipBoard(fingerprint)) { | ||||
| 									Toast.makeText( | ||||
| 											EditAccountActivity.this, | ||||
| 											R.string.toast_message_otr_fingerprint, | ||||
| 											Toast.LENGTH_SHORT).show(); | ||||
| 								} | ||||
| 							} | ||||
| 						}); | ||||
| 			} else { | ||||
| 				this.mOtrFingerprintToClipboardButton.setVisibility(View.GONE); | ||||
| 				this.mOtrFingerprint.setVisibility(View.GONE); | ||||
| 				this.mOtrFingerprintHeadline.setVisibility(View.GONE); | ||||
| 			} | ||||
|  | @ -343,4 +411,15 @@ public class EditAccountActivity extends XmppActivity { | |||
| 			this.mStats.setVisibility(View.GONE); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private boolean OtrFingerprintToClipBoard(String fingerprint) { | ||||
| 		ClipboardManager mClipBoardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); | ||||
| 		String label = getResources().getString(R.string.otr_fingerprint); | ||||
| 		if (mClipBoardManager != null) { | ||||
| 			ClipData mClipData = ClipData.newPlainText(label, fingerprint); | ||||
| 			mClipBoardManager.setPrimaryClip(mClipData); | ||||
| 			return true; | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -24,8 +24,6 @@ import android.widget.ListView; | |||
| 
 | ||||
| public class ManageAccountActivity extends XmppActivity { | ||||
| 
 | ||||
| 	protected ManageAccountActivity activity = this; | ||||
| 
 | ||||
| 	protected Account selectedAccount = null; | ||||
| 
 | ||||
| 	protected List<Account> accountList = new ArrayList<Account>(); | ||||
|  | @ -72,7 +70,7 @@ public class ManageAccountActivity extends XmppActivity { | |||
| 	public void onCreateContextMenu(ContextMenu menu, View v, | ||||
| 			ContextMenuInfo menuInfo) { | ||||
| 		super.onCreateContextMenu(menu, v, menuInfo); | ||||
| 		activity.getMenuInflater().inflate(R.menu.manageaccounts_context, menu); | ||||
| 		ManageAccountActivity.this.getMenuInflater().inflate(R.menu.manageaccounts_context, menu); | ||||
| 		AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; | ||||
| 		this.selectedAccount = accountList.get(acmi.position); | ||||
| 		if (this.selectedAccount.isOptionSet(Account.OPTION_DISABLED)) { | ||||
|  | @ -181,7 +179,7 @@ public class ManageAccountActivity extends XmppActivity { | |||
| 	} | ||||
| 
 | ||||
| 	private void publishOpenPGPPublicKey(Account account) { | ||||
| 		if (activity.hasPgp()) { | ||||
| 		if (ManageAccountActivity.this.hasPgp()) { | ||||
| 			announcePgp(account, null); | ||||
| 		} else { | ||||
| 			this.showInstallPgpDialog(); | ||||
|  | @ -189,7 +187,7 @@ public class ManageAccountActivity extends XmppActivity { | |||
| 	} | ||||
| 
 | ||||
| 	private void deleteAccount(final Account account) { | ||||
| 		AlertDialog.Builder builder = new AlertDialog.Builder(activity); | ||||
| 		AlertDialog.Builder builder = new AlertDialog.Builder(ManageAccountActivity.this); | ||||
| 		builder.setTitle(getString(R.string.mgmt_account_are_you_sure)); | ||||
| 		builder.setIconAttribute(android.R.attr.alertDialogIcon); | ||||
| 		builder.setMessage(getString(R.string.mgmt_account_delete_confirm_text)); | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ public class SettingsActivity extends XmppActivity implements | |||
| 		super.onCreate(savedInstanceState); | ||||
| 		mSettingsFragment = new SettingsFragment(); | ||||
| 		getFragmentManager().beginTransaction() | ||||
| 				.replace(android.R.id.content,mSettingsFragment).commit(); | ||||
| 				.replace(android.R.id.content, mSettingsFragment).commit(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
|  | @ -34,12 +34,16 @@ public class SettingsActivity extends XmppActivity implements | |||
| 		super.onStart(); | ||||
| 		PreferenceManager.getDefaultSharedPreferences(this) | ||||
| 				.registerOnSharedPreferenceChangeListener(this); | ||||
| 		ListPreference resources = (ListPreference) mSettingsFragment.findPreference("resource"); | ||||
| 		if (resources!=null) { | ||||
| 			ArrayList<CharSequence> entries = new ArrayList<CharSequence>(Arrays.asList(resources.getEntries())); | ||||
| 			entries.add(0,Build.MODEL); | ||||
| 			resources.setEntries(entries.toArray(new CharSequence[entries.size()])); | ||||
| 			resources.setEntryValues(entries.toArray(new CharSequence[entries.size()])); | ||||
| 		ListPreference resources = (ListPreference) mSettingsFragment | ||||
| 				.findPreference("resource"); | ||||
| 		if (resources != null) { | ||||
| 			ArrayList<CharSequence> entries = new ArrayList<CharSequence>( | ||||
| 					Arrays.asList(resources.getEntries())); | ||||
| 			entries.add(0, Build.MODEL); | ||||
| 			resources.setEntries(entries.toArray(new CharSequence[entries | ||||
| 					.size()])); | ||||
| 			resources.setEntryValues(entries.toArray(new CharSequence[entries | ||||
| 					.size()])); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,9 +1,12 @@ | |||
| package eu.siacs.conversations.ui; | ||||
| 
 | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.net.URLDecoder; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import android.annotation.SuppressLint; | ||||
| import android.app.ActionBar; | ||||
| import android.app.ActionBar.Tab; | ||||
| import android.app.ActionBar.TabListener; | ||||
|  | @ -14,6 +17,8 @@ import android.app.ListFragment; | |||
| import android.content.Context; | ||||
| import android.content.DialogInterface; | ||||
| import android.content.DialogInterface.OnClickListener; | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.support.v13.app.FragmentPagerAdapter; | ||||
| import android.support.v4.view.ViewPager; | ||||
|  | @ -157,6 +162,8 @@ public class StartConversationActivity extends XmppActivity { | |||
| 			}); | ||||
| 		} | ||||
| 	}; | ||||
| 	private MenuItem mMenuSearchView; | ||||
| 	private String mInitialJid; | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onCreate(Bundle savedInstanceState) { | ||||
|  | @ -308,7 +315,8 @@ public class StartConversationActivity extends XmppActivity { | |||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	protected void showCreateContactDialog() { | ||||
| 	@SuppressLint("InflateParams") | ||||
| 	protected void showCreateContactDialog(String prefilledJid) { | ||||
| 		AlertDialog.Builder builder = new AlertDialog.Builder(this); | ||||
| 		builder.setTitle(R.string.create_contact); | ||||
| 		View dialogView = getLayoutInflater().inflate( | ||||
|  | @ -318,6 +326,9 @@ public class StartConversationActivity extends XmppActivity { | |||
| 				.findViewById(R.id.jid); | ||||
| 		jid.setAdapter(new KnownHostsAdapter(this, | ||||
| 				android.R.layout.simple_list_item_1, mKnownHosts)); | ||||
| 		if (prefilledJid != null) { | ||||
| 			jid.append(prefilledJid); | ||||
| 		} | ||||
| 		populateAccountSpinner(spinner); | ||||
| 		builder.setView(dialogView); | ||||
| 		builder.setNegativeButton(R.string.cancel, null); | ||||
|  | @ -348,8 +359,8 @@ public class StartConversationActivity extends XmppActivity { | |||
| 								jid.setError(getString(R.string.contact_already_exists)); | ||||
| 							} else { | ||||
| 								xmppConnectionService.createContact(contact); | ||||
| 								switchToConversation(contact); | ||||
| 								dialog.dismiss(); | ||||
| 								switchToConversation(contact); | ||||
| 							} | ||||
| 						} else { | ||||
| 							jid.setError(getString(R.string.invalid_jid)); | ||||
|  | @ -359,6 +370,7 @@ public class StartConversationActivity extends XmppActivity { | |||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@SuppressLint("InflateParams") | ||||
| 	protected void showJoinConferenceDialog() { | ||||
| 		AlertDialog.Builder builder = new AlertDialog.Builder(this); | ||||
| 		builder.setTitle(R.string.join_conference); | ||||
|  | @ -391,6 +403,10 @@ public class StartConversationActivity extends XmppActivity { | |||
| 							String conferenceJid = jid.getText().toString(); | ||||
| 							Account account = xmppConnectionService | ||||
| 									.findAccountByJid(accountJid); | ||||
| 							if (account == null) { | ||||
| 								dialog.dismiss(); | ||||
| 								return; | ||||
| 							} | ||||
| 							if (bookmarkCheckBox.isChecked()) { | ||||
| 								if (account.hasBookmarkFor(conferenceJid)) { | ||||
| 									jid.setError(getString(R.string.bookmark_already_exists)); | ||||
|  | @ -409,6 +425,7 @@ public class StartConversationActivity extends XmppActivity { | |||
| 										xmppConnectionService | ||||
| 												.joinMuc(conversation); | ||||
| 									} | ||||
| 									dialog.dismiss(); | ||||
| 									switchToConversation(conversation); | ||||
| 								} | ||||
| 							} else { | ||||
|  | @ -418,6 +435,7 @@ public class StartConversationActivity extends XmppActivity { | |||
| 								if (!conversation.getMucOptions().online()) { | ||||
| 									xmppConnectionService.joinMuc(conversation); | ||||
| 								} | ||||
| 								dialog.dismiss(); | ||||
| 								switchToConversation(conversation); | ||||
| 							} | ||||
| 						} else { | ||||
|  | @ -449,9 +467,9 @@ public class StartConversationActivity extends XmppActivity { | |||
| 				.findItem(R.id.action_create_contact); | ||||
| 		MenuItem menuCreateConference = (MenuItem) menu | ||||
| 				.findItem(R.id.action_join_conference); | ||||
| 		MenuItem menuSearchView = (MenuItem) menu.findItem(R.id.action_search); | ||||
| 		menuSearchView.setOnActionExpandListener(mOnActionExpandListener); | ||||
| 		View mSearchView = menuSearchView.getActionView(); | ||||
| 		mMenuSearchView = (MenuItem) menu.findItem(R.id.action_search); | ||||
| 		mMenuSearchView.setOnActionExpandListener(mOnActionExpandListener); | ||||
| 		View mSearchView = mMenuSearchView.getActionView(); | ||||
| 		mSearchEditText = (EditText) mSearchView | ||||
| 				.findViewById(R.id.search_field); | ||||
| 		mSearchEditText.addTextChangedListener(mSearchTextWatcher); | ||||
|  | @ -460,6 +478,11 @@ public class StartConversationActivity extends XmppActivity { | |||
| 		} else { | ||||
| 			menuCreateContact.setVisible(false); | ||||
| 		} | ||||
| 		if (mInitialJid != null) { | ||||
| 			mMenuSearchView.expandActionView(); | ||||
| 			mSearchEditText.append(mInitialJid); | ||||
| 			filter(mInitialJid); | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -467,7 +490,7 @@ public class StartConversationActivity extends XmppActivity { | |||
| 	public boolean onOptionsItemSelected(MenuItem item) { | ||||
| 		switch (item.getItemId()) { | ||||
| 		case R.id.action_create_contact: | ||||
| 			showCreateContactDialog(); | ||||
| 			showCreateContactDialog(null); | ||||
| 			break; | ||||
| 		case R.id.action_join_conference: | ||||
| 			showJoinConferenceDialog(); | ||||
|  | @ -486,13 +509,8 @@ public class StartConversationActivity extends XmppActivity { | |||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	void onBackendConnected() { | ||||
| 	protected void onBackendConnected() { | ||||
| 		xmppConnectionService.setOnRosterUpdateListener(this.onRosterUpdate); | ||||
| 		if (mSearchEditText != null) { | ||||
| 			filter(mSearchEditText.getText().toString()); | ||||
| 		} else { | ||||
| 			filter(null); | ||||
| 		} | ||||
| 		this.mActivatedAccounts.clear(); | ||||
| 		for (Account account : xmppConnectionService.getAccounts()) { | ||||
| 			if (account.getStatus() != Account.STATUS_DISABLED) { | ||||
|  | @ -502,6 +520,55 @@ public class StartConversationActivity extends XmppActivity { | |||
| 		this.mKnownHosts = xmppConnectionService.getKnownHosts(); | ||||
| 		this.mKnownConferenceHosts = xmppConnectionService | ||||
| 				.getKnownConferenceHosts(); | ||||
| 		if (!startByIntent()) { | ||||
| 			if (mSearchEditText != null) { | ||||
| 				filter(mSearchEditText.getText().toString()); | ||||
| 			} else { | ||||
| 				filter(null); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	protected boolean startByIntent() { | ||||
| 		if (getIntent() != null | ||||
| 				&& Intent.ACTION_SENDTO.equals(getIntent().getAction())) { | ||||
| 			try { | ||||
| 				String jid = URLDecoder.decode( | ||||
| 						getIntent().getData().getEncodedPath(), "UTF-8").split( | ||||
| 						"/")[1]; | ||||
| 				setIntent(null); | ||||
| 				return handleJid(jid); | ||||
| 			} catch (UnsupportedEncodingException e) { | ||||
| 				setIntent(null); | ||||
| 				return false; | ||||
| 			} | ||||
| 		} else if (getIntent() != null | ||||
| 				&& Intent.ACTION_VIEW.equals(getIntent().getAction())) { | ||||
| 			Uri uri = getIntent().getData(); | ||||
| 			String jid = uri.getSchemeSpecificPart().split("\\?")[0]; | ||||
| 			return handleJid(jid); | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	private boolean handleJid(String jid) { | ||||
| 		List<Contact> contacts = xmppConnectionService.findContacts(jid); | ||||
| 		if (contacts.size() == 0) { | ||||
| 			showCreateContactDialog(jid); | ||||
| 			return false; | ||||
| 		} else if (contacts.size() == 1) { | ||||
| 			switchToConversation(contacts.get(0)); | ||||
| 			return true; | ||||
| 		} else { | ||||
| 			if (mMenuSearchView != null) { | ||||
| 				mMenuSearchView.expandActionView(); | ||||
| 				mSearchEditText.setText(jid); | ||||
| 				filter(jid); | ||||
| 			} else { | ||||
| 				mInitialJid = jid; | ||||
| 			} | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	protected void filter(String needle) { | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ import eu.siacs.conversations.entities.Presences; | |||
| import eu.siacs.conversations.services.XmppConnectionService; | ||||
| import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder; | ||||
| import eu.siacs.conversations.utils.ExceptionHelper; | ||||
| import android.annotation.SuppressLint; | ||||
| import android.app.Activity; | ||||
| import android.app.AlertDialog; | ||||
| import android.app.PendingIntent; | ||||
|  | @ -58,11 +59,12 @@ public abstract class XmppActivity extends Activity { | |||
| 
 | ||||
| 	protected int mPrimaryTextColor; | ||||
| 	protected int mSecondaryTextColor; | ||||
| 	protected int mSecondaryBackgroundColor; | ||||
| 	protected int mColorRed; | ||||
| 	protected int mColorOrange; | ||||
| 	protected int mColorGreen; | ||||
| 	protected int mPrimaryColor; | ||||
| 	 | ||||
| 
 | ||||
| 	protected boolean mUseSubject = true; | ||||
| 
 | ||||
| 	private DisplayMetrics metrics; | ||||
|  | @ -206,6 +208,8 @@ public abstract class XmppActivity extends Activity { | |||
| 		mColorOrange = getResources().getColor(R.color.orange); | ||||
| 		mColorGreen = getResources().getColor(R.color.green); | ||||
| 		mPrimaryColor = getResources().getColor(R.color.primary); | ||||
| 		mSecondaryBackgroundColor = getResources().getColor( | ||||
| 				R.color.secondarybackground); | ||||
| 		if (getPreferences().getBoolean("use_larger_font", false)) { | ||||
| 			setTheme(R.style.ConversationsTheme_LargerText); | ||||
| 		} | ||||
|  | @ -216,7 +220,7 @@ public abstract class XmppActivity extends Activity { | |||
| 		return PreferenceManager | ||||
| 				.getDefaultSharedPreferences(getApplicationContext()); | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	public boolean useSubjectToIdentifyConference() { | ||||
| 		return mUseSubject; | ||||
| 	} | ||||
|  | @ -245,6 +249,7 @@ public abstract class XmppActivity extends Activity { | |||
| 					| Intent.FLAG_ACTIVITY_CLEAR_TOP); | ||||
| 		} | ||||
| 		startActivity(viewConversationIntent); | ||||
| 		finish(); | ||||
| 	} | ||||
| 
 | ||||
| 	public void switchToContactDetails(Contact contact) { | ||||
|  | @ -254,7 +259,7 @@ public abstract class XmppActivity extends Activity { | |||
| 		intent.putExtra("contact", contact.getJid()); | ||||
| 		startActivity(intent); | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	public void switchToAccount(Account account) { | ||||
| 		Intent intent = new Intent(this, EditAccountActivity.class); | ||||
| 		intent.putExtra("jid", account.getJid()); | ||||
|  | @ -292,6 +297,8 @@ public abstract class XmppActivity extends Activity { | |||
| 						if (conversation != null) { | ||||
| 							conversation | ||||
| 									.setNextEncryption(Message.ENCRYPTION_PGP); | ||||
| 							xmppConnectionService.databaseBackend | ||||
| 									.updateConversation(conversation); | ||||
| 						} | ||||
| 					} | ||||
| 
 | ||||
|  | @ -389,6 +396,7 @@ public abstract class XmppActivity extends Activity { | |||
| 		quickEdit(previousValue, callback, true); | ||||
| 	} | ||||
| 
 | ||||
| 	@SuppressLint("InflateParams") | ||||
| 	private void quickEdit(final String previousValue, | ||||
| 			final OnValueEdited callback, boolean password) { | ||||
| 		AlertDialog.Builder builder = new AlertDialog.Builder(this); | ||||
|  | @ -514,6 +522,10 @@ public abstract class XmppActivity extends Activity { | |||
| 		return this.mPrimaryColor; | ||||
| 	} | ||||
| 
 | ||||
| 	public int getSecondaryBackgroundColor() { | ||||
| 		return this.mSecondaryBackgroundColor; | ||||
| 	} | ||||
| 
 | ||||
| 	class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> { | ||||
| 		private final WeakReference<ImageView> imageViewReference; | ||||
| 		private Message message = null; | ||||
|  |  | |||
|  | @ -40,9 +40,10 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { | |||
| 		Conversation conv = getItem(position); | ||||
| 		if (this.activity instanceof ConversationActivity) { | ||||
| 			ConversationActivity activity = (ConversationActivity) this.activity; | ||||
| 			if (!activity.getSlidingPaneLayout().isSlideable()) { | ||||
| 			if (!activity.isConversationsOverviewHideable()) { | ||||
| 				if (conv == activity.getSelectedConversation()) { | ||||
| 					view.setBackgroundColor(0xffdddddd); | ||||
| 					view.setBackgroundColor(activity | ||||
| 							.getSecondaryBackgroundColor()); | ||||
| 				} else { | ||||
| 					view.setBackgroundColor(Color.TRANSPARENT); | ||||
| 				} | ||||
|  | @ -52,7 +53,8 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { | |||
| 		} | ||||
| 		TextView convName = (TextView) view | ||||
| 				.findViewById(R.id.conversation_name); | ||||
| 		if (conv.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) { | ||||
| 		if (conv.getMode() == Conversation.MODE_SINGLE | ||||
| 				|| activity.useSubjectToIdentifyConference()) { | ||||
| 			convName.setText(conv.getName()); | ||||
| 		} else { | ||||
| 			convName.setText(conv.getContactJid().split("/")[0]); | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> { | |||
| 				.getSystemService(Context.LAYOUT_INFLATER_SERVICE); | ||||
| 		ListItem item = getItem(position); | ||||
| 		if (view == null) { | ||||
| 			view = (View) inflater.inflate(R.layout.contact, null); | ||||
| 			view = (View) inflater.inflate(R.layout.contact, parent, false); | ||||
| 		} | ||||
| 		TextView name = (TextView) view.findViewById(R.id.contact_display_name); | ||||
| 		TextView jid = (TextView) view.findViewById(R.id.contact_jid); | ||||
|  | @ -36,4 +36,4 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> { | |||
| 		return view; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -417,7 +417,17 @@ public class MessageAdapter extends ArrayAdapter<Message> { | |||
| 			viewHolder = (ViewHolder) view.getTag(); | ||||
| 		} | ||||
| 
 | ||||
| 		if (type == STATUS || type == NULL) { | ||||
| 		if (type == STATUS) { | ||||
| 			return view; | ||||
| 		} | ||||
| 		if (type == NULL) { | ||||
| 			if (position == getCount() - 1) { | ||||
| 				view.getLayoutParams().height = 1; | ||||
| 			} else { | ||||
| 				view.getLayoutParams().height = 0; | ||||
| 
 | ||||
| 			} | ||||
| 			view.setLayoutParams(view.getLayoutParams()); | ||||
| 			return view; | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -30,17 +30,17 @@ public class DNSHelper { | |||
| 		String dns[] = client.findDNS(); | ||||
| 
 | ||||
| 		if (dns != null) { | ||||
| 			// we have a list of DNS servers, let's go | ||||
| 			for (String dnsserver : dns) { | ||||
| 				InetAddress ip = InetAddress.getByName(dnsserver); | ||||
| 				Bundle b = queryDNS(host, ip); | ||||
| 				if (b.containsKey("name")) { | ||||
| 					return b; | ||||
| 				} else if (b.containsKey("error") | ||||
| 						&& "nosrv".equals(b.getString("error", null))) { | ||||
| 					return b; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// fallback | ||||
| 		return queryDNS(host, InetAddress.getByName("8.8.8.8")); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -164,10 +164,8 @@ public class DNSHelper { | |||
| 			} | ||||
| 
 | ||||
| 		} catch (SocketTimeoutException e) { | ||||
| 			Log.d(Config.LOGTAG, "timeout during dns"); | ||||
| 			namePort.putString("error", "timeout"); | ||||
| 		} catch (Exception e) { | ||||
| 			Log.d(Config.LOGTAG, "unhandled exception in sub project"); | ||||
| 			namePort.putString("error", "unhandled"); | ||||
| 		} | ||||
| 		return namePort; | ||||
|  |  | |||
|  | @ -7,16 +7,15 @@ import java.util.Date; | |||
| import java.util.List; | ||||
| import java.util.Locale; | ||||
| import java.util.regex.Pattern; | ||||
| import java.util.regex.Matcher; | ||||
| 
 | ||||
| import eu.siacs.conversations.R; | ||||
| import eu.siacs.conversations.entities.Account; | ||||
| import eu.siacs.conversations.entities.Contact; | ||||
| import eu.siacs.conversations.entities.Conversation; | ||||
| import eu.siacs.conversations.entities.Message; | ||||
| import eu.siacs.conversations.entities.MucOptions.User; | ||||
| import eu.siacs.conversations.ui.ConversationActivity; | ||||
| import eu.siacs.conversations.ui.ManageAccountActivity; | ||||
| import android.annotation.SuppressLint; | ||||
| import android.app.Activity; | ||||
| import android.app.AlertDialog; | ||||
| import android.app.Notification; | ||||
|  | @ -26,7 +25,6 @@ import android.content.Context; | |||
| import android.content.DialogInterface; | ||||
| import android.content.DialogInterface.OnClickListener; | ||||
| import android.content.Intent; | ||||
| import android.content.SharedPreferences; | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.BitmapFactory; | ||||
| import android.graphics.Canvas; | ||||
|  | @ -34,13 +32,11 @@ import android.graphics.Paint; | |||
| import android.graphics.Rect; | ||||
| import android.graphics.Typeface; | ||||
| import android.net.Uri; | ||||
| import android.preference.PreferenceManager; | ||||
| import android.provider.ContactsContract.Contacts; | ||||
| import android.support.v4.app.NotificationCompat; | ||||
| import android.support.v4.app.TaskStackBuilder; | ||||
| import android.text.format.DateFormat; | ||||
| import android.text.format.DateUtils; | ||||
| import android.text.Html; | ||||
| import android.util.DisplayMetrics; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
|  | @ -330,177 +326,6 @@ public class UIHelper { | |||
| 		mNotificationManager.notify(1111, notification); | ||||
| 	} | ||||
| 
 | ||||
| 	private static Pattern generateNickHighlightPattern(String nick) { | ||||
| 		// We expect a word boundary, i.e. space or start of string, followed by | ||||
| 		// the | ||||
| 		// nick (matched in case-insensitive manner), followed by optional | ||||
| 		// punctuation (for example "bob: i disagree" or "how are you alice?"), | ||||
| 		// followed by another word boundary. | ||||
| 		return Pattern.compile("\\b" + nick + "\\p{Punct}?\\b", | ||||
| 				Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); | ||||
| 	} | ||||
| 
 | ||||
| 	public static void updateNotification(Context context, | ||||
| 			List<Conversation> conversations, Conversation currentCon, | ||||
| 			boolean notify) { | ||||
| 		NotificationManager mNotificationManager = (NotificationManager) context | ||||
| 				.getSystemService(Context.NOTIFICATION_SERVICE); | ||||
| 
 | ||||
| 		SharedPreferences preferences = PreferenceManager | ||||
| 				.getDefaultSharedPreferences(context); | ||||
| 		boolean showNofifications = preferences.getBoolean("show_notification", | ||||
| 				true); | ||||
| 		boolean vibrate = preferences.getBoolean("vibrate_on_notification", | ||||
| 				true); | ||||
| 		boolean alwaysNotify = preferences.getBoolean( | ||||
| 				"notify_in_conversation_when_highlighted", false); | ||||
| 
 | ||||
| 		if (!showNofifications) { | ||||
| 			mNotificationManager.cancel(2342); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		String targetUuid = ""; | ||||
| 
 | ||||
| 		if ((currentCon != null) | ||||
| 				&& (currentCon.getMode() == Conversation.MODE_MULTI) | ||||
| 				&& (!alwaysNotify) && notify) { | ||||
| 			String nick = currentCon.getMucOptions().getActualNick(); | ||||
| 			Pattern highlight = generateNickHighlightPattern(nick); | ||||
| 			Matcher m = highlight.matcher(currentCon.getLatestMessage() | ||||
| 					.getBody()); | ||||
| 			notify = m.find() | ||||
| 					|| (currentCon.getLatestMessage().getType() == Message.TYPE_PRIVATE); | ||||
| 		} | ||||
| 
 | ||||
| 		List<Conversation> unread = new ArrayList<Conversation>(); | ||||
| 		for (Conversation conversation : conversations) { | ||||
| 			if (conversation.getMode() == Conversation.MODE_MULTI) { | ||||
| 				if ((!conversation.isRead()) | ||||
| 						&& ((wasHighlightedOrPrivate(conversation) || (alwaysNotify)))) { | ||||
| 					unread.add(conversation); | ||||
| 				} | ||||
| 			} else { | ||||
| 				if (!conversation.isRead()) { | ||||
| 					unread.add(conversation); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		String ringtone = preferences.getString("notification_ringtone", null); | ||||
| 
 | ||||
| 		NotificationCompat.Builder mBuilder = new NotificationCompat.Builder( | ||||
| 				context); | ||||
| 		if (unread.size() == 0) { | ||||
| 			mNotificationManager.cancel(2342); | ||||
| 			return; | ||||
| 		} else if (unread.size() == 1) { | ||||
| 			Conversation conversation = unread.get(0); | ||||
| 			targetUuid = conversation.getUuid(); | ||||
| 			mBuilder.setLargeIcon(conversation.getImage(context, 64)); | ||||
| 			mBuilder.setContentTitle(conversation.getName()); | ||||
| 			if (notify) { | ||||
| 				mBuilder.setTicker(conversation.getLatestMessage() | ||||
| 						.getReadableBody(context)); | ||||
| 			} | ||||
| 			StringBuilder bigText = new StringBuilder(); | ||||
| 			List<Message> messages = conversation.getMessages(); | ||||
| 			String firstLine = ""; | ||||
| 			for (int i = messages.size() - 1; i >= 0; --i) { | ||||
| 				if (!messages.get(i).isRead()) { | ||||
| 					if (i == messages.size() - 1) { | ||||
| 						firstLine = messages.get(i).getReadableBody(context); | ||||
| 						bigText.append(firstLine); | ||||
| 					} else { | ||||
| 						firstLine = messages.get(i).getReadableBody(context); | ||||
| 						bigText.insert(0, firstLine + "\n"); | ||||
| 					} | ||||
| 				} else { | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			mBuilder.setContentText(firstLine); | ||||
| 			mBuilder.setStyle(new NotificationCompat.BigTextStyle() | ||||
| 					.bigText(bigText.toString())); | ||||
| 		} else { | ||||
| 			NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle(); | ||||
| 			style.setBigContentTitle(unread.size() + " " | ||||
| 					+ context.getString(R.string.unread_conversations)); | ||||
| 			StringBuilder names = new StringBuilder(); | ||||
| 			for (int i = 0; i < unread.size(); ++i) { | ||||
| 				targetUuid = unread.get(i).getUuid(); | ||||
| 				if (i < unread.size() - 1) { | ||||
| 					names.append(unread.get(i).getName() + ", "); | ||||
| 				} else { | ||||
| 					names.append(unread.get(i).getName()); | ||||
| 				} | ||||
| 				style.addLine(Html.fromHtml("<b>" | ||||
| 						+ unread.get(i).getName() | ||||
| 						+ "</b> " | ||||
| 						+ unread.get(i).getLatestMessage() | ||||
| 								.getReadableBody(context))); | ||||
| 			} | ||||
| 			mBuilder.setContentTitle(unread.size() + " " | ||||
| 					+ context.getString(R.string.unread_conversations)); | ||||
| 			mBuilder.setContentText(names.toString()); | ||||
| 			mBuilder.setStyle(style); | ||||
| 		} | ||||
| 		if ((currentCon != null) && (notify)) { | ||||
| 			targetUuid = currentCon.getUuid(); | ||||
| 		} | ||||
| 		if (unread.size() != 0) { | ||||
| 			mBuilder.setSmallIcon(R.drawable.ic_notification); | ||||
| 			if (notify) { | ||||
| 				if (vibrate) { | ||||
| 					int dat = 70; | ||||
| 					long[] pattern = { 0, 3 * dat, dat, dat }; | ||||
| 					mBuilder.setVibrate(pattern); | ||||
| 				} | ||||
| 				mBuilder.setLights(0xffffffff, 2000, 4000); | ||||
| 				if (ringtone != null) { | ||||
| 					mBuilder.setSound(Uri.parse(ringtone)); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); | ||||
| 			stackBuilder.addParentStack(ConversationActivity.class); | ||||
| 
 | ||||
| 			Intent viewConversationIntent = new Intent(context, | ||||
| 					ConversationActivity.class); | ||||
| 			viewConversationIntent.setAction(Intent.ACTION_VIEW); | ||||
| 			viewConversationIntent.putExtra(ConversationActivity.CONVERSATION, | ||||
| 					targetUuid); | ||||
| 			viewConversationIntent | ||||
| 					.setType(ConversationActivity.VIEW_CONVERSATION); | ||||
| 
 | ||||
| 			stackBuilder.addNextIntent(viewConversationIntent); | ||||
| 
 | ||||
| 			PendingIntent resultPendingIntent = stackBuilder.getPendingIntent( | ||||
| 					0, PendingIntent.FLAG_UPDATE_CURRENT); | ||||
| 
 | ||||
| 			mBuilder.setContentIntent(resultPendingIntent); | ||||
| 			Notification notification = mBuilder.build(); | ||||
| 			mNotificationManager.notify(2342, notification); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private static boolean wasHighlightedOrPrivate(Conversation conversation) { | ||||
| 		List<Message> messages = conversation.getMessages(); | ||||
| 		String nick = conversation.getMucOptions().getActualNick(); | ||||
| 		Pattern highlight = generateNickHighlightPattern(nick); | ||||
| 		for (int i = messages.size() - 1; i >= 0; --i) { | ||||
| 			if (messages.get(i).isRead()) { | ||||
| 				break; | ||||
| 			} else { | ||||
| 				Matcher m = highlight.matcher(messages.get(i).getBody()); | ||||
| 				if (m.find() | ||||
| 						|| messages.get(i).getType() == Message.TYPE_PRIVATE) { | ||||
| 					return true; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	public static void prepareContactBadge(final Activity activity, | ||||
| 			QuickContactBadge badge, final Contact contact, Context context) { | ||||
| 		if (contact.getSystemAccount() != null) { | ||||
|  | @ -511,6 +336,7 @@ public class UIHelper { | |||
| 		badge.setImageBitmap(contact.getImage(72, context)); | ||||
| 	} | ||||
| 
 | ||||
| 	@SuppressLint("InflateParams") | ||||
| 	public static AlertDialog getVerifyFingerprintDialog( | ||||
| 			final ConversationActivity activity, | ||||
| 			final Conversation conversation, final View msg) { | ||||
|  |  | |||
|  | @ -166,8 +166,14 @@ public class XmppConnection implements Runnable { | |||
| 							+ ":" + srvRecordPort); | ||||
| 					socket = new Socket(srvRecordServer, srvRecordPort); | ||||
| 				} | ||||
| 			} else { | ||||
| 			} else if (namePort.containsKey("error") | ||||
| 					&& "nosrv".equals(namePort.getString("error", null))) { | ||||
| 				socket = new Socket(account.getServer(), 5222); | ||||
| 			} else { | ||||
| 				Log.d(Config.LOGTAG, account.getJid() | ||||
| 						+ ": timeout in DNS resolution"); | ||||
| 				changeStatus(Account.STATUS_OFFLINE); | ||||
| 				return; | ||||
| 			} | ||||
| 			OutputStream out = socket.getOutputStream(); | ||||
| 			tagWriter.setOutputStream(out); | ||||
|  | @ -307,7 +313,8 @@ public class XmppConnection implements Runnable { | |||
| 				} catch (NumberFormatException e) { | ||||
| 
 | ||||
| 				} | ||||
| 				changeStatus(Account.STATUS_ONLINE); | ||||
| 				sendInitialPing(); | ||||
| 
 | ||||
| 			} else if (nextTag.isStart("r")) { | ||||
| 				tagReader.readElement(nextTag); | ||||
| 				AckPacket ack = new AckPacket(this.stanzasReceived, smVersion); | ||||
|  | @ -348,6 +355,22 @@ public class XmppConnection implements Runnable { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private void sendInitialPing() { | ||||
| 		Log.d(Config.LOGTAG, account.getJid() + ": sending intial ping"); | ||||
| 		IqPacket iq = new IqPacket(IqPacket.TYPE_GET); | ||||
| 		iq.setFrom(account.getFullJid()); | ||||
| 		iq.addChild("ping", "urn:xmpp:ping"); | ||||
| 		this.sendIqPacket(iq, new OnIqPacketReceived() { | ||||
| 
 | ||||
| 			@Override | ||||
| 			public void onIqPacketReceived(Account account, IqPacket packet) { | ||||
| 				Log.d(Config.LOGTAG, account.getJid() | ||||
| 						+ ": online with resource " + account.getResource()); | ||||
| 				changeStatus(Account.STATUS_ONLINE); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	private Element processPacket(Tag currentTag, int packetType) | ||||
| 			throws XmlPullParserException, IOException { | ||||
| 		Element element; | ||||
|  | @ -372,8 +395,11 @@ public class XmppConnection implements Runnable { | |||
| 		while (!nextTag.isEnd(element.getName())) { | ||||
| 			if (!nextTag.isNo()) { | ||||
| 				Element child = tagReader.readElement(nextTag); | ||||
| 				if ((packetType == PACKET_IQ) | ||||
| 						&& ("jingle".equals(child.getName()))) { | ||||
| 				String type = currentTag.getAttribute("type"); | ||||
| 				if (packetType == PACKET_IQ | ||||
| 						&& "jingle".equals(child.getName()) | ||||
| 						&& ("set".equalsIgnoreCase(type) || "get" | ||||
| 								.equalsIgnoreCase(type))) { | ||||
| 					element = new JinglePacket(); | ||||
| 					element.setAttributes(currentTag.getAttributes()); | ||||
| 				} | ||||
|  | @ -410,7 +436,9 @@ public class XmppConnection implements Runnable { | |||
| 				} | ||||
| 
 | ||||
| 				packetCallbacks.remove(packet.getId()); | ||||
| 			} else if (this.unregisteredIqListener != null) { | ||||
| 			} else if ((packet.getType() == IqPacket.TYPE_GET || packet | ||||
| 					.getType() == IqPacket.TYPE_SET) | ||||
| 					&& this.unregisteredIqListener != null) { | ||||
| 				this.unregisteredIqListener.onIqPacketReceived(account, packet); | ||||
| 			} | ||||
| 		} | ||||
|  | @ -657,7 +685,7 @@ public class XmppConnection implements Runnable { | |||
| 				if (bind != null) { | ||||
| 					Element jid = bind.findChild("jid"); | ||||
| 					if (jid != null && jid.getContent() != null) { | ||||
| 						account.setResource(jid.getContent().split("/",2)[1]); | ||||
| 						account.setResource(jid.getContent().split("/", 2)[1]); | ||||
| 						if (streamFeatures.hasChild("sm", "urn:xmpp:sm:3")) { | ||||
| 							smVersion = 3; | ||||
| 							EnablePacket enable = new EnablePacket(smVersion); | ||||
|  | @ -677,7 +705,7 @@ public class XmppConnection implements Runnable { | |||
| 						if (bindListener != null) { | ||||
| 							bindListener.onBind(account); | ||||
| 						} | ||||
| 						changeStatus(Account.STATUS_ONLINE); | ||||
| 						sendInitialPing(); | ||||
| 					} else { | ||||
| 						disconnect(true); | ||||
| 					} | ||||
|  | @ -882,8 +910,7 @@ public class XmppConnection implements Runnable { | |||
| 	} | ||||
| 
 | ||||
| 	public void disconnect(boolean force) { | ||||
| 		changeStatus(Account.STATUS_OFFLINE); | ||||
| 		Log.d(Config.LOGTAG, "disconnecting"); | ||||
| 		Log.d(Config.LOGTAG, account.getJid()+": disconnecting"); | ||||
| 		try { | ||||
| 			if (force) { | ||||
| 				socket.close(); | ||||
|  | @ -901,6 +928,7 @@ public class XmppConnection implements Runnable { | |||
| 								Thread.sleep(100); | ||||
| 							} | ||||
| 							tagWriter.writeTag(Tag.end("stream:stream")); | ||||
| 							socket.close(); | ||||
| 						} catch (IOException e) { | ||||
| 							Log.d(Config.LOGTAG, | ||||
| 									"io exception during disconnect"); | ||||
|  |  | |||
|  | @ -88,8 +88,8 @@ public class JingleConnection implements Downloadable { | |||
| 				sendSuccess(); | ||||
| 				if (acceptedAutomatically) { | ||||
| 					message.markUnread(); | ||||
| 					JingleConnection.this.mXmppConnectionService.notifyUi( | ||||
| 							message.getConversation(), true); | ||||
| 					JingleConnection.this.mXmppConnectionService | ||||
| 							.getNotificationService().push(message); | ||||
| 				} | ||||
| 				BitmapFactory.Options options = new BitmapFactory.Options(); | ||||
| 				options.inJustDecodeBounds = true; | ||||
|  | @ -256,12 +256,12 @@ public class JingleConnection implements Downloadable { | |||
| 		this.status = STATUS_INITIATED; | ||||
| 		Conversation conversation = this.mXmppConnectionService | ||||
| 				.findOrCreateConversation(account, | ||||
| 						packet.getFrom().split("/",2)[0], false); | ||||
| 						packet.getFrom().split("/", 2)[0], false); | ||||
| 		this.message = new Message(conversation, "", Message.ENCRYPTION_NONE); | ||||
| 		this.message.setType(Message.TYPE_IMAGE); | ||||
| 		this.message.setStatus(Message.STATUS_RECEIVED_OFFER); | ||||
| 		this.message.setDownloadable(this); | ||||
| 		String[] fromParts = packet.getFrom().split("/",2); | ||||
| 		String[] fromParts = packet.getFrom().split("/", 2); | ||||
| 		this.message.setPresence(fromParts[1]); | ||||
| 		this.account = account; | ||||
| 		this.initiator = packet.getFrom(); | ||||
|  | @ -319,8 +319,8 @@ public class JingleConnection implements Downloadable { | |||
| 										+ " allowed size:" | ||||
| 										+ this.mJingleConnectionManager | ||||
| 												.getAutoAcceptFileSize()); | ||||
| 						this.mXmppConnectionService | ||||
| 								.notifyUi(conversation, true); | ||||
| 						this.mXmppConnectionService.getNotificationService() | ||||
| 								.push(message); | ||||
| 					} | ||||
| 					this.file = this.mXmppConnectionService.getFileBackend() | ||||
| 							.getJingleFile(message, false); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 iNPUTmice
						iNPUTmice