Extract TextSecure strings for i18n.
1) Change all instances which use concatenation to build strings with variables in them to use string formatting instead. 2) Extract all string literals from layouts and menus into strings.xml 3) Extract all string literals from code into strings.xml
@ -36,58 +36,58 @@
|
|||||||
|
|
||||||
<activity android:name=".PassphraseCreateActivity"
|
<activity android:name=".PassphraseCreateActivity"
|
||||||
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
||||||
android:label="Create Passphrase"
|
android:label="@string/create_passphrase"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".PassphrasePromptActivity"
|
<activity android:name=".PassphrasePromptActivity"
|
||||||
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
||||||
android:label="Enter Passphrase"
|
android:label="@string/enter_passphrase"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
android:windowSoftInputMode="stateVisible"
|
android:windowSoftInputMode="stateVisible"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".ContactSelectionActivity"
|
<activity android:name=".ContactSelectionActivity"
|
||||||
android:label="Select Contacts"
|
android:label="@string/select_contacts"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".AutoInitiateActivity"
|
<activity android:name=".AutoInitiateActivity"
|
||||||
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
||||||
android:label="TextSecure Messaging Detected"
|
android:label="@string/textsecure_messaging_detected"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".ViewIdentityActivity"
|
<activity android:name=".ViewIdentityActivity"
|
||||||
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
||||||
android:label="Public Identity Key"
|
android:label="@string/public_identity_key"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".PassphraseChangeActivity"
|
<activity android:name=".PassphraseChangeActivity"
|
||||||
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
||||||
android:label="Change Passphrase"
|
android:label="@string/change_passphrase2"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".VerifyKeysActivity"
|
<activity android:name=".VerifyKeysActivity"
|
||||||
android:label="Verify Session"
|
android:label="@string/verify_session"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".VerifyIdentityActivity"
|
<activity android:name=".VerifyIdentityActivity"
|
||||||
android:label="Verify Identity"
|
android:label="@string/verify_identity"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".SaveIdentityActivity"
|
<activity android:name=".SaveIdentityActivity"
|
||||||
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
||||||
android:label="Save Identity"
|
android:label="@string/save_identity"
|
||||||
android:windowSoftInputMode="stateVisible"
|
android:windowSoftInputMode="stateVisible"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".ReviewIdentitiesActivity"
|
<activity android:name=".ReviewIdentitiesActivity"
|
||||||
android:label="Manage Identity Keys"
|
android:label="@string/manage_identity_keys2"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".ReceiveKeyActivity"
|
<activity android:name=".ReceiveKeyActivity"
|
||||||
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
||||||
android:label="Complete Key Exchange"
|
android:label="@string/complete_key_exchange"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<activity android:name=".ApplicationPreferencesActivity"
|
<activity android:name=".ApplicationPreferencesActivity"
|
||||||
@ -95,7 +95,7 @@
|
|||||||
|
|
||||||
<activity android:name=".VerifyImportedIdentityActivity"
|
<activity android:name=".VerifyImportedIdentityActivity"
|
||||||
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
android:theme="@style/Theme.Sherlock.Light.Dialog"
|
||||||
android:label="Verify Imported Identity"
|
android:label="@string/verify_imported_identity"
|
||||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||||
|
|
||||||
<service android:enabled="true" android:name=".service.ApplicationMigrationService"/>
|
<service android:enabled="true" android:name=".service.ApplicationMigrationService"/>
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 789 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
@ -9,22 +9,22 @@
|
|||||||
<TextView android:id="@+id/description_text"
|
<TextView android:id="@+id/description_text"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="5px"
|
android:layout_marginBottom="5dip"
|
||||||
android:text="You have received a message from someone who supports TextSecure encrypted sessions. Would you like to initiate a key exchange so you can communicate securely?"/>
|
android:text="@string/you_have_received_a_message_from_someone_who_supports_textsecure_encrypted_sessions_would_you_like_to_initiate_a_key_exchange_so_you_can_communicate_securely"/>
|
||||||
|
|
||||||
<LinearLayout android:layout_width="fill_parent"
|
<LinearLayout android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="10px"
|
android:layout_marginTop="10dip"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<Button android:id="@+id/initiate_button"
|
<Button android:id="@+id/initiate_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Initiate Exchange"
|
android:text="@string/initiate_exchange"
|
||||||
android:gravity="center"/>
|
android:gravity="center"/>
|
||||||
|
|
||||||
<Button android:id="@+id/cancel_button"
|
<Button android:id="@+id/cancel_button"
|
||||||
android:text="Cancel"
|
android:text="@string/cancel"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"/>
|
android:gravity="center"/>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TextView
|
<TextView
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:text="Old passphrase:"
|
android:text="@string/old_passphrase"
|
||||||
android:padding="3dip" />
|
android:padding="3dip" />
|
||||||
|
|
||||||
<EditText android:id="@+id/old_passphrase"
|
<EditText android:id="@+id/old_passphrase"
|
||||||
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TextView
|
<TextView
|
||||||
android:text="New passphrase:"
|
android:text="@string/new_passphrase"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:padding="3dip" />
|
android:padding="3dip" />
|
||||||
|
|
||||||
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TextView
|
<TextView
|
||||||
android:text="Repeat new passphrase:"
|
android:text="@string/repeat_new_passphrase"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:padding="3dip" />
|
android:padding="3dip" />
|
||||||
|
|
||||||
@ -51,13 +51,13 @@
|
|||||||
android:padding="10dip"
|
android:padding="10dip"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Cancel"/>
|
android:text="@string/cancel"/>
|
||||||
|
|
||||||
<Button android:id="@+id/ok_button"
|
<Button android:id="@+id/ok_button"
|
||||||
android:padding="10dip"
|
android:padding="10dip"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Ok"/>
|
android:text="@android:string/ok"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableLayout>
|
</TableLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
/*
|
|
||||||
* Copyright 2009, The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
|
||||||
android:paddingLeft="14dip"
|
|
||||||
android:paddingRight="5dip"
|
|
||||||
>
|
|
||||||
|
|
||||||
<ImageView android:id="@+id/presence"
|
|
||||||
android:layout_width="32dip"
|
|
||||||
android:layout_height="32dip"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_marginLeft="5dip"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
|
|
||||||
android:gravity="center"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextView android:id="@+id/label"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:layout_marginBottom="8dip"
|
|
||||||
android:layout_marginTop="-8dip"
|
|
||||||
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="marquee"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:visibility = "gone"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextView android:id="@+id/number"
|
|
||||||
android:visibility = "gone"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="5dip"
|
|
||||||
android:layout_toRightOf="@id/label"
|
|
||||||
android:layout_alignBaseline="@id/label"
|
|
||||||
android:layout_toLeftOf="@id/presence"
|
|
||||||
android:layout_alignWithParentIfMissing="true"
|
|
||||||
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="marquee"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextView android:id="@+id/name"
|
|
||||||
android:layout_width="0dip"
|
|
||||||
android:layout_height="0dip"
|
|
||||||
android:layout_above="@id/label"
|
|
||||||
android:layout_alignWithParentIfMissing="true"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_toLeftOf="@id/presence"
|
|
||||||
android:layout_marginBottom="1dip"
|
|
||||||
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="marquee"
|
|
||||||
android:gravity="center_vertical|left"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
|
||||||
/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
@ -1,27 +1,7 @@
|
|||||||
<!--
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<!-- <EditText android:id="@+id/group_name"-->
|
|
||||||
<!-- android:layout_width="fill_parent"-->
|
|
||||||
<!-- android:layout_height="wrap_content"-->
|
|
||||||
<!-- android:hint="Enter group name"-->
|
|
||||||
<!-- android:layout_alignParentTop="true" />-->
|
|
||||||
|
|
||||||
<ListView android:id="@android:id/list"
|
<ListView android:id="@android:id/list"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
@ -32,10 +12,11 @@
|
|||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:fillViewport="true">
|
android:fillViewport="true">
|
||||||
|
|
||||||
<TextView android:id="@+id/emptyText"
|
<TextView android:id="@+id/emptyText"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="No contacts."
|
android:text="@string/no_contacts"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
android:paddingLeft="10dip"
|
android:paddingLeft="10dip"
|
||||||
@ -43,21 +24,5 @@
|
|||||||
android:paddingTop="10dip"
|
android:paddingTop="10dip"
|
||||||
android:lineSpacingMultiplier="0.92"
|
android:lineSpacingMultiplier="0.92"
|
||||||
/>
|
/>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
<!-- <Button android:id="@+id/create_button"-->
|
|
||||||
<!-- android:layout_width="wrap_content"-->
|
|
||||||
<!-- android:layout_height="wrap_content"-->
|
|
||||||
<!-- android:padding="15dip"-->
|
|
||||||
<!-- android:text="Create"-->
|
|
||||||
<!-- android:layout_alignParentBottom="true"-->
|
|
||||||
<!-- android:layout_alignParentLeft="true" />-->
|
|
||||||
<!-- -->
|
|
||||||
<!-- <Button android:id="@+id/cancel_button"-->
|
|
||||||
<!-- android:layout_width="wrap_content"-->
|
|
||||||
<!-- android:layout_height="wrap_content"-->
|
|
||||||
<!-- android:padding="15dip"-->
|
|
||||||
<!-- android:text="Cancel"-->
|
|
||||||
<!-- android:layout_alignParentBottom="true"-->
|
|
||||||
<!-- android:layout_alignParentRight="true" /> -->
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -1,21 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
|
||||||
/*
|
|
||||||
* Copyright 2009, The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
|
@ -1,16 +1,3 @@
|
|||||||
<!--
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
@ -20,18 +7,16 @@
|
|||||||
<ListView android:id="@android:id/list"
|
<ListView android:id="@android:id/list"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:fastScrollEnabled="true"
|
android:fastScrollEnabled="true" />
|
||||||
/>
|
|
||||||
|
|
||||||
<ScrollView android:id="@android:id/empty"
|
<ScrollView android:id="@android:id/empty"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:fillViewport="true"
|
android:fillViewport="true">
|
||||||
>
|
|
||||||
<TextView android:id="@+id/emptyText"
|
<TextView android:id="@+id/emptyText"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="No contacts."
|
android:text="@string/no_contacts"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
android:paddingLeft="10dip"
|
android:paddingLeft="10dip"
|
||||||
|
@ -1,21 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
|
||||||
/*
|
|
||||||
* Copyright 2009, The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
|
@ -1,16 +1,4 @@
|
|||||||
<!--
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
@ -20,18 +8,17 @@
|
|||||||
<ListView android:id="@android:id/list"
|
<ListView android:id="@android:id/list"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:fastScrollEnabled="true"
|
android:fastScrollEnabled="true" />
|
||||||
/>
|
|
||||||
|
|
||||||
<ScrollView android:id="@android:id/empty"
|
<ScrollView android:id="@android:id/empty"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:fillViewport="true"
|
android:fillViewport="true" >
|
||||||
>
|
|
||||||
<TextView android:id="@+id/emptyText"
|
<TextView android:id="@+id/emptyText"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="No recent calls."
|
android:text="@string/no_recent_calls"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
android:paddingLeft="10dip"
|
android:paddingLeft="10dip"
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (C) 2008 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<ListView android:id="@android:id/list"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:fastScrollEnabled="true"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ScrollView android:id="@android:id/empty"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:fillViewport="true"
|
|
||||||
>
|
|
||||||
<TextView android:id="@+id/emptyText"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="No contacts."
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
android:paddingLeft="10dip"
|
|
||||||
android:paddingRight="10dip"
|
|
||||||
android:paddingTop="10dip"
|
|
||||||
android:lineSpacingMultiplier="0.92"
|
|
||||||
/>
|
|
||||||
</ScrollView>
|
|
||||||
</LinearLayout>
|
|
@ -59,26 +59,12 @@
|
|||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<!-- <Button-->
|
|
||||||
<!-- android:id="@+id/view_image_button"-->
|
|
||||||
<!-- style="?android:attr/buttonStyleSmall"-->
|
|
||||||
<!-- android:layout_width="100dip"-->
|
|
||||||
<!-- android:layout_height="50dip"-->
|
|
||||||
<!-- android:text="View" />-->
|
|
||||||
<!-- -->
|
|
||||||
<!-- <Button-->
|
|
||||||
<!-- android:id="@+id/replace_image_button"-->
|
|
||||||
<!-- style="?android:attr/buttonStyleSmall"-->
|
|
||||||
<!-- android:layout_width="100dip"-->
|
|
||||||
<!-- android:layout_height="50dip"-->
|
|
||||||
<!-- android:text="Replace" />-->
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/remove_image_button"
|
android:id="@+id/remove_image_button"
|
||||||
style="?android:attr/buttonStyleSmall"
|
style="?android:attr/buttonStyleSmall"
|
||||||
android:layout_width="100dip"
|
android:layout_width="100dip"
|
||||||
android:layout_height="50dip"
|
android:layout_height="50dip"
|
||||||
android:text="Remove" />
|
android:text="@string/remove" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
@ -108,7 +94,7 @@
|
|||||||
android:autoText="true"
|
android:autoText="true"
|
||||||
android:capitalize="sentences"
|
android:capitalize="sentences"
|
||||||
android:nextFocusRight="@+id/send_button"
|
android:nextFocusRight="@+id/send_button"
|
||||||
android:hint="Type message"
|
android:hint="@string/type_message"
|
||||||
android:maxLines="4"
|
android:maxLines="4"
|
||||||
android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine"
|
android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine"
|
||||||
android:imeOptions="actionSend|flagNoEnterAction"
|
android:imeOptions="actionSend|flagNoEnterAction"
|
||||||
@ -121,7 +107,7 @@
|
|||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:nextFocusLeft="@+id/embedded_text_editor"
|
android:nextFocusLeft="@+id/embedded_text_editor"
|
||||||
android:text="Send"
|
android:text="@string/send2"
|
||||||
android:padding="8dip"
|
android:padding="8dip"
|
||||||
/>
|
/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
android:text="Batch Selection Mode"
|
android:text="@string/batch_selection_mode"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
|
@ -12,14 +12,14 @@
|
|||||||
android:paddingRight="16dip"
|
android:paddingRight="16dip"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView android:text="Please choose a passphrase that will be used to locally encrypt your data. This should be a strong passphrase."
|
<TextView android:text="@string/please_choose_a_passphrase_that_will_be_used_to_locally_encrypt_your_data_this_should_be_a_strong_passphrase"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="10dip"
|
android:layout_marginTop="10dip"
|
||||||
android:layout_marginBottom="10dip"/>
|
android:layout_marginBottom="10dip"/>
|
||||||
|
|
||||||
<TextView android:text="Passphrase:"
|
<TextView android:text="@string/passphrase"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -37,7 +37,7 @@
|
|||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
android:layout_marginBottom="5dip"
|
android:layout_marginBottom="5dip"
|
||||||
android:layout_marginTop="10dip"
|
android:layout_marginTop="10dip"
|
||||||
android:text="Repeat:"/>
|
android:text="@string/repeat"/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -57,14 +57,14 @@
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<Button android:layout_height="wrap_content"
|
<Button android:layout_height="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:text="Cancel"
|
android:text="@string/cancel"
|
||||||
android:id="@+id/cancel_button"
|
android:id="@+id/cancel_button"
|
||||||
android:layout_marginRight="15dip"
|
android:layout_marginRight="15dip"
|
||||||
android:layout_marginLeft="16dip"/>
|
android:layout_marginLeft="16dip"/>
|
||||||
|
|
||||||
<Button android:layout_width="wrap_content"
|
<Button android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="OK"
|
android:text="@android:string/ok"
|
||||||
android:id="@+id/ok_button"
|
android:id="@+id/ok_button"
|
||||||
android:layout_marginRight="16dip"/>
|
android:layout_marginRight="16dip"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
@ -1,22 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2008 Esmertec AG.
|
|
||||||
* Copyright (C) 2008 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
<?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="fill_parent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<ListView android:id="@android:id/list"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:drawSelectorOnTop="false"
|
|
||||||
android:scrollbarStyle="insideOverlay"
|
|
||||||
android:fadingEdgeLength="16dip"
|
|
||||||
android:layout_alignParentTop="true"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
@ -1,43 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2008 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/mms_download_controls"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<Button android:id="@+id/btn_download_msg"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:text="Download"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<TextView android:id="@+id/label_downloading"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_marginLeft="5dp"
|
|
||||||
android:layout_marginRight="5dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="Downloading"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
@ -23,14 +23,14 @@
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<Button android:layout_height="wrap_content"
|
<Button android:layout_height="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:text="Cancel"
|
android:text="@string/cancel"
|
||||||
android:id="@+id/cancel_button"
|
android:id="@+id/cancel_button"
|
||||||
android:layout_marginRight="15dip"
|
android:layout_marginRight="15dip"
|
||||||
android:layout_marginLeft="16dip"/>
|
android:layout_marginLeft="16dip"/>
|
||||||
|
|
||||||
<Button android:layout_width="wrap_content"
|
<Button android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="OK"
|
android:text="@android:string/ok"
|
||||||
android:id="@+id/ok_button"
|
android:id="@+id/ok_button"
|
||||||
android:layout_marginRight="16dip"/>
|
android:layout_marginRight="16dip"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
@ -30,25 +30,25 @@
|
|||||||
<Button android:id="@+id/verify_session_button"
|
<Button android:id="@+id/verify_session_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Session"
|
android:text="@string/session"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:gravity="center" />
|
android:gravity="center" />
|
||||||
|
|
||||||
<Button android:id="@+id/verify_identity_button"
|
<Button android:id="@+id/verify_identity_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Identities"
|
android:text="@string/identities"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:gravity="center" />
|
android:gravity="center" />
|
||||||
|
|
||||||
<Button android:id="@+id/ok_button"
|
<Button android:id="@+id/ok_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Complete Exchange"
|
android:text="@string/complete_exchange"
|
||||||
android:gravity="center"/>
|
android:gravity="center"/>
|
||||||
|
|
||||||
<Button android:id="@+id/cancel_button"
|
<Button android:id="@+id/cancel_button"
|
||||||
android:text="Cancel"
|
android:text="@android:string/cancel"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"/>
|
android:gravity="center"/>
|
||||||
|
@ -11,15 +11,13 @@
|
|||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:paddingLeft="14dip"
|
android:paddingLeft="14dip"
|
||||||
android:paddingRight="11dip"
|
android:paddingRight="11dip"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical" />
|
||||||
/>
|
|
||||||
|
|
||||||
<View android:id="@+id/divider"
|
<View android:id="@+id/divider"
|
||||||
android:layout_width="1dip"
|
android:layout_width="1dip"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:layout_toRightOf="@id/call_type_icon"
|
android:layout_toRightOf="@id/call_type_icon"
|
||||||
android:layout_marginRight="11dip"
|
android:layout_marginRight="11dip" />
|
||||||
/>
|
|
||||||
|
|
||||||
<TextView android:id="@+id/date"
|
<TextView android:id="@+id/date"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -28,10 +26,8 @@
|
|||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:layout_marginBottom="9dip"
|
android:layout_marginBottom="9dip"
|
||||||
android:layout_marginTop="5dip"
|
android:layout_marginTop="5dip"
|
||||||
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
android:singleLine="true"
|
android:singleLine="true" />
|
||||||
/>
|
|
||||||
|
|
||||||
<TextView android:id="@+id/label"
|
<TextView android:id="@+id/label"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -40,12 +36,10 @@
|
|||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:layout_marginBottom="8dip"
|
android:layout_marginBottom="8dip"
|
||||||
android:layout_marginTop="-10dip"
|
android:layout_marginTop="-10dip"
|
||||||
|
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="marquee"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold" />
|
||||||
/>
|
|
||||||
|
|
||||||
<TextView android:id="@+id/number"
|
<TextView android:id="@+id/number"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -55,11 +49,9 @@
|
|||||||
android:layout_toLeftOf="@id/date"
|
android:layout_toLeftOf="@id/date"
|
||||||
android:layout_alignBaseline="@id/label"
|
android:layout_alignBaseline="@id/label"
|
||||||
android:layout_alignWithParentIfMissing="true"
|
android:layout_alignWithParentIfMissing="true"
|
||||||
|
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="marquee"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
/>
|
|
||||||
|
|
||||||
|
|
||||||
<CheckedTextView android:id="@+id/line1"
|
<CheckedTextView android:id="@+id/line1"
|
||||||
@ -75,7 +67,6 @@
|
|||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
|
||||||
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
|
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="marquee"/>
|
||||||
/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
android:capitalize="sentences"
|
android:capitalize="sentences"
|
||||||
android:autoText="true"
|
android:autoText="true"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:hint="To"
|
android:hint="@string/to"
|
||||||
android:paddingRight="45dip"
|
android:paddingRight="45dip"
|
||||||
android:layout_width="fill_parent"/>
|
android:layout_width="fill_parent"/>
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<TextView android:id="@id/android:empty"
|
<TextView android:id="@id/android:empty"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="You don't currently have any identity keys in your trust database."
|
android:text="@string/you_don_t_currently_have_any_identity_keys_in_your_trust_database"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
android:padding="20dip" />
|
android:padding="20dip" />
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
android:layout_marginTop="5dip"
|
android:layout_marginTop="5dip"
|
||||||
android:layout_marginBottom="5dip"
|
android:layout_marginBottom="5dip"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
android:text="Identity Name:" />
|
android:text="@string/identity_name" />
|
||||||
|
|
||||||
<EditText android:layout_height="wrap_content"
|
<EditText android:layout_height="wrap_content"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
@ -30,14 +30,14 @@
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<Button android:layout_height="wrap_content"
|
<Button android:layout_height="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:text="Cancel"
|
android:text="@string/cancel"
|
||||||
android:id="@+id/cancel_button"
|
android:id="@+id/cancel_button"
|
||||||
android:layout_marginRight="15dip"
|
android:layout_marginRight="15dip"
|
||||||
android:layout_marginLeft="16dip"/>
|
android:layout_marginLeft="16dip"/>
|
||||||
|
|
||||||
<Button android:layout_width="wrap_content"
|
<Button android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="OK"
|
android:text="@android:string/ok"
|
||||||
android:id="@+id/ok_button"
|
android:id="@+id/ok_button"
|
||||||
android:layout_marginRight="16dip"/>
|
android:layout_marginRight="16dip"/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
<?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:orientation="vertical">
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.RecipientsPanel
|
|
||||||
android:id="@+id/key_recipients"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:visibility="visible"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button android:id="@+id/send_key_button"
|
|
||||||
android:layout_marginLeft="5dip"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
style="?android:attr/buttonStyle"
|
|
||||||
android:layout_below="@id/key_recipients"
|
|
||||||
android:layout_alignRight="@id/key_recipients"
|
|
||||||
android:text="Send"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button android:id="@+id/cancel_key_button"
|
|
||||||
android:layout_marginLeft="5dip"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
style="?android:attr/buttonStyle"
|
|
||||||
android:layout_toLeftOf="@id/send_key_button"
|
|
||||||
android:layout_below="@id/key_recipients"
|
|
||||||
android:text="Cancel"
|
|
||||||
/>
|
|
||||||
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
|||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
android:text="Their identity (they read):"
|
android:text="@string/their_identity_they_read"
|
||||||
android:padding="7dip" />
|
android:padding="7dip" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -29,7 +29,7 @@
|
|||||||
<TextView
|
<TextView
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Your identity (you read):"
|
android:text="@string/your_identity_you_read"
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
android:padding="7dip" />
|
android:padding="7dip" />
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TextView
|
<TextView
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:text="Identity name:\n"
|
android:text="@string/identity_name_n"
|
||||||
android:padding="3dip" />
|
android:padding="3dip" />
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/identity_name"
|
android:id="@+id/identity_name"
|
||||||
@ -22,7 +22,7 @@
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TextView
|
<TextView
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:text="Imported identity:\n"
|
android:text="@string/imported_identity_n"
|
||||||
android:padding="3dip" />
|
android:padding="3dip" />
|
||||||
<TextView
|
<TextView
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
@ -43,19 +43,19 @@
|
|||||||
android:padding="15dip"
|
android:padding="15dip"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Verified!"/>
|
android:text="@string/verified5"/>
|
||||||
|
|
||||||
<Button android:id="@+id/compare_button"
|
<Button android:id="@+id/compare_button"
|
||||||
android:padding="15dip"
|
android:padding="15dip"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Compare"/>
|
android:text="@string/compare5"/>
|
||||||
|
|
||||||
<Button android:id="@+id/cancel_button"
|
<Button android:id="@+id/cancel_button"
|
||||||
android:padding="15dip"
|
android:padding="15dip"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Cancel" />
|
android:text="@string/cancel" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
android:text="They read this:"
|
android:text="@string/they_read_this"
|
||||||
android:padding="7dip" />
|
android:padding="7dip" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -31,7 +31,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
android:text="You read this:"
|
android:text="@string/you_read_this"
|
||||||
android:padding="7dip" />
|
android:padding="7dip" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TextView
|
<TextView
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
android:text="Identity:"
|
android:text="@string/identity5"
|
||||||
android:layout_marginRight="7dip" />
|
android:layout_marginRight="7dip" />
|
||||||
<TextView
|
<TextView
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
@ -34,14 +34,14 @@
|
|||||||
android:padding="5dip"
|
android:padding="5dip"
|
||||||
android:layout_width="100dip"
|
android:layout_width="100dip"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="QR Code" />
|
android:text="@string/qr_code" />
|
||||||
|
|
||||||
<Button android:id="@+id/ok_button"
|
<Button android:id="@+id/ok_button"
|
||||||
android:layout_margin="10dip"
|
android:layout_margin="10dip"
|
||||||
android:padding="5dip"
|
android:padding="5dip"
|
||||||
android:layout_width="100dip"
|
android:layout_width="100dip"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Ok"/>
|
android:text="@android:string/ok"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:title="Finished"
|
<item android:title="@string/menu_finished"
|
||||||
android:id="@+id/menu_selection_finished"
|
android:id="@+id/menu_selection_finished"
|
||||||
android:icon="@drawable/ic_menu_done_holo_dark"
|
android:icon="@drawable/ic_menu_done_holo_dark"
|
||||||
android:showAsAction="ifRoom"
|
android:showAsAction="ifRoom"
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:title="Select All"
|
<item android:title="@string/menu_select_all"
|
||||||
android:id="@+id/menu_select_all" />
|
android:id="@+id/menu_select_all" />
|
||||||
|
|
||||||
<item android:title="Unselect All"
|
<item android:title="@string/menu_unselect_all"
|
||||||
android:id="@+id/menu_unselect_all" />
|
android:id="@+id/menu_unselect_all" />
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item android:title="Add attachment"
|
<item android:title="@string/menu_add_attachment"
|
||||||
android:id="@+id/menu_add_attachment"
|
android:id="@+id/menu_add_attachment"
|
||||||
android:icon="@drawable/ic_menu_attach" />
|
android:icon="@drawable/ic_menu_attach" />
|
||||||
|
|
||||||
<item android:title="Delete thread"
|
<item android:title="@string/menu_delete_thread"
|
||||||
android:id="@+id/menu_delete_thread"
|
android:id="@+id/menu_delete_thread"
|
||||||
android:icon="@android:drawable/ic_menu_delete" />
|
android:icon="@android:drawable/ic_menu_delete" />
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:title="Send unencrypted"
|
<item android:title="@string/menu_send_unencrypted"
|
||||||
android:id="@+id/menu_context_send_unencrypted" />
|
android:id="@+id/menu_context_send_unencrypted" />
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item android:title="Call"
|
<item android:title="@string/menu_call"
|
||||||
android:id="@+id/menu_call"
|
android:id="@+id/menu_call"
|
||||||
android:icon="@drawable/ic_menu_call"
|
android:icon="@drawable/ic_menu_call"
|
||||||
android:showAsAction="ifRoom" />
|
android:showAsAction="ifRoom" />
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:title="Copy text"
|
<item android:title="@string/menu_copy_text"
|
||||||
android:id="@+id/menu_context_copy" />
|
android:id="@+id/menu_context_copy" />
|
||||||
|
|
||||||
<item android:title="Delete message"
|
<item android:title="@string/menu_delete_message"
|
||||||
android:id="@+id/menu_context_delete_message" />
|
android:id="@+id/menu_context_delete_message" />
|
||||||
|
|
||||||
<item android:title="Message details"
|
<item android:title="@string/menu_message_details"
|
||||||
android:id="@+id/menu_context_details" />
|
android:id="@+id/menu_context_details" />
|
||||||
|
|
||||||
<item android:title="Forward message"
|
<item android:title="@string/menu_forward_message"
|
||||||
android:id="@+id/menu_context_forward" />
|
android:id="@+id/menu_context_forward" />
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
android:icon="@drawable/ic_menu_lock_holo_dark"
|
android:icon="@drawable/ic_menu_lock_holo_dark"
|
||||||
android:showAsAction="ifRoom">
|
android:showAsAction="ifRoom">
|
||||||
<menu>
|
<menu>
|
||||||
<item android:title="Start Secure Session"
|
<item android:title="@string/menu_start_secure_session"
|
||||||
android:id="@+id/menu_start_secure_session" />
|
android:id="@+id/menu_start_secure_session" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item android:title="Search"
|
<item android:title="@string/menu_search"
|
||||||
android:id="@+id/menu_search"
|
android:id="@+id/menu_search"
|
||||||
android:icon="@drawable/ic_menu_search_holo_dark"
|
android:icon="@drawable/ic_menu_search_holo_dark"
|
||||||
android:actionViewClass="android.widget.SearchView"
|
android:actionViewClass="android.widget.SearchView"
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item android:title="Delete Selected"
|
<item android:title="@string/menu_delete_selected"
|
||||||
android:id="@+id/menu_delete_selected"
|
android:id="@+id/menu_delete_selected"
|
||||||
android:icon="@drawable/ic_menu_trash_holo_dark"
|
android:icon="@drawable/ic_menu_trash_holo_dark"
|
||||||
android:showAsAction="ifRoom" />
|
android:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item android:title="Select All"
|
<item android:title="@string/menu_select_all"
|
||||||
android:id="@+id/menu_select_all"
|
android:id="@+id/menu_select_all"
|
||||||
android:icon="@drawable/ic_menu_selectall_holo_dark" />
|
android:icon="@drawable/ic_menu_selectall_holo_dark" />
|
||||||
|
|
||||||
<!-- <item android:title="Unselect All" -->
|
|
||||||
<!-- android:id="@+id/menu_unselect_all" -->
|
|
||||||
<!-- android:icon="@android:drawable/ic_menu_revert" /> -->
|
|
||||||
|
|
||||||
</menu>
|
</menu>
|
@ -1,17 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:title="Security"
|
<item android:title="@string/menu_security"
|
||||||
android:id="@+id/menu_security"
|
android:id="@+id/menu_security"
|
||||||
android:icon="@drawable/ic_menu_lock_unverified_holo_dark"
|
android:icon="@drawable/ic_menu_lock_unverified_holo_dark"
|
||||||
android:showAsAction="ifRoom">
|
android:showAsAction="ifRoom">
|
||||||
<menu>
|
<menu>
|
||||||
<item android:title="Verify Session"
|
<item android:title="@string/menu_verify_session"
|
||||||
android:id="@+id/menu_verify_session" />
|
android:id="@+id/menu_verify_session" />
|
||||||
|
|
||||||
<item android:title="Verify Recipient"
|
<item android:title="@string/menu_verify_recipient"
|
||||||
android:id="@+id/menu_verify_recipient"/>
|
android:id="@+id/menu_verify_recipient"/>
|
||||||
|
|
||||||
<item android:title="Abort Secure Session"
|
<item android:title="@string/menu_abort_secure_session"
|
||||||
android:id="@+id/menu_abort_session"/>
|
android:id="@+id/menu_abort_session"/>
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:title="Security"
|
<item android:title="@string/menu_security"
|
||||||
android:id="@+id/menu_security"
|
android:id="@+id/menu_security"
|
||||||
android:icon="@drawable/ic_menu_lock_verified_holo_dark"
|
android:icon="@drawable/ic_menu_lock_verified_holo_dark"
|
||||||
android:showAsAction="ifRoom">
|
android:showAsAction="ifRoom">
|
||||||
<menu>
|
<menu>
|
||||||
<item android:title="Verify Session"
|
<item android:title="@string/menu_verify_session"
|
||||||
android:id="@+id/menu_verify_session" />
|
android:id="@+id/menu_verify_session" />
|
||||||
|
|
||||||
<item android:title="Verify Recipient"
|
<item android:title="@string/menu_verify_recipient"
|
||||||
android:id="@+id/menu_verify_recipient"/>
|
android:id="@+id/menu_verify_recipient"/>
|
||||||
|
|
||||||
<item android:title="Abort Secure Session"
|
<item android:title="@string/menu_abort_secure_session"
|
||||||
android:id="@+id/menu_abort_session"/>
|
android:id="@+id/menu_abort_session"/>
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item android:title="Compare"
|
<item android:title="@string/menu_compare"
|
||||||
android:id="@+id/menu_barcode"
|
android:id="@+id/menu_barcode"
|
||||||
android:icon="@drawable/ic_menu_barcode"
|
android:icon="@drawable/ic_menu_barcode"
|
||||||
android:showAsAction="ifRoom">
|
android:showAsAction="ifRoom">
|
||||||
|
|
||||||
<menu>
|
<menu>
|
||||||
<item android:title="Scan to compare"
|
<item android:title="@string/menu_scan_to_compare"
|
||||||
android:id="@+id/menu_scan"/>
|
android:id="@+id/menu_scan"/>
|
||||||
|
|
||||||
<item android:title="Get scanned to compare"
|
<item android:title="@string/menu_get_scanned_to_compare"
|
||||||
android:id="@+id/menu_get_scanned"/>
|
android:id="@+id/menu_get_scanned"/>
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:title="Unlock"
|
<item android:title="@string/menu_unlock"
|
||||||
android:id="@+id/menu_unlock"
|
android:id="@+id/menu_unlock"
|
||||||
android:showAsAction="ifRoom" />
|
android:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:title="New Message"
|
<item android:title="@string/menu_new_message"
|
||||||
android:id="@+id/menu_new_message"
|
android:id="@+id/menu_new_message"
|
||||||
android:icon="@drawable/ic_menu_msg_compose_holo_dark"
|
android:icon="@drawable/ic_menu_msg_compose_holo_dark"
|
||||||
android:showAsAction="ifRoom" />
|
android:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item android:title="Settings"
|
<item android:title="@string/menu_settings"
|
||||||
android:id="@+id/menu_settings"
|
android:id="@+id/menu_settings"
|
||||||
android:icon="@android:drawable/ic_menu_preferences" />
|
android:icon="@android:drawable/ic_menu_preferences" />
|
||||||
|
|
||||||
<item android:title="Import/Export"
|
<item android:title="@string/menu_import_export"
|
||||||
android:icon="@android:drawable/ic_menu_save">
|
android:icon="@android:drawable/ic_menu_save">
|
||||||
<menu>
|
<menu>
|
||||||
<item android:title="Import"
|
<item android:title="@string/menu_import"
|
||||||
android:id="@+id/menu_import"
|
android:id="@+id/menu_import"
|
||||||
android:icon="@android:drawable/ic_menu_revert" />
|
android:icon="@android:drawable/ic_menu_revert" />
|
||||||
|
|
||||||
<item android:title="Export"
|
<item android:title="@string/menu_export"
|
||||||
android:id="@+id/menu_export"
|
android:id="@+id/menu_export"
|
||||||
android:icon="@android:drawable/ic_menu_save" />
|
android:icon="@android:drawable/ic_menu_save" />
|
||||||
</menu>
|
</menu>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
<item android:title="Clear Passphrase"
|
<item android:title="@string/menu_clear_passphrase"
|
||||||
android:id="@+id/menu_clear_passphrase"
|
android:id="@+id/menu_clear_passphrase"
|
||||||
android:icon="@android:drawable/ic_menu_close_clear_cancel" />
|
android:icon="@android:drawable/ic_menu_close_clear_cancel" />
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:title="Verified"
|
<item android:title="@string/menu_verified"
|
||||||
android:id="@+id/menu_session_verified"
|
android:id="@+id/menu_session_verified"
|
||||||
android:icon="@drawable/ic_menu_done_holo_dark"
|
android:icon="@drawable/ic_menu_done_holo_dark"
|
||||||
android:showAsAction="ifRoom" />
|
android:showAsAction="ifRoom" />
|
||||||
|
@ -1,28 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Activity background color -->
|
|
||||||
<drawable name="class_zero_background">#7f040000</drawable>
|
|
||||||
|
|
||||||
<!-- Widget background -->
|
|
||||||
<drawable name="light_blue_background">#ffecfbff</drawable>
|
|
||||||
<drawable name="white_background">#ffffffff</drawable>
|
<drawable name="white_background">#ffffffff</drawable>
|
||||||
<drawable name="alert_background">#f0777700</drawable>
|
<drawable name="text_color_black">#ff000000</drawable>
|
||||||
|
|
||||||
<!-- text color -->
|
|
||||||
<drawable name="text_color">#ffffffff</drawable>
|
|
||||||
<drawable name="text_color_red">#ffff0000</drawable>
|
|
||||||
<drawable name="text_color_black">#ff000000</drawable>
|
|
||||||
<drawable name="text_color_offwhite">#55ffffff</drawable>
|
|
||||||
|
|
||||||
<!-- Chat "sent time" text background -->
|
|
||||||
<color name="timestamp_color">#bf000000</color>
|
|
||||||
|
|
||||||
<!-- For dark theme -->
|
|
||||||
<drawable name="lightgrey_background">#ff2f2f2f</drawable>
|
|
||||||
<drawable name="softgrey_background">#ff181818</drawable>
|
|
||||||
|
|
||||||
<!-- the background color used for unread conversation -->
|
|
||||||
<color name="light_list_bgcolor">#ffeeeeee</color>
|
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -3,4 +3,387 @@
|
|||||||
<string name="app_name">TextSecure</string>
|
<string name="app_name">TextSecure</string>
|
||||||
<string name="yes">Yes</string>
|
<string name="yes">Yes</string>
|
||||||
<string name="no">No</string>
|
<string name="no">No</string>
|
||||||
|
|
||||||
|
<!-- ApplicationExportManager -->
|
||||||
|
<string name="import_database_and_settings_title">Import Database and Settings?</string>
|
||||||
|
<string name="import_database_and_settings_message">Import TextSecure database, keys, and settings from the SD Card?\n\nWARNING: This will clobber any existing messages, keys, and settings!</string>
|
||||||
|
<string name="importing_database_and_keys">Importing Database and Keys</string>
|
||||||
|
<string name="importing_your_sms_database_keys_and_settings">Importing your SMS database, keys, and settings...</string>
|
||||||
|
<string name="export_database_question">Export Database?</string>
|
||||||
|
<string name="export_textsecure_database_keys_and_settings_prompt">Export TextSecure database, keys, and settings to the SD Card?</string>
|
||||||
|
<string name="exporting_database_and_keys">Exporting Database and Keys</string>
|
||||||
|
<string name="exporting_your_sms_database_keys_and_settings">Exporting your SMS database, keys, and settings...</string>
|
||||||
|
<string name="no_sd_card_found_exclamation">No SD card found!</string>
|
||||||
|
<string name="error_exporting_to_sd_exclamation">Error exporting to SD!</string>
|
||||||
|
<string name="import_successful_exclamation">Import Successful!</string>
|
||||||
|
<string name="export_successful_exclamation">Export Successful!</string>
|
||||||
|
|
||||||
|
<!-- ApplicationMigrationManager -->
|
||||||
|
<string name="migrating_database">Migrating Database</string>
|
||||||
|
<string name="migrating_text_message_database">Migrating text message database...</string>
|
||||||
|
<string name="copy_system_text_message_database_question">Copy System Text Message Database?</string>
|
||||||
|
<string name="copy_system_text_message_database_explanation">TextSecure uses an encrypted database that is separate from the default system database. Would you like to copy your existing text messages into TextSecure\'s encrypted database? Your default system database will be unaffected.</string>
|
||||||
|
<string name="copy">Copy</string>
|
||||||
|
<string name="dont_copy">Don\'t copy</string>
|
||||||
|
|
||||||
|
<!-- ApplicationPreferencesActivity -->
|
||||||
|
<string name="not_found_exclamation">Not found!</string>
|
||||||
|
<string name="no_valid_identity_key_was_found_in_the_specified_contact">No valid identity key was found in the specified contact.</string>
|
||||||
|
<string name="you_don_t_have_an_identity_key_exclamation">You don\'t have an identity key!</string>
|
||||||
|
<string name="you_have_not_yet_defined_a_contact_for_yourself">You have not yet defined a contact for yourself! Select one in the Settings menu.</string>
|
||||||
|
<string name="exported_to_contacts_database">Exported to contacts database!</string>
|
||||||
|
<string name="you_need_to_have_entered_your_passphrase_before_importing_keys">You need to have entered your passphrase before importing keys...</string>
|
||||||
|
<string name="you_need_to_have_entered_your_passphrase_before_managing_keys">You need to have entered your passphrase before managing keys...</string>
|
||||||
|
<string name="you_havent_set_a_passphrase_yet">You haven\'t set a passphrase yet!</string>
|
||||||
|
|
||||||
|
<!-- ConversationItem -->
|
||||||
|
<string name="message_size_d_kb">Message size: %d KB</string>
|
||||||
|
<string name="expires_s">Expires: %s</string>
|
||||||
|
<string name="error_sending_message">Error sending message</string>
|
||||||
|
<string name="sending">Sending...</string>
|
||||||
|
<string name="saving_attachment">Saving Attachment</string>
|
||||||
|
<string name="saving_attachment_to_sd_card">Saving attachment to SD card...</string>
|
||||||
|
<string name="save_to_sd_card">Save to SD Card?</string>
|
||||||
|
<string name="this_media_has_been_stored_in_an_encrypted_database_warning">This media has been stored in an encrypted database. The version you save to the SD card will no longer be encrypted, would you like to continue?</string>
|
||||||
|
<string name="error_while_saving_attachment_to_sd_card">Error while saving attachment to SD card!</string>
|
||||||
|
<string name="success_exclamation">Success!</string>
|
||||||
|
<string name="unable_to_write_to_sd_card_exclamation">Unable to write to SD Card!</string>
|
||||||
|
<string name="view_secure_media_question">View secure media?</string>
|
||||||
|
<string name="this_media_has_been_stored_in_an_encrypted_database_external_viewer_warning">This media has been stored in an encrypted database. Unfortunately, to view it with an external content viewer currently requires the data to be temporarily decrypted and written to disk. Are you sure that you would like to do this?</string>
|
||||||
|
<string name="key_exchange_message2">Key exchange message</string>
|
||||||
|
<string name="received_and_processed_key_exchange_message">Received and processed key exchange message.</string>
|
||||||
|
<string name="error_received_stale_key_exchange_message">Error, received stale key exchange message.</string>
|
||||||
|
<string name="received_key_exchange_message_click_to_process">Received key exchange message, click to process</string>
|
||||||
|
|
||||||
|
<!-- ConversationActivity -->
|
||||||
|
<string name="initiate_secure_session_question">Initiate Secure Session?</string>
|
||||||
|
<string name="initiate_secure_session_with_s_question">Initiate secure session with %s?</string>
|
||||||
|
<string name="abort_secure_session_confirmation">Abort Secure Session Confirmation</string>
|
||||||
|
<string name="are_you_sure_that_you_want_to_abort_this_secure_session_question">Are you sure that you want to abort this secure session?</string>
|
||||||
|
<string name="delete_thread_confirmation">Delete Thread Confirmation</string>
|
||||||
|
<string name="are_you_sure_that_you_want_to_permanently_delete_this_conversation_question">Are you sure that you want to permanently delete this conversation?</string>
|
||||||
|
<string name="add_attachment">Add attachment</string>
|
||||||
|
<string name="compose_message">Compose Message</string>
|
||||||
|
<string name="sorry_there_was_an_error_setting_your_attachment">Sorry, there was an error setting your attachment.</string>
|
||||||
|
<string name="sorry_the_selected_video_exceeds_message_size_restrictions">Sorry, the selected video exceeds message size restrictions.</string>
|
||||||
|
<string name="sorry_the_selected_audio_exceeds_message_size_restrictions">Sorry, the selected audio exceeds message size restrictions.</string>
|
||||||
|
<string name="recipient_is_not_a_valid_sms_or_email_address_exclamation">Recipient is not a valid SMS or email address!</string>
|
||||||
|
<string name="message_is_empty_exclamation">Message is empty!</string>
|
||||||
|
|
||||||
|
<!-- ConversationFragment -->
|
||||||
|
<string name="message_details">Message details</string>
|
||||||
|
<string name="sender_s_transport_s_sent_received_s">Sender: %1$s\nTransport: %2$s\nSent/Received:%3$s</string>
|
||||||
|
|
||||||
|
<!-- ConversationListAdapter -->
|
||||||
|
<string name="encrypted_message_enter_passphrase">"Encrypted message, enter passphrase... "</string>
|
||||||
|
<string name="key_exchange_message">Key exchange message...</string>
|
||||||
|
|
||||||
|
<!-- ConversationListFragment -->
|
||||||
|
<string name="delete_threads_question">Delete threads?</string>
|
||||||
|
<string name="are_you_sure_you_wish_to_delete_all_selected_conversation_threads">Are you sure you wish to delete ALL selected conversation threads?</string>
|
||||||
|
<string name="delete">Delete</string>
|
||||||
|
<string name="cancel">Cancel</string>
|
||||||
|
|
||||||
|
<!-- KeyScanningActivity -->
|
||||||
|
<string name="no_scanned_key_found_exclamation">No scanned key found!</string>
|
||||||
|
|
||||||
|
<!-- PassphraseChangeActivity -->
|
||||||
|
<string name="passphrases_dont_match_exclamation">Passphrases Don\'t Match!</string>
|
||||||
|
<string name="incorrect_old_passphrase_exclamation">Incorrect old passphrase!</string>
|
||||||
|
|
||||||
|
<!-- PassphraseCreateActivity -->
|
||||||
|
<string name="generating_keypair">Generating KeyPair</string>
|
||||||
|
<string name="generating_a_local_encryption_keypair">Generating a local encryption keypair...</string>
|
||||||
|
|
||||||
|
<!-- PassphrasePromptActivity -->
|
||||||
|
<string name="invalid_passphrase_exclamation">Invalid Passphrase!</string>
|
||||||
|
|
||||||
|
<!-- ReceiveKeyActivity -->
|
||||||
|
<string name="error_you_have_received_a_corrupted_public_key">ERROR:\n\nYou have received a corrupted public key. This key can not be processed, please re-initiate a secure session.</string>
|
||||||
|
<string name="error_you_have_received_a_public_key_from_an_unsupported_version_of_the_protocol">ERROR:\n\nYou have received a public key from an unsupported version of the protocol. This key can not be processed, please re-initiate a secure session.</string>
|
||||||
|
<string name="this_key_exchange_message_does_not_include_an_identity_signature">This key exchange message does not include an identity signature.</string>
|
||||||
|
<string name="this_key_exchange_message_includes_an_identity_signature_but_you_do_not_yet_trust_it">This key exchange message includes an identity signature, but you do not yet trust it.</string>
|
||||||
|
<string name="this_key_exchange_message_includes_an_identity_signature_which_you_trust_for_s">This key exchange message includes an identity signature which you trust for: %s</string>
|
||||||
|
<string name="this_is_the_key_that_you_sent_to_start_your_current_encrypted_session_with_s">This is the key that you sent to start your current encrypted session with %s</string>
|
||||||
|
<string name="this_is_the_key_that_you_received_to_start_your_current_encrypted_session_with_s">This is the key that you received to start your current encrypted session with %s</string>
|
||||||
|
<string name="you_have_received_a_key_exchange_message_from_s_warning_you_already_have_an_encrypted_session">You have received a Key Exchange message from %s.\n\nWARNING: You already have an encrypted session with this contact. If you choose to accept this key exchange message, it will destroy your existing session and you will have to re-authenticate. Would you like to complete this key exchange?</string>
|
||||||
|
<string name="you_have_received_a_key_exchange_message_from_s_you_have_previously_initiated">You have received a Key Exchange message from %s. You have previously initiated a session with this contact, and by accepting this key you will complete the key exchange. Would you like to complete this key exchange?</string>
|
||||||
|
<string name="you_have_initiated_a_key_exchange_message_with_s_but_have_not_yet_received_a_reply">You have initiated a Key Exchange message with %s but have not yet received a reply.</string>
|
||||||
|
<string name="you_have_received_a_key_exchange_message_from_s_you_have_no_existing_session">You have received a Key Exchange message from %s. You have no existing session with this contact, would you like to complete this key exchange?</string>
|
||||||
|
|
||||||
|
<!-- ReviewIdentitiesActivity -->
|
||||||
|
<string name="unable_to_view_corrupted_identity_key_exclamation">Unable to view corrupted identity key!</string>
|
||||||
|
|
||||||
|
<!-- SaveIdentityActivity -->
|
||||||
|
<string name="you_must_specify_a_name_for_this_identity_exclamation">You must specify a name for this identity!</string>
|
||||||
|
<string name="identity_name_exists_exclamation">Identity Name Exists!</string>
|
||||||
|
<string name="an_identity_key_with_the_specified_name_already_exists">An identity key with the specified name already exists.</string>
|
||||||
|
<string name="manage_identities">Manage Identities</string>
|
||||||
|
|
||||||
|
<!-- VerifyIdentityActivity -->
|
||||||
|
<string name="mark_identity_verified_question">Mark Identity Verified?</string>
|
||||||
|
<string name="are_you_sure_you_have_validated_the_recipients_identity_fingerprint_and_would_like_to_mark_it_as_verified">Are you sure you have validated the recipients\' identity fingerprint and would like to mark it as verified?</string>
|
||||||
|
<string name="mark_verified">Mark Verified</string>
|
||||||
|
<string name="you_do_not_have_an_identity_key">You do not have an identity key.</string>
|
||||||
|
<string name="recipient_has_no_identity_key">Recipient has no identity key.</string>
|
||||||
|
<string name="recipient_has_no_identity_key_exclamation">Recipient has no identity key!</string>
|
||||||
|
<string name="scan_their_key_to_compare">Scan their key to compare</string>
|
||||||
|
<string name="get_my_key_scanned">Get my key scanned</string>
|
||||||
|
<string name="warning_the_scanned_key_does_not_match_please_check_the_fingerprint_text_carefully">WARNING, the scanned key DOES NOT match! Please check the fingerprint text carefully.</string>
|
||||||
|
<string name="not_verified_exclamation">NOT Verified!</string>
|
||||||
|
<string name="their_key_is_correct_it_is_also_necessary_to_verify_your_key_with_them_as_well">Their key is correct. It is also necessary to verify your key with them as well.</string>
|
||||||
|
<string name="verified_exclamation">Verified!</string>
|
||||||
|
|
||||||
|
<!-- VerifyImportedIdentityActivity -->
|
||||||
|
<string name="you_must_specify_a_name_for_this_contact_exclamation">You must specify a name for this contact!</string>
|
||||||
|
<string name="save_identity_key_question">Save Identity Key?</string>
|
||||||
|
<string name="error_saving_identity_key_exclamation">Error saving identity key!</string>
|
||||||
|
<string name="this_identity_key_or_an_identity_key_with_the_same_name_already_exists_please_edit_your_key_database">This identity key or an identity key with the same name already exists. Please edit your key database.</string>
|
||||||
|
<string name="scan_to_compare">Scan to compare</string>
|
||||||
|
<string name="get_scanned_to_compare">Get scanned to compare</string>
|
||||||
|
<string name="not_verified_exclamation2">NOT Verified!</string>
|
||||||
|
<string name="warning_the_scanned_key_does_not_match_exclamation">WARNING, the scanned key DOES NOT match!</string>
|
||||||
|
<string name="the_scanned_key_matches_exclamation">The scanned key matches!</string>
|
||||||
|
<string name="verified_exclamation2">Verified!</string>
|
||||||
|
<string name="are_you_sure_that_you_would_like_to_mark_this_as_a_valid_identity_key_for_all_future_correspondence_with_s">Are you sure that you would like to mark this as a valid identity key for all future correspondence with %s? You should only do this if you have actually verified the fingerprint.</string>
|
||||||
|
|
||||||
|
<!-- VerifyKeysActivity -->
|
||||||
|
<string name="mark_session_verified_question">Mark Session Verified?</string>
|
||||||
|
<string name="are_you_sure_that_you_have_validated_these_fingerprints_and_would_like_to_mark_this_session_as_verified">Are you sure that you have validated these fingerprints and would like to mark this session as verified?</string>
|
||||||
|
<string name="mark_verified2">Mark Verified</string>
|
||||||
|
<string name="get_my_fingerprint_scanned">Get my fingerprint scanned</string>
|
||||||
|
<string name="scan_their_fingerprint">Scan their fingerprint</string>
|
||||||
|
<string name="warning_the_scanned_key_does_not_match_please_check_the_fingerprint_text_carefully2">WARNING, the scanned key DOES NOT match! Please check the fingerprint text carefully.</string>
|
||||||
|
<string name="not_verified_exclamation3">NOT Verified!</string>
|
||||||
|
<string name="their_key_is_correct_it_is_also_necessary_to_get_your_fingerprint_scanned_as_well">Their key is correct. It is also necessary to get your fingerprint scanned as well.</string>
|
||||||
|
<string name="verified_exclamation3">Verified!</string>
|
||||||
|
|
||||||
|
<!-- ViewIdentityActivity -->
|
||||||
|
<string name="you_do_not_have_an_identity_key2">You do not have an identity key.</string>
|
||||||
|
<string name="scan_to_compare2">Scan to compare</string>
|
||||||
|
<string name="get_scanned_to_compare2">Get scanned to compare</string>
|
||||||
|
<string name="warning_the_scanned_key_does_not_match_exclamation2">WARNING, the scanned key DOES NOT match!</string>
|
||||||
|
<string name="not_verified_exclamation4">NOT Verified!</string>
|
||||||
|
<string name="the_scanned_key_matches_exclamation2">The scanned key matches!</string>
|
||||||
|
<string name="verified_exclamation4">Verified!</string>
|
||||||
|
|
||||||
|
<!-- KeyExchangeInitiator -->
|
||||||
|
<string name="initiate_despite_existing_request_question">Initiate Despite Existing Request?</string>
|
||||||
|
<string name="youve_already_sent_a_session_initiation_request_to_this_recipient_are_you_sure">You\'ve already sent a session initiation request to this recipient, are you sure you\'d like to send another? This will invalidate the first request.</string>
|
||||||
|
<string name="send">Send</string>
|
||||||
|
|
||||||
|
<!-- MessageDisplayHelper -->
|
||||||
|
<string name="bad_encrypted_message">Bad encrypted message...</string>
|
||||||
|
<string name="decrypting_please_wait">Decrypting, please wait...</string>
|
||||||
|
<string name="message_encrypted_for_non_existing_session">Message encrypted for non-existing session...</string>
|
||||||
|
<string name="decryption_error_local_message_corrupted_mac_doesn_t_match_potential_tampering_question">Decryption error: local message corrupted, MAC doesn\'t match. Potential tampering?</string>
|
||||||
|
|
||||||
|
<!-- MmsDatabase -->
|
||||||
|
<string name="connecting_to_mms_server">Connecting to MMS server...</string>
|
||||||
|
<string name="downloading_mms">Downloading MMS...</string>
|
||||||
|
<string name="mms_download_failed">MMS Download failed!</string>
|
||||||
|
<string name="downloading">Downloading...</string>
|
||||||
|
<string name="anonymous">Anonymous</string>
|
||||||
|
|
||||||
|
<!-- MmsMessageRecord -->
|
||||||
|
<string name="decrypting_mms_please_wait">Decrypting MMS, please wait...</string>
|
||||||
|
<string name="bad_encrypted_mms_message">Bad encrypted MMS message...</string>
|
||||||
|
<string name="mms_message_encrypted_for_non_existing_session">MMS message encrypted for non-existing session...</string>
|
||||||
|
|
||||||
|
<!-- ApplicationMigrationService -->
|
||||||
|
<string name="migrating">Migrating</string>
|
||||||
|
<string name="migrating_system_text_messages">Migrating System Text Messages</string>
|
||||||
|
|
||||||
|
<!-- KeyCachingService -->
|
||||||
|
<string name="textsecure_passphrase_cached">TextSecure Passphrase Cached</string>
|
||||||
|
<string name="textsecure_cached">TextSecure Cached</string>
|
||||||
|
|
||||||
|
<!-- MessageNotifier -->
|
||||||
|
<string name="_d_new_messages">(%d) New messages</string>
|
||||||
|
<string name="_d_new_messages_most_recent_from_s">(%1$d) New messages, most recent from: %2$s</string>
|
||||||
|
<string name="most_recent_from_s">Most recent from: %s</string>
|
||||||
|
|
||||||
|
<!-- auto_initiate_activity -->
|
||||||
|
<string name="you_have_received_a_message_from_someone_who_supports_textsecure_encrypted_sessions_would_you_like_to_initiate_a_key_exchange_so_you_can_communicate_securely">You have received a message from someone who supports TextSecure encrypted sessions. Would you like to initiate a key exchange so you can communicate securely?</string>
|
||||||
|
<string name="initiate_exchange">Initiate Exchange</string>
|
||||||
|
|
||||||
|
<!-- change_passphrase_activity -->
|
||||||
|
<string name="old_passphrase">Old passphrase:</string>
|
||||||
|
<string name="new_passphrase">New passphrase:</string>
|
||||||
|
<string name="repeat_new_passphrase">Repeat new passphrase:</string>
|
||||||
|
|
||||||
|
<!-- contact_selection_group_activity -->
|
||||||
|
<!-- contact_selection_list_activity -->
|
||||||
|
<string name="no_contacts">No contacts.</string>
|
||||||
|
|
||||||
|
<!-- contact_selection_recent_activity -->
|
||||||
|
<string name="no_recent_calls">No recent calls.</string>
|
||||||
|
|
||||||
|
<!-- conversation_activity -->
|
||||||
|
<string name="type_message">Type message</string>
|
||||||
|
<string name="send2">Send</string>
|
||||||
|
<string name="remove">Remove</string>
|
||||||
|
|
||||||
|
<!-- conversation_fragment_cab -->
|
||||||
|
<string name="batch_selection_mode">Batch Selection Mode</string>
|
||||||
|
|
||||||
|
<!-- create_passphrase_activity -->
|
||||||
|
<string name="please_choose_a_passphrase_that_will_be_used_to_locally_encrypt_your_data_this_should_be_a_strong_passphrase">Please choose a passphrase that will be used to locally encrypt your data. This should be a strong passphrase.</string>
|
||||||
|
<string name="passphrase">Passphrase:</string>
|
||||||
|
<string name="repeat">Repeat:</string>
|
||||||
|
|
||||||
|
<!-- mms_download_view -->
|
||||||
|
<string name="download">Download</string>
|
||||||
|
<string name="downloading">Downloading</string>
|
||||||
|
|
||||||
|
<!-- receive_key_activity -->
|
||||||
|
<string name="session">Session</string>
|
||||||
|
<string name="identities">Identities</string>
|
||||||
|
<string name="complete_exchange">Complete Exchange</string>
|
||||||
|
|
||||||
|
<!-- recipients_panel -->
|
||||||
|
<string name="to">To</string>
|
||||||
|
|
||||||
|
<!-- review_identities -->
|
||||||
|
<string name="you_don_t_currently_have_any_identity_keys_in_your_trust_database">You don\'t currently have any identity keys in your trust database.</string>
|
||||||
|
|
||||||
|
<!-- save_identity_activity -->
|
||||||
|
<string name="identity_name">Identity Name:</string>
|
||||||
|
|
||||||
|
<!-- verify_identity_activity -->
|
||||||
|
<string name="their_identity_they_read">Their identity (they read):</string>
|
||||||
|
<string name="your_identity_you_read">Your identity (you read):</string>
|
||||||
|
|
||||||
|
<!-- verify_import_identity_activity -->
|
||||||
|
<string name="identity_name_n">Identity name:\\n</string>
|
||||||
|
<string name="imported_identity_n">Imported identity:\\n</string>
|
||||||
|
<string name="verified5">Verified!</string>
|
||||||
|
<string name="compare5">Compare</string>
|
||||||
|
|
||||||
|
<!-- verify_keys_activity -->
|
||||||
|
<string name="they_read_this">They read this:</string>
|
||||||
|
<string name="you_read_this">You read this:</string>
|
||||||
|
|
||||||
|
<!-- view_identity_activity -->
|
||||||
|
<string name="identity5">Identity:</string>
|
||||||
|
<string name="qr_code">QR Code</string>
|
||||||
|
|
||||||
|
<!-- AndroidManifest.xml -->
|
||||||
|
|
||||||
|
<string name="create_passphrase">Create Passphrase</string>
|
||||||
|
<string name="enter_passphrase">Enter Passphrase</string>
|
||||||
|
<string name="select_contacts">Select Contacts</string>
|
||||||
|
<string name="textsecure_messaging_detected">TextSecure Messaging Detected</string>
|
||||||
|
<string name="public_identity_key">Public Identity Key</string>
|
||||||
|
<string name="change_passphrase2">Change Passphrase</string>
|
||||||
|
<string name="verify_session">Verify Session</string>
|
||||||
|
<string name="verify_identity">Verify Identity</string>
|
||||||
|
<string name="save_identity">Save Identity</string>
|
||||||
|
<string name="manage_identity_keys2">Manage Identity Keys</string>
|
||||||
|
<string name="complete_key_exchange">Complete Key Exchange</string>
|
||||||
|
<string name="verify_imported_identity">Verify Imported Identity</string>
|
||||||
|
|
||||||
|
<!-- preferences.xml -->
|
||||||
|
|
||||||
|
<string name="use_settings">Use Settings</string>
|
||||||
|
<string name="use_textsecure_for_viewing_and_storing_all_incoming_text_messages">Use TextSecure for viewing and storing all incoming text messages</string>
|
||||||
|
<string name="use_textsecure_for_viewing_and_storing_all_incoming_multimedia_messages">Use TextSecure for viewing and storing all incoming multimedia messages</string>
|
||||||
|
<string name="input_settings">Input Settings</string>
|
||||||
|
<string name="pressing_the_enter_key_will_send_text_messages">Pressing the enter key will send text messages</string>
|
||||||
|
<string name="display_settings">Display Settings</string>
|
||||||
|
<string name="choose_identity">Choose Identity</string>
|
||||||
|
<string name="choose_your_contact_entry_from_the_contacts_list">Choose your contact entry from the contacts list.</string>
|
||||||
|
<string name="encryption_settings">Encryption Settings</string>
|
||||||
|
<string name="change_passphrase">Change Passphrase</string>
|
||||||
|
<string name="change_my_passphrase">Change my passphrase</string>
|
||||||
|
<string name="complete_key_exchanges">Complete Key Exchanges</string>
|
||||||
|
<string name="automatically_complete_key_exchanges_for_new_sessions_or_for_existing_sessions_with_the_same_identity_key">Automatically complete key exchanges for new sessions or for existing sessions with the same identity key</string>
|
||||||
|
<string name="include_a_whitespace_tag_at_the_end_of_every_non_encrypted_message">Include a whitespace tag at the end of every non-encrypted message</string>
|
||||||
|
<string name="include_whitespace_tag">Include whitespace tag</string>
|
||||||
|
<string name="sign_key_exchange_messages_with_identity_key">Sign key exchange messages with identity key</string>
|
||||||
|
<string name="sign_key_exchange">Sign Key Exchange</string>
|
||||||
|
<string name="forget_passphrase_from_memory_after_some_interval">Forget passphrase from memory after some interval</string>
|
||||||
|
<string name="timeout_passphrase">Timeout passphrase</string>
|
||||||
|
<string name="identity_key_settings">Identity Key Settings</string>
|
||||||
|
<string name="view_my_identity_key">View my identity key</string>
|
||||||
|
<string name="export_my_identity_key">Export my identity key</string>
|
||||||
|
<string name="import_contacts_key">Import Contact\'s Key</string>
|
||||||
|
<string name="import_an_identity_key_from_a_contact">Import an identity key from a contact</string>
|
||||||
|
<string name="manage_identity_keys">Manage Identity Keys</string>
|
||||||
|
<string name="manage_configured_identity_keys">Manage configured identity keys</string>
|
||||||
|
<string name="notification_settings">Notification Settings</string>
|
||||||
|
<string name="notifications">Notifications</string>
|
||||||
|
<string name="display_message_notifications_in_status_bar">Display message notifications in status bar</string>
|
||||||
|
<string name="led_color">LED Color</string>
|
||||||
|
<string name="change_notification_led_color">Change notification LED color</string>
|
||||||
|
<string name="select_led_color">Select LED Color</string>
|
||||||
|
<string name="select_ringtone">Select ringtone</string>
|
||||||
|
<string name="vibrate">Vibrate</string>
|
||||||
|
<string name="also_vibrate_when_notified">Also vibrate when notified</string>
|
||||||
|
|
||||||
|
<!-- **************************************** -->
|
||||||
|
<!-- menus -->
|
||||||
|
<!-- **************************************** -->
|
||||||
|
|
||||||
|
<!-- contact_selection_list -->
|
||||||
|
<string name="menu_select_all">Select All</string>
|
||||||
|
<string name="menu_unselect_all">Unselect All</string>
|
||||||
|
|
||||||
|
<!-- contact_selection -->
|
||||||
|
<string name="menu_finished">Finished</string>
|
||||||
|
|
||||||
|
<!-- conversation_button_context -->
|
||||||
|
<string name="menu_send_unencrypted">Send unencrypted</string>
|
||||||
|
|
||||||
|
<!-- conversation_callable -->
|
||||||
|
<string name="menu_call">Call</string>
|
||||||
|
|
||||||
|
<!-- conversation_context -->
|
||||||
|
<string name="menu_message_details">Message details</string>
|
||||||
|
<string name="menu_copy_text">Copy text</string>
|
||||||
|
<string name="menu_delete_message">Delete message</string>
|
||||||
|
<string name="menu_forward_message">Forward message</string>
|
||||||
|
|
||||||
|
<!-- conversation_insecure -->
|
||||||
|
<string name="menu_start_secure_session">Start Secure Session</string>
|
||||||
|
|
||||||
|
<!-- conversation_list_batch -->
|
||||||
|
<string name="menu_delete_selected">Delete Selected</string>
|
||||||
|
<string name="menu_select_all">Select All</string>
|
||||||
|
|
||||||
|
<!-- conversation_list -->
|
||||||
|
<string name="menu_search">Search</string>
|
||||||
|
|
||||||
|
<!-- conversation_secure_verified -->
|
||||||
|
<!-- conversation_secure_unverified -->
|
||||||
|
<string name="menu_security">Security</string>
|
||||||
|
<string name="menu_verify_session">Verify Session</string>
|
||||||
|
<string name="menu_verify_recipient">Verify Recipient</string>
|
||||||
|
<string name="menu_abort_secure_session">Abort Secure Session</string>
|
||||||
|
|
||||||
|
<!-- conversation -->
|
||||||
|
<string name="menu_add_attachment">Add attachment</string>
|
||||||
|
<string name="menu_delete_thread">Delete thread</string>
|
||||||
|
<string name="menu_compare">Compare</string>
|
||||||
|
|
||||||
|
<!-- key_scanning -->
|
||||||
|
<string name="menu_get_scanned_to_compare">Get scanned to compare</string>
|
||||||
|
<string name="menu_scan_to_compare">Scan to compare</string>
|
||||||
|
|
||||||
|
<!-- text_secure_locked -->
|
||||||
|
<string name="menu_unlock">Unlock</string>
|
||||||
|
|
||||||
|
<!-- text_secure_normal -->
|
||||||
|
<string name="menu_new_message">New Message</string>
|
||||||
|
<string name="menu_settings">Settings</string>
|
||||||
|
<string name="menu_import_export">Import/Export</string>
|
||||||
|
<string name="menu_import">Import</string>
|
||||||
|
<string name="menu_export">Export</string>
|
||||||
|
<string name="menu_clear_passphrase">Clear Passphrase</string>
|
||||||
|
|
||||||
|
<!-- verify_keys -->
|
||||||
|
<string name="menu_verified">Verified</string>
|
||||||
|
|
||||||
|
<!-- EOF -->
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -18,59 +18,59 @@
|
|||||||
*/
|
*/
|
||||||
-->
|
-->
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<PreferenceCategory android:title="Use Settings">
|
<PreferenceCategory android:title="@string/use_settings">
|
||||||
<CheckBoxPreference android:defaultValue="true"
|
<CheckBoxPreference android:defaultValue="true"
|
||||||
android:key="pref_all_sms"
|
android:key="pref_all_sms"
|
||||||
android:summary="Use TextSecure for viewing and storing all incoming text messages"
|
android:summary="@string/use_textsecure_for_viewing_and_storing_all_incoming_text_messages"
|
||||||
android:title="Use for all SMS" />
|
android:title="Use for all SMS" />
|
||||||
|
|
||||||
<CheckBoxPreference android:defaultValue="true"
|
<CheckBoxPreference android:defaultValue="true"
|
||||||
android:key="pref_all_mms"
|
android:key="pref_all_mms"
|
||||||
android:summary="Use TextSecure for viewing and storing all incoming multimedia messages"
|
android:summary="@string/use_textsecure_for_viewing_and_storing_all_incoming_multimedia_messages"
|
||||||
android:title="Use for all MMS" />
|
android:title="Use for all MMS" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="Input Settings">
|
<PreferenceCategory android:title="@string/input_settings">
|
||||||
<CheckBoxPreference android:defaultValue="false"
|
<CheckBoxPreference android:defaultValue="false"
|
||||||
android:key="pref_enter_sends"
|
android:key="pref_enter_sends"
|
||||||
android:summary="Pressing the enter key will send text messages"
|
android:summary="@string/pressing_the_enter_key_will_send_text_messages"
|
||||||
android:title="Enter Sends" />
|
android:title="Enter Sends" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="Display Settings">
|
<PreferenceCategory android:title="@string/display_settings">
|
||||||
|
|
||||||
<Preference android:key="pref_choose_identity"
|
<Preference android:key="pref_choose_identity"
|
||||||
android:title="Choose Identity"
|
android:title="@string/choose_identity"
|
||||||
android:summary="Choose your contact entry from the contacts list."/>
|
android:summary="@string/choose_your_contact_entry_from_the_contacts_list"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="Encryption Settings">
|
<PreferenceCategory android:title="@string/encryption_settings">
|
||||||
|
|
||||||
<Preference android:key="pref_change_passphrase"
|
<Preference android:key="pref_change_passphrase"
|
||||||
android:title="Change Passphrase"
|
android:title="@string/change_passphrase"
|
||||||
android:summary="Change my passphrase"/>
|
android:summary="@string/change_my_passphrase"/>
|
||||||
|
|
||||||
<CheckBoxPreference android:defaultValue="true"
|
<CheckBoxPreference android:defaultValue="true"
|
||||||
android:key="pref_auto_complete_key_exchange"
|
android:key="pref_auto_complete_key_exchange"
|
||||||
android:title="Complete Key Exchanges"
|
android:title="@string/complete_key_exchanges"
|
||||||
android:summary="Automatically complete key exchanges for new sessions or for existing sessions with the same identity key" />
|
android:summary="@string/automatically_complete_key_exchanges_for_new_sessions_or_for_existing_sessions_with_the_same_identity_key" />
|
||||||
|
|
||||||
<CheckBoxPreference android:defaultValue="true"
|
<CheckBoxPreference android:defaultValue="true"
|
||||||
android:key="pref_key_tag_whitespace"
|
android:key="pref_key_tag_whitespace"
|
||||||
android:summary="Include a whitespace tag at the end of every non-encrypted message"
|
android:summary="@string/include_a_whitespace_tag_at_the_end_of_every_non_encrypted_message"
|
||||||
android:title="Include whitespace tag" />
|
android:title="@string/include_whitespace_tag" />
|
||||||
|
|
||||||
<CheckBoxPreference android:defaultValue="true"
|
<CheckBoxPreference android:defaultValue="true"
|
||||||
android:key="pref_send_identity_key"
|
android:key="pref_send_identity_key"
|
||||||
android:summary="Sign key exchange messages with identity key"
|
android:summary="@string/sign_key_exchange_messages_with_identity_key"
|
||||||
android:title="Sign Key Exchange" />
|
android:title="@string/sign_key_exchange" />
|
||||||
|
|
||||||
<CheckBoxPreference android:defaultValue="false"
|
<CheckBoxPreference android:defaultValue="false"
|
||||||
android:key="pref_timeout_passphrase"
|
android:key="pref_timeout_passphrase"
|
||||||
android:summary="Forget passphrase from memory after some interval"
|
android:summary="@string/forget_passphrase_from_memory_after_some_interval"
|
||||||
android:title="Timeout passphrase" />
|
android:title="@string/timeout_passphrase" />
|
||||||
|
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.preferences.PassphraseTimeoutPreference
|
<org.thoughtcrime.securesms.preferences.PassphraseTimeoutPreference
|
||||||
@ -83,38 +83,38 @@
|
|||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="Identity Key Settings">
|
<PreferenceCategory android:title="@string/identity_key_settings">
|
||||||
<Preference android:key="pref_view_identity"
|
<Preference android:key="pref_view_identity"
|
||||||
android:title="View My Identity Key"
|
android:title="@string/view_my_identity_key"
|
||||||
android:summary="View my identity key"/>
|
android:summary="@string/view_my_identity_key"/>
|
||||||
|
|
||||||
<Preference android:key="pref_export_identity"
|
<Preference android:key="pref_export_identity"
|
||||||
android:title="Export My Identity Key"
|
android:title="@string/export_my_identity_key"
|
||||||
android:summary="Export my identity key"/>
|
android:summary="@string/export_my_identity_key"/>
|
||||||
|
|
||||||
<Preference android:key="pref_import_identity"
|
<Preference android:key="pref_import_identity"
|
||||||
android:title="Import Contact's Key"
|
android:title="@string/import_contacts_key"
|
||||||
android:summary="Import an identity key from a contact"/>
|
android:summary="@string/import_an_identity_key_from_a_contact"/>
|
||||||
|
|
||||||
<Preference android:key="pref_manage_identity"
|
<Preference android:key="pref_manage_identity"
|
||||||
android:title="Manage Identity Keys"
|
android:title="@string/manage_identity_keys"
|
||||||
android:summary="Manage configured identity keys"/>
|
android:summary="@string/manage_configured_identity_keys"/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="Notification Settings">
|
<PreferenceCategory android:title="@string/notification_settings">
|
||||||
<CheckBoxPreference android:key="pref_key_enable_notifications"
|
<CheckBoxPreference android:key="pref_key_enable_notifications"
|
||||||
android:title="Notifications"
|
android:title="@string/notifications"
|
||||||
android:summary="Display message notifications in status bar"
|
android:summary="@string/display_message_notifications_in_status_bar"
|
||||||
android:defaultValue="true" />
|
android:defaultValue="true" />
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="pref_led_color"
|
android:key="pref_led_color"
|
||||||
android:defaultValue="green"
|
android:defaultValue="green"
|
||||||
android:title="LED Color"
|
android:title="@string/led_color"
|
||||||
android:dependency="pref_key_enable_notifications"
|
android:dependency="pref_key_enable_notifications"
|
||||||
android:summary="Change notification LED color"
|
android:summary="@string/change_notification_led_color"
|
||||||
android:entries="@array/pref_led_color_entries"
|
android:entries="@array/pref_led_color_entries"
|
||||||
android:entryValues="@array/pref_led_color_values"
|
android:entryValues="@array/pref_led_color_values"
|
||||||
android:dialogTitle="Select LED Color" />
|
android:dialogTitle="@string/select_led_color" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.preferences.LedBlinkPatternListPreference
|
<org.thoughtcrime.securesms.preferences.LedBlinkPatternListPreference
|
||||||
android:key="pref_led_blink"
|
android:key="pref_led_blink"
|
||||||
@ -130,14 +130,14 @@
|
|||||||
<RingtonePreference android:layout="?android:attr/preferenceLayoutChild"
|
<RingtonePreference android:layout="?android:attr/preferenceLayoutChild"
|
||||||
android:dependency="pref_key_enable_notifications"
|
android:dependency="pref_key_enable_notifications"
|
||||||
android:key="pref_key_ringtone"
|
android:key="pref_key_ringtone"
|
||||||
android:title="Select ringtone"
|
android:title="@string/select_ringtone"
|
||||||
android:ringtoneType="notification"
|
android:ringtoneType="notification"
|
||||||
android:defaultValue="content://settings/system/notification_sound" />
|
android:defaultValue="content://settings/system/notification_sound" />
|
||||||
<CheckBoxPreference android:layout="?android:attr/preferenceLayoutChild"
|
<CheckBoxPreference android:layout="?android:attr/preferenceLayoutChild"
|
||||||
android:dependency="pref_key_enable_notifications"
|
android:dependency="pref_key_enable_notifications"
|
||||||
android:key="pref_key_vibrate"
|
android:key="pref_key_vibrate"
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:title="Vibrate"
|
android:title="@string/vibrate"
|
||||||
android:summary="Also vibrate when notified" />
|
android:summary="@string/also_vibrate_when_notified" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
@ -39,17 +39,16 @@ public class ApplicationExportManager extends Handler implements Runnable {
|
|||||||
|
|
||||||
public void importDatabase() {
|
public void importDatabase() {
|
||||||
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
|
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
|
||||||
alertBuilder.setTitle("Import Database and Settings?");
|
alertBuilder.setTitle(R.string.import_database_and_settings_title);
|
||||||
alertBuilder.setMessage("Import TextSecure database, keys, and settings from the SD Card?" +
|
alertBuilder.setMessage(R.string.import_database_and_settings_message);
|
||||||
"\n\nWARNING: This will clobber any existing messages, keys, and " +
|
|
||||||
"settings!");
|
|
||||||
alertBuilder.setCancelable(false);
|
alertBuilder.setCancelable(false);
|
||||||
alertBuilder.setPositiveButton("Import", new DialogInterface.OnClickListener() {
|
alertBuilder.setPositiveButton("Import", new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
task = TASK_IMPORT;
|
task = TASK_IMPORT;
|
||||||
progressDialog = new ProgressDialog(context);
|
progressDialog = new ProgressDialog(context);
|
||||||
progressDialog.setTitle("Importing Database and Keys");
|
progressDialog.setTitle(context.getString(R.string.importing_database_and_keys));
|
||||||
progressDialog.setMessage("Importnig your SMS database, keys, and settings...");
|
progressDialog.setMessage(context
|
||||||
|
.getString(R.string.importing_your_sms_database_keys_and_settings));
|
||||||
progressDialog.setCancelable(false);
|
progressDialog.setCancelable(false);
|
||||||
progressDialog.setIndeterminate(true);
|
progressDialog.setIndeterminate(true);
|
||||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||||
@ -70,16 +69,17 @@ public class ApplicationExportManager extends Handler implements Runnable {
|
|||||||
public void exportDatabase() {
|
public void exportDatabase() {
|
||||||
Log.w("ApplicationExportManager", "Context: " + context);
|
Log.w("ApplicationExportManager", "Context: " + context);
|
||||||
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
|
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
|
||||||
alertBuilder.setTitle("Export Database?");
|
alertBuilder.setTitle(R.string.export_database_question);
|
||||||
alertBuilder.setMessage("Export TextSecure database, keys, and settings to the SD Card?");
|
alertBuilder.setMessage(R.string.export_textsecure_database_keys_and_settings_prompt);
|
||||||
alertBuilder.setCancelable(false);
|
alertBuilder.setCancelable(false);
|
||||||
|
|
||||||
alertBuilder.setPositiveButton("Export", new DialogInterface.OnClickListener() {
|
alertBuilder.setPositiveButton("Export", new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
task = TASK_EXPORT;
|
task = TASK_EXPORT;
|
||||||
progressDialog = new ProgressDialog(context);
|
progressDialog = new ProgressDialog(context);
|
||||||
progressDialog.setTitle("Exporting Database and Keys");
|
progressDialog.setTitle(context.getString(R.string.exporting_database_and_keys));
|
||||||
progressDialog.setMessage("Exporting your SMS database, keys, and settings...");
|
progressDialog.setMessage(context
|
||||||
|
.getString(R.string.exporting_your_sms_database_keys_and_settings));
|
||||||
progressDialog.setCancelable(false);
|
progressDialog.setCancelable(false);
|
||||||
progressDialog.setIndeterminate(true);
|
progressDialog.setIndeterminate(true);
|
||||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||||
@ -117,18 +117,18 @@ public class ApplicationExportManager extends Handler implements Runnable {
|
|||||||
public void handleMessage(Message message) {
|
public void handleMessage(Message message) {
|
||||||
switch (message.what) {
|
switch (message.what) {
|
||||||
case ERROR_NO_SD:
|
case ERROR_NO_SD:
|
||||||
Toast.makeText(context, "No SD card found!", Toast.LENGTH_LONG).show();
|
Toast.makeText(context, R.string.no_sd_card_found_exclamation, Toast.LENGTH_LONG).show();
|
||||||
break;
|
break;
|
||||||
case ERROR_IO:
|
case ERROR_IO:
|
||||||
Toast.makeText(context, "Error exporting to SD!", Toast.LENGTH_LONG).show();
|
Toast.makeText(context, R.string.error_exporting_to_sd_exclamation, Toast.LENGTH_LONG).show();
|
||||||
break;
|
break;
|
||||||
case COMPLETE:
|
case COMPLETE:
|
||||||
switch (task) {
|
switch (task) {
|
||||||
case TASK_IMPORT:
|
case TASK_IMPORT:
|
||||||
Toast.makeText(context, "Import Successful!", Toast.LENGTH_LONG).show();
|
Toast.makeText(context, R.string.import_successful_exclamation, Toast.LENGTH_LONG).show();
|
||||||
break;
|
break;
|
||||||
case TASK_EXPORT:
|
case TASK_EXPORT:
|
||||||
Toast.makeText(context, "Export Successful!", Toast.LENGTH_LONG).show();
|
Toast.makeText(context, R.string.export_successful_exclamation, Toast.LENGTH_LONG).show();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -35,8 +35,8 @@ public class ApplicationMigrationManager extends Handler {
|
|||||||
|
|
||||||
private void displayMigrationProgress() {
|
private void displayMigrationProgress() {
|
||||||
progressDialog = new ProgressDialog(context);
|
progressDialog = new ProgressDialog(context);
|
||||||
progressDialog.setTitle("Migrating Database");
|
progressDialog.setTitle(context.getString(R.string.migrating_database));
|
||||||
progressDialog.setMessage("Migrating text message database...");
|
progressDialog.setMessage(context.getString(R.string.migrating_text_message_database));
|
||||||
progressDialog.setMax(10000);
|
progressDialog.setMax(10000);
|
||||||
progressDialog.setCancelable(false);
|
progressDialog.setCancelable(false);
|
||||||
progressDialog.setIndeterminate(false);
|
progressDialog.setIndeterminate(false);
|
||||||
@ -51,14 +51,11 @@ public class ApplicationMigrationManager extends Handler {
|
|||||||
|
|
||||||
private void displayMigrationPrompt() {
|
private void displayMigrationPrompt() {
|
||||||
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
|
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
|
||||||
alertBuilder.setTitle("Copy System Text Message Database?");
|
alertBuilder.setTitle(R.string.copy_system_text_message_database_question);
|
||||||
alertBuilder.setMessage("TextSecure uses an encrypted database that is " +
|
alertBuilder.setMessage(R.string.copy_system_text_message_database_explanation);
|
||||||
"separate from the default system database. Would you like to " +
|
|
||||||
"copy your existing text messages into TextSecure's encrypted " +
|
|
||||||
"database? Your default system database will be unaffected.");
|
|
||||||
alertBuilder.setCancelable(false);
|
alertBuilder.setCancelable(false);
|
||||||
|
|
||||||
alertBuilder.setPositiveButton("Copy", new DialogInterface.OnClickListener() {
|
alertBuilder.setPositiveButton(R.string.copy, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
displayMigrationProgress();
|
displayMigrationProgress();
|
||||||
Intent intent = new Intent(context, ApplicationMigrationService.class);
|
Intent intent = new Intent(context, ApplicationMigrationService.class);
|
||||||
@ -68,7 +65,7 @@ public class ApplicationMigrationManager extends Handler {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
alertBuilder.setNegativeButton("Don't copy", new DialogInterface.OnClickListener() {
|
alertBuilder.setNegativeButton(R.string.dont_copy, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE)
|
context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE)
|
||||||
.edit()
|
.edit()
|
||||||
|
@ -138,7 +138,10 @@ public class ApplicationPreferencesActivity extends SherlockPreferenceActivity {
|
|||||||
String contactName = ContactAccessor.getInstance().getNameFromContact(this, uri);
|
String contactName = ContactAccessor.getInstance().getNameFromContact(this, uri);
|
||||||
|
|
||||||
if (identityKey == null) {
|
if (identityKey == null) {
|
||||||
Dialogs.displayAlert(this, "Not found!", "No valid identity key was found in the specified contact.", android.R.drawable.ic_dialog_alert);
|
Dialogs.displayAlert(this,
|
||||||
|
getString(R.string.not_found_exclamation),
|
||||||
|
getString(R.string.no_valid_identity_key_was_found_in_the_specified_contact),
|
||||||
|
android.R.drawable.ic_dialog_alert);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,13 +176,15 @@ public class ApplicationPreferencesActivity extends SherlockPreferenceActivity {
|
|||||||
.getString(IDENTITY_PREF, null);
|
.getString(IDENTITY_PREF, null);
|
||||||
|
|
||||||
if (!IdentityKeyUtil.hasIdentityKey(ApplicationPreferencesActivity.this)) {
|
if (!IdentityKeyUtil.hasIdentityKey(ApplicationPreferencesActivity.this)) {
|
||||||
Toast.makeText(ApplicationPreferencesActivity.this, "You don't have an identity key!", Toast.LENGTH_LONG).show();
|
Toast.makeText(ApplicationPreferencesActivity.this,
|
||||||
|
R.string.you_don_t_have_an_identity_key_exclamation,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contactUri == null) {
|
if (contactUri == null) {
|
||||||
Toast.makeText(ApplicationPreferencesActivity.this,
|
Toast.makeText(ApplicationPreferencesActivity.this,
|
||||||
"You have not yet defined a contact for yourself! Select one in the Settings menu.",
|
R.string.you_have_not_yet_defined_a_contact_for_yourself,
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -187,7 +192,9 @@ public class ApplicationPreferencesActivity extends SherlockPreferenceActivity {
|
|||||||
ContactAccessor.getInstance().insertIdentityKey(ApplicationPreferencesActivity.this, Uri.parse(contactUri),
|
ContactAccessor.getInstance().insertIdentityKey(ApplicationPreferencesActivity.this, Uri.parse(contactUri),
|
||||||
IdentityKeyUtil.getIdentityKey(ApplicationPreferencesActivity.this));
|
IdentityKeyUtil.getIdentityKey(ApplicationPreferencesActivity.this));
|
||||||
|
|
||||||
Toast.makeText(ApplicationPreferencesActivity.this, "Exported to contacts database!", Toast.LENGTH_LONG).show();
|
Toast.makeText(ApplicationPreferencesActivity.this,
|
||||||
|
R.string.exported_to_contacts_database,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -202,7 +209,7 @@ public class ApplicationPreferencesActivity extends SherlockPreferenceActivity {
|
|||||||
startActivityForResult(importIntent, IMPORT_IDENTITY_ID);
|
startActivityForResult(importIntent, IMPORT_IDENTITY_ID);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(ApplicationPreferencesActivity.this,
|
Toast.makeText(ApplicationPreferencesActivity.this,
|
||||||
"You need to have entered your passphrase before importing keys...",
|
R.string.you_need_to_have_entered_your_passphrase_before_importing_keys,
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +227,7 @@ public class ApplicationPreferencesActivity extends SherlockPreferenceActivity {
|
|||||||
startActivity(manageIntent);
|
startActivity(manageIntent);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(ApplicationPreferencesActivity.this,
|
Toast.makeText(ApplicationPreferencesActivity.this,
|
||||||
"You need to have entered your passphrase before managing keys...",
|
R.string.you_need_to_have_entered_your_passphrase_before_managing_keys,
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +242,9 @@ public class ApplicationPreferencesActivity extends SherlockPreferenceActivity {
|
|||||||
if (settings.getBoolean("passphrase_initialized", false)) {
|
if (settings.getBoolean("passphrase_initialized", false)) {
|
||||||
startActivity(new Intent(ApplicationPreferencesActivity.this, PassphraseChangeActivity.class));
|
startActivity(new Intent(ApplicationPreferencesActivity.this, PassphraseChangeActivity.class));
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(ApplicationPreferencesActivity.this, "You haven't set a passphrase yet!", Toast.LENGTH_LONG).show();
|
Toast.makeText(ApplicationPreferencesActivity.this,
|
||||||
|
R.string.you_havent_set_a_passphrase_yet,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -260,10 +260,10 @@ public class ConversationActivity extends SherlockFragmentActivity
|
|||||||
final Recipient recipient = getRecipients().getPrimaryRecipient();
|
final Recipient recipient = getRecipients().getPrimaryRecipient();
|
||||||
String recipientName = (recipient.getName() == null ? recipient.getNumber() : recipient.getName());
|
String recipientName = (recipient.getName() == null ? recipient.getNumber() : recipient.getName());
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setTitle("Initiate Secure Session?");
|
builder.setTitle(R.string.initiate_secure_session_question);
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_info);
|
builder.setIcon(android.R.drawable.ic_dialog_info);
|
||||||
builder.setCancelable(true);
|
builder.setCancelable(true);
|
||||||
builder.setMessage("Initiate secure session with " + recipientName + "?");
|
builder.setMessage(String.format(getString(R.string.initiate_secure_session_with_s_question), recipientName));
|
||||||
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
@ -278,10 +278,10 @@ public class ConversationActivity extends SherlockFragmentActivity
|
|||||||
|
|
||||||
private void handleAbortSecureSession() {
|
private void handleAbortSecureSession() {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setTitle("Abort Secure Session Confirmation");
|
builder.setTitle(R.string.abort_secure_session_confirmation);
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||||
builder.setCancelable(true);
|
builder.setCancelable(true);
|
||||||
builder.setMessage("Are you sure that you want to abort this secure session?");
|
builder.setMessage(R.string.are_you_sure_that_you_want_to_abort_this_secure_session_question);
|
||||||
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
@ -306,10 +306,10 @@ public class ConversationActivity extends SherlockFragmentActivity
|
|||||||
|
|
||||||
private void handleDeleteThread() {
|
private void handleDeleteThread() {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setTitle("Delete Thread Confirmation");
|
builder.setTitle(R.string.delete_thread_confirmation);
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||||
builder.setCancelable(true);
|
builder.setCancelable(true);
|
||||||
builder.setMessage("Are you sure that you want to permanently delete this conversation?");
|
builder.setMessage(R.string.are_you_sure_that_you_want_to_permanently_delete_this_conversation_question);
|
||||||
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
@ -327,7 +327,7 @@ public class ConversationActivity extends SherlockFragmentActivity
|
|||||||
private void handleAddAttachment() {
|
private void handleAddAttachment() {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setIcon(R.drawable.ic_dialog_attach);
|
builder.setIcon(R.drawable.ic_dialog_attach);
|
||||||
builder.setTitle("Add attachment");
|
builder.setTitle(R.string.add_attachment);
|
||||||
builder.setAdapter(attachmentAdapter, new AttachmentTypeListener());
|
builder.setAdapter(attachmentAdapter, new AttachmentTypeListener());
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
@ -356,7 +356,7 @@ public class ConversationActivity extends SherlockFragmentActivity
|
|||||||
subtitle = getRecipients().getPrimaryRecipient().getNumber();
|
subtitle = getRecipients().getPrimaryRecipient().getNumber();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
title = "Compose Message";
|
title = getString(R.string.compose_message);
|
||||||
subtitle = "";
|
subtitle = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,7 +473,7 @@ public class ConversationActivity extends SherlockFragmentActivity
|
|||||||
attachmentManager.setImage(imageUri);
|
attachmentManager.setImage(imageUri);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
attachmentManager.clear();
|
attachmentManager.clear();
|
||||||
Toast.makeText(this, "Sorry, there was an error setting your attachment.",
|
Toast.makeText(this, R.string.sorry_there_was_an_error_setting_your_attachment,
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
Log.w("ComposeMessageActivity", e);
|
Log.w("ComposeMessageActivity", e);
|
||||||
}
|
}
|
||||||
@ -484,12 +484,12 @@ public class ConversationActivity extends SherlockFragmentActivity
|
|||||||
attachmentManager.setVideo(videoUri);
|
attachmentManager.setVideo(videoUri);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
attachmentManager.clear();
|
attachmentManager.clear();
|
||||||
Toast.makeText(this, "Sorry, there was an error setting your attachment.",
|
Toast.makeText(this, R.string.sorry_there_was_an_error_setting_your_attachment,
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
Log.w("ComposeMessageActivity", e);
|
Log.w("ComposeMessageActivity", e);
|
||||||
} catch (MediaTooLargeException e) {
|
} catch (MediaTooLargeException e) {
|
||||||
attachmentManager.clear();
|
attachmentManager.clear();
|
||||||
Toast.makeText(this, "Sorry, the selected video exceeds message size restrictions.",
|
Toast.makeText(this, R.string.sorry_the_selected_video_exceeds_message_size_restrictions,
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
Log.w("ComposeMessageActivity", e);
|
Log.w("ComposeMessageActivity", e);
|
||||||
}
|
}
|
||||||
@ -500,12 +500,12 @@ public class ConversationActivity extends SherlockFragmentActivity
|
|||||||
attachmentManager.setAudio(audioUri);
|
attachmentManager.setAudio(audioUri);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
attachmentManager.clear();
|
attachmentManager.clear();
|
||||||
Toast.makeText(this, "Sorry, there was an error setting your attachment.",
|
Toast.makeText(this, R.string.sorry_there_was_an_error_setting_your_attachment,
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
Log.w("ComposeMessageActivity", e);
|
Log.w("ComposeMessageActivity", e);
|
||||||
} catch (MediaTooLargeException e) {
|
} catch (MediaTooLargeException e) {
|
||||||
attachmentManager.clear();
|
attachmentManager.clear();
|
||||||
Toast.makeText(this, "Sorry, the selected audio exceeds message size restrictions.",
|
Toast.makeText(this, R.string.sorry_the_selected_audio_exceeds_message_size_restrictions,
|
||||||
Toast.LENGTH_LONG).show();
|
Toast.LENGTH_LONG).show();
|
||||||
Log.w("ComposeMessageActivity", e);
|
Log.w("ComposeMessageActivity", e);
|
||||||
}
|
}
|
||||||
@ -546,7 +546,7 @@ public class ConversationActivity extends SherlockFragmentActivity
|
|||||||
String rawText = composeText.getText().toString();
|
String rawText = composeText.getText().toString();
|
||||||
|
|
||||||
if (rawText.length() < 1 && !attachmentManager.isAttachmentPresent())
|
if (rawText.length() < 1 && !attachmentManager.isAttachmentPresent())
|
||||||
throw new InvalidMessageException("Message is empty!");
|
throw new InvalidMessageException(getString(R.string.message_is_empty_exclamation));
|
||||||
|
|
||||||
if (!sendEncrypted && sp.getBoolean(ApplicationPreferencesActivity.WHITESPACE_PREF, true) && rawText.length() <= 145)
|
if (!sendEncrypted && sp.getBoolean(ApplicationPreferencesActivity.WHITESPACE_PREF, true) && rawText.length() <= 145)
|
||||||
rawText = rawText + " ";
|
rawText = rawText + " ";
|
||||||
@ -600,10 +600,13 @@ public class ConversationActivity extends SherlockFragmentActivity
|
|||||||
sendComplete(recipients, allocatedThreadId);
|
sendComplete(recipients, allocatedThreadId);
|
||||||
MessageNotifier.updateNotification(ConversationActivity.this, false);
|
MessageNotifier.updateNotification(ConversationActivity.this, false);
|
||||||
} catch (RecipientFormattingException ex) {
|
} catch (RecipientFormattingException ex) {
|
||||||
Toast.makeText(ConversationActivity.this, "Recipient is not a valid SMS or email address!", Toast.LENGTH_LONG).show();
|
Toast.makeText(ConversationActivity.this,
|
||||||
|
R.string.recipient_is_not_a_valid_sms_or_email_address_exclamation,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
Log.w("compose", ex);
|
Log.w("compose", ex);
|
||||||
} catch (InvalidMessageException ex) {
|
} catch (InvalidMessageException ex) {
|
||||||
Toast.makeText(ConversationActivity.this, "Message is empty!", Toast.LENGTH_SHORT).show();
|
Toast.makeText(ConversationActivity.this, R.string.message_is_empty_exclamation,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
Log.w("compose", ex);
|
Log.w("compose", ex);
|
||||||
} catch (MmsException e) {
|
} catch (MmsException e) {
|
||||||
Log.w("ComposeMessageActivity", e);
|
Log.w("ComposeMessageActivity", e);
|
||||||
|
@ -187,7 +187,7 @@ public class ConversationAdapter extends CursorAdapter {
|
|||||||
if (body == null)
|
if (body == null)
|
||||||
message.setBody("");
|
message.setBody("");
|
||||||
else
|
else
|
||||||
MessageDisplayHelper.setDecryptedMessageBody(body, message, masterCipher);
|
MessageDisplayHelper.setDecryptedMessageBody(context, body, message, masterCipher);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -130,12 +130,13 @@ public class ConversationFragment extends SherlockListFragment
|
|||||||
|
|
||||||
SimpleDateFormat dateFormatter = new SimpleDateFormat("EEE MMM d, yyyy 'at' hh:mm:ss a zzz");
|
SimpleDateFormat dateFormatter = new SimpleDateFormat("EEE MMM d, yyyy 'at' hh:mm:ss a zzz");
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
builder.setTitle("Message Details");
|
builder.setTitle(R.string.message_details);
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_info);
|
builder.setIcon(android.R.drawable.ic_dialog_info);
|
||||||
builder.setCancelable(false);
|
builder.setCancelable(false);
|
||||||
builder.setMessage("Sender: " + sender + "\nTransport: " + transport.toUpperCase() +
|
builder.setMessage(String.format(getSherlockActivity().getString(R.string.sender_s_transport_s_sent_received_s),
|
||||||
"\nSent/Received: " + dateFormatter.format(new Date(date)));
|
sender, transport.toUpperCase(),
|
||||||
builder.setPositiveButton("Ok", null);
|
dateFormatter.format(new Date(date))));
|
||||||
|
builder.setPositiveButton(android.R.string.ok, null);
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,8 +149,12 @@ public class ConversationItem extends LinearLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setMmsNotificationAttributes(MmsMessageRecord messageRecord) {
|
private void setMmsNotificationAttributes(MmsMessageRecord messageRecord) {
|
||||||
String messageSize = "Message size: " + messageRecord.getMessageSize() + " KB";
|
String messageSize = String.format(getContext().getString(R.string.message_size_d_kb),
|
||||||
String expires = "Expires: " + DateUtils.getRelativeTimeSpanString(getContext(), messageRecord.getExpiration(), false);
|
messageRecord.getMessageSize());
|
||||||
|
String expires = String.format(getContext().getString(R.string.expires_s),
|
||||||
|
DateUtils.getRelativeTimeSpanString(getContext(),
|
||||||
|
messageRecord.getExpiration(),
|
||||||
|
false));
|
||||||
|
|
||||||
dateText.setText(messageSize + "\n" + expires);
|
dateText.setText(messageSize + "\n" + expires);
|
||||||
|
|
||||||
@ -158,7 +162,7 @@ public class ConversationItem extends LinearLayout {
|
|||||||
mmsDownloadButton.setVisibility(View.VISIBLE);
|
mmsDownloadButton.setVisibility(View.VISIBLE);
|
||||||
mmsDownloadingLabel.setVisibility(View.GONE);
|
mmsDownloadingLabel.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
mmsDownloadingLabel.setText(MmsDatabase.Types.getLabelForStatus(messageRecord.getStatus()));
|
mmsDownloadingLabel.setText(MmsDatabase.Types.getLabelForStatus(context, messageRecord.getStatus()));
|
||||||
mmsDownloadButton.setVisibility(View.GONE);
|
mmsDownloadButton.setVisibility(View.GONE);
|
||||||
mmsDownloadingLabel.setVisibility(View.VISIBLE);
|
mmsDownloadingLabel.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
@ -207,10 +211,10 @@ public class ConversationItem extends LinearLayout {
|
|||||||
private void setBodyText(MessageRecord messageRecord) {
|
private void setBodyText(MessageRecord messageRecord) {
|
||||||
String body = messageRecord.getBody();
|
String body = messageRecord.getBody();
|
||||||
|
|
||||||
if (messageRecord.isKeyExchange() && messageRecord.isOutgoing()) body = "\nKey exchange message";
|
if (messageRecord.isKeyExchange() && messageRecord.isOutgoing()) body = "\n" + getContext().getString(R.string.key_exchange_message2);
|
||||||
else if (messageRecord.isProcessedKeyExchange() && !messageRecord.isOutgoing()) body = "\nReceived and processed key exchange message.";
|
else if (messageRecord.isProcessedKeyExchange() && !messageRecord.isOutgoing()) body = "\n" + getContext().getString(R.string.received_and_processed_key_exchange_message);
|
||||||
else if (messageRecord.isStaleKeyExchange()) body = "\nError, received stale key exchange message.";
|
else if (messageRecord.isStaleKeyExchange()) body = "\n" + getContext().getString(R.string.error_received_stale_key_exchange_message);
|
||||||
else if (messageRecord.isKeyExchange() && !messageRecord.isOutgoing()) body = "\nReceived key exchange message, click to process";
|
else if (messageRecord.isKeyExchange() && !messageRecord.isOutgoing()) body = "\n" + getContext().getString(R.string.received_key_exchange_message_click_to_process);
|
||||||
|
|
||||||
bodyText.setText(body, TextView.BufferType.SPANNABLE);
|
bodyText.setText(body, TextView.BufferType.SPANNABLE);
|
||||||
|
|
||||||
@ -274,8 +278,8 @@ public class ConversationItem extends LinearLayout {
|
|||||||
mmsDownloadButton.setVisibility(View.GONE);
|
mmsDownloadButton.setVisibility(View.GONE);
|
||||||
mmsDownloadingLabel.setVisibility(View.GONE);
|
mmsDownloadingLabel.setVisibility(View.GONE);
|
||||||
|
|
||||||
if (messageRecord.isFailed()) dateText.setText("Error sending message");
|
if (messageRecord.isFailed()) dateText.setText(R.string.error_sending_message);
|
||||||
else if (messageRecord.isPending()) dateText.setText("Sending...");
|
else if (messageRecord.isPending()) dateText.setText(R.string.sending);
|
||||||
else dateText.setText(DateUtils.getRelativeTimeSpanString(getContext(),
|
else dateText.setText(DateUtils.getRelativeTimeSpanString(getContext(),
|
||||||
messageRecord.getDate(),
|
messageRecord.getDate(),
|
||||||
false));
|
false));
|
||||||
@ -358,8 +362,8 @@ public class ConversationItem extends LinearLayout {
|
|||||||
|
|
||||||
private void saveToSdCard() {
|
private void saveToSdCard() {
|
||||||
progressDialog = new ProgressDialog(context);
|
progressDialog = new ProgressDialog(context);
|
||||||
progressDialog.setTitle("Saving Attachment");
|
progressDialog.setTitle(context.getString(R.string.saving_attachment));
|
||||||
progressDialog.setMessage("Saving attachment to SD card...");
|
progressDialog.setMessage(context.getString(R.string.saving_attachment_to_sd_card));
|
||||||
progressDialog.setCancelable(false);
|
progressDialog.setCancelable(false);
|
||||||
progressDialog.setIndeterminate(true);
|
progressDialog.setIndeterminate(true);
|
||||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||||
@ -369,10 +373,10 @@ public class ConversationItem extends LinearLayout {
|
|||||||
|
|
||||||
public boolean onLongClick(View v) {
|
public boolean onLongClick(View v) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
builder.setTitle("Save to SD Card?");
|
builder.setTitle(R.string.save_to_sd_card);
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||||
builder.setCancelable(true);
|
builder.setCancelable(true);
|
||||||
builder.setMessage("This media has been stored in an encrypted database. The version you save to the SD card will no longer be encrypted, would you like to continue?");
|
builder.setMessage(R.string.this_media_has_been_stored_in_an_encrypted_database_warning);
|
||||||
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
saveToSdCard();
|
saveToSdCard();
|
||||||
@ -388,13 +392,16 @@ public class ConversationItem extends LinearLayout {
|
|||||||
public void handleMessage(Message message) {
|
public void handleMessage(Message message) {
|
||||||
switch (message.what) {
|
switch (message.what) {
|
||||||
case FAILURE:
|
case FAILURE:
|
||||||
Toast.makeText(context, "Error while saving attachment to SD card!", Toast.LENGTH_LONG);
|
Toast.makeText(context, R.string.error_while_saving_attachment_to_sd_card,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
break;
|
break;
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
Toast.makeText(context, "Success!", Toast.LENGTH_LONG);
|
Toast.makeText(context, R.string.success_exclamation,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
break;
|
break;
|
||||||
case WRITE_ACCESS_FAILURE:
|
case WRITE_ACCESS_FAILURE:
|
||||||
Toast.makeText(context, "Unable to write to SD Card!", Toast.LENGTH_LONG);
|
Toast.makeText(context, R.string.unable_to_write_to_sd_card_exclamation,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,10 +435,10 @@ public class ConversationItem extends LinearLayout {
|
|||||||
|
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
builder.setTitle("View secure media?");
|
builder.setTitle(R.string.view_secure_media_question);
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||||
builder.setCancelable(true);
|
builder.setCancelable(true);
|
||||||
builder.setMessage("This media has been stored in an encrypted database. Unfortunately, to view it with an external content viewer currently requires the data to be temporarily decrypted and written to disk. Are you sure that you would like to do this?");
|
builder.setMessage(R.string.this_media_has_been_stored_in_an_encrypted_database_external_viewer_warning);
|
||||||
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
fireIntent();
|
fireIntent();
|
||||||
|
@ -78,10 +78,10 @@ public class ConversationListAdapter extends CursorAdapter {
|
|||||||
if (body == null) body = "(No subject)";
|
if (body == null) body = "(No subject)";
|
||||||
|
|
||||||
if (body.startsWith(Prefix.SYMMETRIC_ENCRYPT) || body.startsWith(Prefix.ASYMMETRIC_ENCRYPT) || body.startsWith(Prefix.ASYMMETRIC_LOCAL_ENCRYPT)) {
|
if (body.startsWith(Prefix.SYMMETRIC_ENCRYPT) || body.startsWith(Prefix.ASYMMETRIC_ENCRYPT) || body.startsWith(Prefix.ASYMMETRIC_LOCAL_ENCRYPT)) {
|
||||||
message.setBody("Encrypted message, enter passphrase... ");
|
message.setBody(context.getString(R.string.encrypted_message_enter_passphrase));
|
||||||
message.setEmphasis(true);
|
message.setEmphasis(true);
|
||||||
} else if (body.startsWith(Prefix.KEY_EXCHANGE)) {
|
} else if (body.startsWith(Prefix.KEY_EXCHANGE)) {
|
||||||
message.setBody("Key exchange message...");
|
message.setBody(context.getString(R.string.key_exchange_message));
|
||||||
message.setEmphasis(true);
|
message.setEmphasis(true);
|
||||||
} else {
|
} else {
|
||||||
message.setBody(body);
|
message.setBody(body);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms;
|
package org.thoughtcrime.securesms;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@ -102,7 +103,8 @@ public class ConversationListFragment extends SherlockListFragment
|
|||||||
initializeListAdapter();
|
initializeListAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeSearch(android.widget.SearchView searchView) {
|
@SuppressLint({ "NewApi", "NewApi" })
|
||||||
|
private void initializeSearch(android.widget.SearchView searchView) {
|
||||||
searchView.setOnQueryTextListener(new android.widget.SearchView.OnQueryTextListener() {
|
searchView.setOnQueryTextListener(new android.widget.SearchView.OnQueryTextListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onQueryTextSubmit(String query) {
|
public boolean onQueryTextSubmit(String query) {
|
||||||
@ -146,11 +148,11 @@ public class ConversationListFragment extends SherlockListFragment
|
|||||||
private void handleDeleteAllSelected() {
|
private void handleDeleteAllSelected() {
|
||||||
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
|
||||||
alert.setIcon(android.R.drawable.ic_dialog_alert);
|
alert.setIcon(android.R.drawable.ic_dialog_alert);
|
||||||
alert.setTitle("Delete threads?");
|
alert.setTitle(R.string.delete_threads_question);
|
||||||
alert.setMessage("Are you sure you wish to delete ALL selected conversation threads?");
|
alert.setMessage(R.string.are_you_sure_you_wish_to_delete_all_selected_conversation_threads);
|
||||||
alert.setCancelable(true);
|
alert.setCancelable(true);
|
||||||
|
|
||||||
alert.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
|
alert.setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
Set<Long> selectedConversations = ((ConversationListAdapter)getListAdapter())
|
Set<Long> selectedConversations = ((ConversationListAdapter)getListAdapter())
|
||||||
.getBatchSelections();
|
.getBatchSelections();
|
||||||
@ -162,7 +164,7 @@ public class ConversationListFragment extends SherlockListFragment
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
alert.setNegativeButton("Cancel", null);
|
alert.setNegativeButton(R.string.cancel, null);
|
||||||
alert.show();
|
alert.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ public class ConversationListItem extends RelativeLayout {
|
|||||||
this.fromView.setText(formatFrom(recipients, message.getCount(), message.getRead()));
|
this.fromView.setText(formatFrom(recipients, message.getCount(), message.getRead()));
|
||||||
|
|
||||||
if (message.isKeyExchange())
|
if (message.isKeyExchange())
|
||||||
this.subjectView.setText("Key exchange message...", TextView.BufferType.SPANNABLE);
|
this.subjectView.setText(R.string.key_exchange_message, TextView.BufferType.SPANNABLE);
|
||||||
else
|
else
|
||||||
this.subjectView.setText(message.getBody(), TextView.BufferType.SPANNABLE);
|
this.subjectView.setText(message.getBody(), TextView.BufferType.SPANNABLE);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,40 +10,42 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms;
|
package org.thoughtcrime.securesms;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.crypto.MessageDisplayHelper;
|
import org.thoughtcrime.securesms.crypto.MessageDisplayHelper;
|
||||||
import org.thoughtcrime.securesms.database.MessageRecord;
|
import org.thoughtcrime.securesms.database.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ConversationListAdapter that decrypts encrypted message bodies.
|
* A ConversationListAdapter that decrypts encrypted message bodies.
|
||||||
*
|
*
|
||||||
* @author Moxie Marlinspike
|
* @author Moxie Marlinspike
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class DecryptingConversationListAdapter extends ConversationListAdapter {
|
public class DecryptingConversationListAdapter extends ConversationListAdapter {
|
||||||
|
|
||||||
private final MasterCipher bodyCipher;
|
private final MasterCipher bodyCipher;
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
public DecryptingConversationListAdapter(Context context, Cursor cursor, MasterSecret masterSecret) {
|
public DecryptingConversationListAdapter(Context context, Cursor cursor, MasterSecret masterSecret) {
|
||||||
super(context, cursor);
|
super(context, cursor);
|
||||||
this.bodyCipher = new MasterCipher(masterSecret);
|
this.bodyCipher = new MasterCipher(masterSecret);
|
||||||
|
this.context = context.getApplicationContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setBody(Cursor cursor, MessageRecord message) {
|
protected void setBody(Cursor cursor, MessageRecord message) {
|
||||||
String body = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET));
|
String body = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET));
|
||||||
if (body == null || body.equals("")) body = "(No subject)";
|
if (body == null || body.equals("")) body = "(No subject)";
|
||||||
MessageDisplayHelper.setDecryptedMessageBody(body, message, bodyCipher);
|
MessageDisplayHelper.setDecryptedMessageBody(context, body, message, bodyCipher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ public abstract class KeyScanningActivity extends SherlockActivity {
|
|||||||
Dialogs.displayAlert(this, getNotVerifiedTitle(), getNotVerifiedMessage(), android.R.drawable.ic_dialog_alert);
|
Dialogs.displayAlert(this, getNotVerifiedTitle(), getNotVerifiedMessage(), android.R.drawable.ic_dialog_alert);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, "No scanned key found!", Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.no_scanned_key_found_exclamation, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,9 @@ public class PassphraseChangeActivity extends PassphraseActivity {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (!passphrase.equals(passphraseRepeat)) {
|
if (!passphrase.equals(passphraseRepeat)) {
|
||||||
Toast.makeText(getApplicationContext(), "Passphrases Don't Match!", Toast.LENGTH_SHORT).show();
|
Toast.makeText(getApplicationContext(),
|
||||||
|
R.string.passphrases_dont_match_exclamation,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
this.newPassphrase.setText("");
|
this.newPassphrase.setText("");
|
||||||
this.repeatPassphrase.setText("");
|
this.repeatPassphrase.setText("");
|
||||||
} else {
|
} else {
|
||||||
@ -86,7 +88,7 @@ public class PassphraseChangeActivity extends PassphraseActivity {
|
|||||||
setMasterSecret(masterSecret);
|
setMasterSecret(masterSecret);
|
||||||
}
|
}
|
||||||
} catch (InvalidPassphraseException e) {
|
} catch (InvalidPassphraseException e) {
|
||||||
Toast.makeText(this, "Incorrect old passphrase!", Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.incorrect_old_passphrase_exclamation, Toast.LENGTH_LONG).show();
|
||||||
this.originalPassphrase.setText("");
|
this.originalPassphrase.setText("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,8 +57,8 @@ public class PassphraseCreateActivity extends PassphraseActivity {
|
|||||||
private void initializeResources() {
|
private void initializeResources() {
|
||||||
this.passphraseEdit = (EditText) findViewById(R.id.passphrase_edit);
|
this.passphraseEdit = (EditText) findViewById(R.id.passphrase_edit);
|
||||||
this.passphraseRepeatEdit = (EditText) findViewById(R.id.passphrase_edit_repeat);
|
this.passphraseRepeatEdit = (EditText) findViewById(R.id.passphrase_edit_repeat);
|
||||||
this.okButton = (Button) findViewById(R.id.ok_button);
|
this.okButton = (Button) findViewById(R.id.ok_button);
|
||||||
this.cancelButton = (Button) findViewById(R.id.cancel_button);
|
this.cancelButton = (Button) findViewById(R.id.cancel_button);
|
||||||
|
|
||||||
this.okButton.setOnClickListener(new OkButtonClickListener());
|
this.okButton.setOnClickListener(new OkButtonClickListener());
|
||||||
this.cancelButton.setOnClickListener(new CancelButtonClickListener());
|
this.cancelButton.setOnClickListener(new CancelButtonClickListener());
|
||||||
@ -69,7 +69,8 @@ public class PassphraseCreateActivity extends PassphraseActivity {
|
|||||||
String passphraseRepeat = this.passphraseRepeatEdit.getText().toString();
|
String passphraseRepeat = this.passphraseRepeatEdit.getText().toString();
|
||||||
|
|
||||||
if (!passphrase.equals(passphraseRepeat)) {
|
if (!passphrase.equals(passphraseRepeat)) {
|
||||||
Toast.makeText(getApplicationContext(), "Passphrases Don't Match!", Toast.LENGTH_SHORT).show();
|
Toast.makeText(getApplicationContext(), R.string.passphrases_dont_match_exclamation,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
this.passphraseEdit.setText("");
|
this.passphraseEdit.setText("");
|
||||||
this.passphraseRepeatEdit.setText("");
|
this.passphraseRepeatEdit.setText("");
|
||||||
} else {
|
} else {
|
||||||
@ -96,8 +97,8 @@ public class PassphraseCreateActivity extends PassphraseActivity {
|
|||||||
|
|
||||||
public void generate() {
|
public void generate() {
|
||||||
progressDialog = new ProgressDialog(PassphraseCreateActivity.this);
|
progressDialog = new ProgressDialog(PassphraseCreateActivity.this);
|
||||||
progressDialog.setTitle("Generating KeyPair");
|
progressDialog.setTitle(R.string.generating_keypair);
|
||||||
progressDialog.setMessage("Generating a local encryption keypair...");
|
progressDialog.setMessage(getString(R.string.generating_a_local_encryption_keypair));
|
||||||
progressDialog.setCancelable(false);
|
progressDialog.setCancelable(false);
|
||||||
progressDialog.setIndeterminate(true);
|
progressDialog.setIndeterminate(true);
|
||||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||||
|
@ -67,7 +67,9 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
|||||||
MemoryCleaner.clean(passphrase);
|
MemoryCleaner.clean(passphrase);
|
||||||
setMasterSecret(masterSecret);
|
setMasterSecret(masterSecret);
|
||||||
} catch (InvalidPassphraseException ipe) {
|
} catch (InvalidPassphraseException ipe) {
|
||||||
Toast.makeText(getApplicationContext(), "Invalid Passphrase!", Toast.LENGTH_SHORT).show();
|
Toast.makeText(getApplicationContext(),
|
||||||
|
R.string.invalid_passphrase_exclamation,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,12 +10,20 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms;
|
package org.thoughtcrime.securesms;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKey;
|
import org.thoughtcrime.securesms.crypto.IdentityKey;
|
||||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||||
import org.thoughtcrime.securesms.crypto.InvalidVersionException;
|
import org.thoughtcrime.securesms.crypto.InvalidVersionException;
|
||||||
@ -26,17 +34,9 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.MemoryCleaner;
|
import org.thoughtcrime.securesms.util.MemoryCleaner;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity for displaying sent/received session keys.
|
* Activity for displaying sent/received session keys.
|
||||||
*
|
*
|
||||||
* @author Moxie Marlinspike
|
* @author Moxie Marlinspike
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -44,26 +44,26 @@ public class ReceiveKeyActivity extends Activity {
|
|||||||
|
|
||||||
private TextView descriptionText;
|
private TextView descriptionText;
|
||||||
private TextView signatureText;
|
private TextView signatureText;
|
||||||
|
|
||||||
private Button confirmButton;
|
private Button confirmButton;
|
||||||
private Button cancelButton;
|
private Button cancelButton;
|
||||||
private Button verifySessionButton;
|
private Button verifySessionButton;
|
||||||
private Button verifyIdentityButton;
|
private Button verifyIdentityButton;
|
||||||
|
|
||||||
private Recipient recipient;
|
private Recipient recipient;
|
||||||
private long threadId;
|
private long threadId;
|
||||||
|
|
||||||
private MasterSecret masterSecret;
|
private MasterSecret masterSecret;
|
||||||
private KeyExchangeMessage keyExchangeMessage;
|
private KeyExchangeMessage keyExchangeMessage;
|
||||||
private KeyExchangeProcessor keyExchangeProcessor;
|
private KeyExchangeProcessor keyExchangeProcessor;
|
||||||
|
|
||||||
private boolean sent;
|
private boolean sent;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle state) {
|
protected void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
setContentView(R.layout.receive_key_activity);
|
setContentView(R.layout.receive_key_activity);
|
||||||
|
|
||||||
initializeResources();
|
initializeResources();
|
||||||
try {
|
try {
|
||||||
initializeKey();
|
initializeKey();
|
||||||
@ -76,110 +76,100 @@ public class ReceiveKeyActivity extends Activity {
|
|||||||
}
|
}
|
||||||
initializeListeners();
|
initializeListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
MemoryCleaner.clean(masterSecret);
|
MemoryCleaner.clean(masterSecret);
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeText() {
|
private void initializeText() {
|
||||||
if (keyExchangeProcessor.hasCompletedSession()) initializeTextForExistingSession();
|
if (keyExchangeProcessor.hasCompletedSession()) initializeTextForExistingSession();
|
||||||
else initializeTextForNewSession();
|
else initializeTextForNewSession();
|
||||||
|
|
||||||
initializeSignatureText();
|
initializeSignatureText();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeCorruptedKeyText() {
|
private void initializeCorruptedKeyText() {
|
||||||
descriptionText.setText("ERROR:\n\nYou have received a corrupted public key. This key can not be processed, please re-initiate a secure session.");
|
descriptionText.setText(R.string.error_you_have_received_a_corrupted_public_key);
|
||||||
confirmButton.setVisibility(View.GONE);
|
confirmButton.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeBadVersionText() {
|
private void initializeBadVersionText() {
|
||||||
descriptionText.setText("ERROR:\n\nYou have received a public key from an unsupported version of the protocol. This key can not be processed, please re-initiate a secure session.");
|
descriptionText.setText(R.string.error_you_have_received_a_public_key_from_an_unsupported_version_of_the_protocol);
|
||||||
confirmButton.setVisibility(View.GONE);
|
confirmButton.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeSignatureText() {
|
private void initializeSignatureText() {
|
||||||
if (!keyExchangeMessage.hasIdentityKey()) {
|
if (!keyExchangeMessage.hasIdentityKey()) {
|
||||||
signatureText.setText("This key exchange message does not include an identity signature.");
|
signatureText.setText(R.string.this_key_exchange_message_does_not_include_an_identity_signature);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentityKey identityKey = keyExchangeMessage.getIdentityKey();
|
IdentityKey identityKey = keyExchangeMessage.getIdentityKey();
|
||||||
String identityName = DatabaseFactory.getIdentityDatabase(this).getNameForIdentity(masterSecret, identityKey);
|
String identityName = DatabaseFactory.getIdentityDatabase(this).getNameForIdentity(masterSecret, identityKey);
|
||||||
|
|
||||||
if (identityName == null) {
|
if (identityName == null) {
|
||||||
signatureText.setText("This key exchange message includes an identity signature, but you do not yet trust it.");
|
signatureText.setText(R.string.this_key_exchange_message_includes_an_identity_signature_but_you_do_not_yet_trust_it);
|
||||||
} else {
|
} else {
|
||||||
signatureText.setText("This key exchange message includes an identity signature which you trust for: " + identityName);
|
signatureText.setText(String.format(getString(R.string.this_key_exchange_message_includes_an_identity_signature_which_you_trust_for_s), identityName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTextForExistingSession() {
|
private void initializeTextForExistingSession() {
|
||||||
if (keyExchangeProcessor.isRemoteKeyExchangeForExistingSession(keyExchangeMessage)) {
|
if (keyExchangeProcessor.isRemoteKeyExchangeForExistingSession(keyExchangeMessage)) {
|
||||||
descriptionText.setText("This is the key that you sent to start your current encrypted session with " + recipient.toShortString());
|
descriptionText.setText(String.format(getString(R.string.this_is_the_key_that_you_sent_to_start_your_current_encrypted_session_with_s), recipient.toShortString()));
|
||||||
this.confirmButton.setVisibility(View.GONE);
|
this.confirmButton.setVisibility(View.GONE);
|
||||||
this.verifySessionButton.setVisibility(View.VISIBLE);
|
this.verifySessionButton.setVisibility(View.VISIBLE);
|
||||||
this.verifyIdentityButton.setVisibility(View.VISIBLE);
|
this.verifyIdentityButton.setVisibility(View.VISIBLE);
|
||||||
} else if (keyExchangeProcessor.isLocalKeyExchangeForExistingSession(keyExchangeMessage)) {
|
} else if (keyExchangeProcessor.isLocalKeyExchangeForExistingSession(keyExchangeMessage)) {
|
||||||
descriptionText.setText("This is the key that you received to start your current encrypted session with " + recipient.toShortString());
|
descriptionText.setText(String.format(getString(R.string.this_is_the_key_that_you_received_to_start_your_current_encrypted_session_with_s), recipient.toShortString()));
|
||||||
this.confirmButton.setVisibility(View.GONE);
|
this.confirmButton.setVisibility(View.GONE);
|
||||||
this.verifySessionButton.setVisibility(View.VISIBLE);
|
this.verifySessionButton.setVisibility(View.VISIBLE);
|
||||||
this.verifyIdentityButton.setVisibility(View.VISIBLE);
|
this.verifyIdentityButton.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
descriptionText.setText("You have received a Key Exchange message from " + recipient.toShortString() + "." +
|
descriptionText.setText(String.format(getString(R.string.you_have_received_a_key_exchange_message_from_s_warning_you_already_have_an_encrypted_session), recipient.toShortString()));
|
||||||
"\n\nWARNING: You already have an encrypted session with this contact." +
|
|
||||||
" If you choose to accept this key exchange message, it will destroy your " +
|
|
||||||
"existing session and you will have to re-authenticate. Would you like to complete " +
|
|
||||||
"this key exchange?");
|
|
||||||
this.confirmButton.setVisibility(View.VISIBLE);
|
this.confirmButton.setVisibility(View.VISIBLE);
|
||||||
this.verifyIdentityButton.setVisibility(View.GONE);
|
this.verifyIdentityButton.setVisibility(View.GONE);
|
||||||
this.verifySessionButton.setVisibility(View.GONE);
|
this.verifySessionButton.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeTextForNewSession() {
|
private void initializeTextForNewSession() {
|
||||||
if (keyExchangeProcessor.hasInitiatedSession() && !this.sent)
|
if (keyExchangeProcessor.hasInitiatedSession() && !this.sent)
|
||||||
descriptionText.setText("You have received a Key Exchange message from " + recipient.toShortString() +
|
descriptionText.setText(String.format(getString(R.string.you_have_received_a_key_exchange_message_from_s_you_have_previously_initiated), recipient.toShortString()));
|
||||||
". You have previously initiated a session with this contact, " +
|
|
||||||
"and by accepting this key you will complete the key exchange. " +
|
|
||||||
"Would you like to complete this key exchange?");
|
|
||||||
else if (keyExchangeProcessor.hasInitiatedSession() && this.sent)
|
else if (keyExchangeProcessor.hasInitiatedSession() && this.sent)
|
||||||
descriptionText.setText("You have initiated a Key Exchange message with " + recipient.toShortString() +
|
descriptionText.setText(String.format(getString(R.string.you_have_initiated_a_key_exchange_message_with_s_but_have_not_yet_received_a_reply), recipient.toShortString()));
|
||||||
" but have not yet received a reply.");
|
|
||||||
else if (!keyExchangeProcessor.hasInitiatedSession() && !this.sent)
|
else if (!keyExchangeProcessor.hasInitiatedSession() && !this.sent)
|
||||||
descriptionText.setText("You have received a Key Exchange message from " + recipient.toShortString() +
|
descriptionText.setText(String.format(getString(R.string.you_have_received_a_key_exchange_message_from_s_you_have_no_existing_session), recipient.toShortString()));
|
||||||
". You have no existing session with this contact, would you like " +
|
|
||||||
"to complete this key exchange?");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeKey() throws InvalidKeyException, InvalidVersionException {
|
private void initializeKey() throws InvalidKeyException, InvalidVersionException {
|
||||||
String messageBody = getIntent().getStringExtra("body");
|
String messageBody = getIntent().getStringExtra("body");
|
||||||
this.keyExchangeMessage = new KeyExchangeMessage(messageBody);
|
this.keyExchangeMessage = new KeyExchangeMessage(messageBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeResources() {
|
private void initializeResources() {
|
||||||
this.descriptionText = (TextView) findViewById(R.id.description_text);
|
this.descriptionText = (TextView) findViewById(R.id.description_text);
|
||||||
this.signatureText = (TextView) findViewById(R.id.signature_text);
|
this.signatureText = (TextView) findViewById(R.id.signature_text);
|
||||||
this.confirmButton = (Button) findViewById(R.id.ok_button);
|
this.confirmButton = (Button) findViewById(R.id.ok_button);
|
||||||
this.cancelButton = (Button) findViewById(R.id.cancel_button);
|
this.cancelButton = (Button) findViewById(R.id.cancel_button);
|
||||||
this.verifyIdentityButton = (Button)findViewById(R.id.verify_identity_button);
|
this.verifyIdentityButton = (Button) findViewById(R.id.verify_identity_button);
|
||||||
this.verifySessionButton = (Button)findViewById(R.id.verify_session_button);
|
this.verifySessionButton = (Button) findViewById(R.id.verify_session_button);
|
||||||
this.recipient = getIntent().getParcelableExtra("recipient");
|
this.recipient = getIntent().getParcelableExtra("recipient");
|
||||||
this.threadId = getIntent().getLongExtra("thread_id", -1);
|
this.threadId = getIntent().getLongExtra("thread_id", -1);
|
||||||
this.masterSecret = (MasterSecret)getIntent().getParcelableExtra("master_secret");
|
this.masterSecret = (MasterSecret)getIntent().getParcelableExtra("master_secret");
|
||||||
this.sent = getIntent().getBooleanExtra("sent", false);
|
this.sent = getIntent().getBooleanExtra("sent", false);
|
||||||
this.keyExchangeProcessor = new KeyExchangeProcessor(this, masterSecret, recipient);
|
this.keyExchangeProcessor = new KeyExchangeProcessor(this, masterSecret, recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeListeners() {
|
private void initializeListeners() {
|
||||||
this.confirmButton.setOnClickListener(new OkListener());
|
this.confirmButton.setOnClickListener(new OkListener());
|
||||||
this.cancelButton.setOnClickListener(new CancelListener());
|
this.cancelButton.setOnClickListener(new CancelListener());
|
||||||
this.verifyIdentityButton.setOnClickListener(new VerifyIdentityListener());
|
this.verifyIdentityButton.setOnClickListener(new VerifyIdentityListener());
|
||||||
this.verifySessionButton.setOnClickListener(new VerifySessionListener());
|
this.verifySessionButton.setOnClickListener(new VerifySessionListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
private class VerifyIdentityListener implements View.OnClickListener {
|
private class VerifyIdentityListener implements View.OnClickListener {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent intent = new Intent(ReceiveKeyActivity.this, VerifyIdentityActivity.class);
|
Intent intent = new Intent(ReceiveKeyActivity.this, VerifyIdentityActivity.class);
|
||||||
@ -189,7 +179,7 @@ public class ReceiveKeyActivity extends Activity {
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class VerifySessionListener implements View.OnClickListener {
|
private class VerifySessionListener implements View.OnClickListener {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent intent = new Intent(ReceiveKeyActivity.this, VerifyKeysActivity.class);
|
Intent intent = new Intent(ReceiveKeyActivity.this, VerifyKeysActivity.class);
|
||||||
@ -199,14 +189,14 @@ public class ReceiveKeyActivity extends Activity {
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OkListener implements View.OnClickListener {
|
private class OkListener implements View.OnClickListener {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
keyExchangeProcessor.processKeyExchangeMessage(keyExchangeMessage, threadId);
|
keyExchangeProcessor.processKeyExchangeMessage(keyExchangeMessage, threadId);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CancelListener implements View.OnClickListener {
|
private class CancelListener implements View.OnClickListener {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
ReceiveKeyActivity.this.finish();
|
ReceiveKeyActivity.this.finish();
|
||||||
|
@ -127,10 +127,10 @@ public class ReviewIdentitiesActivity extends SherlockListActivity {
|
|||||||
startActivity(viewIntent);
|
startActivity(viewIntent);
|
||||||
} catch (InvalidKeyException ike) {
|
} catch (InvalidKeyException ike) {
|
||||||
Log.w("ReviewIdentitiesActivity", ike);
|
Log.w("ReviewIdentitiesActivity", ike);
|
||||||
Toast.makeText(this, "Unable to view corrupted identity key!", Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.unable_to_view_corrupted_identity_key_exclamation, Toast.LENGTH_LONG).show();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w("ReviewIdentitiesActivity", e);
|
Log.w("ReviewIdentitiesActivity", e);
|
||||||
Toast.makeText(this, "Unable to view corrupted identity key!", Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.unable_to_view_corrupted_identity_key_exclamation, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,9 @@ public class SaveIdentityActivity extends SherlockActivity {
|
|||||||
private class OkListener implements View.OnClickListener {
|
private class OkListener implements View.OnClickListener {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (identityName.getText() == null || identityName.getText().toString().trim().length() == 0) {
|
if (identityName.getText() == null || identityName.getText().toString().trim().length() == 0) {
|
||||||
Toast.makeText(SaveIdentityActivity.this, "You must specify a name for this identity!", Toast.LENGTH_LONG).show();
|
Toast.makeText(SaveIdentityActivity.this,
|
||||||
|
R.string.you_must_specify_a_name_for_this_identity_exclamation,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,16 +95,16 @@ public class SaveIdentityActivity extends SherlockActivity {
|
|||||||
DatabaseFactory.getIdentityDatabase(SaveIdentityActivity.this).saveIdentity(masterSecret, identityKey, identityName.getText().toString());
|
DatabaseFactory.getIdentityDatabase(SaveIdentityActivity.this).saveIdentity(masterSecret, identityKey, identityName.getText().toString());
|
||||||
} catch (InvalidKeyException e) {
|
} catch (InvalidKeyException e) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(SaveIdentityActivity.this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(SaveIdentityActivity.this);
|
||||||
builder.setTitle("Identity Name Exists!");
|
builder.setTitle(R.string.identity_name_exists_exclamation);
|
||||||
builder.setMessage("An identity key with the specified name already exists.");
|
builder.setMessage(R.string.an_identity_key_with_the_specified_name_already_exists);
|
||||||
builder.setPositiveButton("Manage Identities", new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(R.string.manage_identities, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
Intent intent = new Intent(SaveIdentityActivity.this, ReviewIdentitiesActivity.class);
|
Intent intent = new Intent(SaveIdentityActivity.this, ReviewIdentitiesActivity.class);
|
||||||
intent.putExtra("master_secret", masterSecret);
|
intent.putExtra("master_secret", masterSecret);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.setNegativeButton("Cancel", null);
|
builder.setNegativeButton(R.string.cancel, null);
|
||||||
builder.show();
|
builder.show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -62,11 +62,10 @@ public class VerifyIdentityActivity extends KeyVerifyingActivity {
|
|||||||
protected void handleVerified() {
|
protected void handleVerified() {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||||
builder.setTitle("Mark Identity Verified?");
|
builder.setTitle(R.string.mark_identity_verified_question);
|
||||||
builder.setMessage("Are you sure you have validated the recipients' identity fingerprint " +
|
builder.setMessage(R.string.are_you_sure_you_have_validated_the_recipients_identity_fingerprint_and_would_like_to_mark_it_as_verified);
|
||||||
"and would like to mark it as verified?");
|
|
||||||
|
|
||||||
builder.setPositiveButton("Mark Verified", new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(R.string.mark_verified, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
SessionRecord sessionRecord = new SessionRecord(VerifyIdentityActivity.this,
|
SessionRecord sessionRecord = new SessionRecord(VerifyIdentityActivity.this,
|
||||||
@ -92,7 +91,7 @@ public class VerifyIdentityActivity extends KeyVerifyingActivity {
|
|||||||
|
|
||||||
private void initializeLocalIdentityKey() {
|
private void initializeLocalIdentityKey() {
|
||||||
if (!IdentityKeyUtil.hasIdentityKey(this)) {
|
if (!IdentityKeyUtil.hasIdentityKey(this)) {
|
||||||
localIdentityFingerprint.setText("You do not have an identity key.");
|
localIdentityFingerprint.setText(R.string.you_do_not_have_an_identity_key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +103,7 @@ public class VerifyIdentityActivity extends KeyVerifyingActivity {
|
|||||||
IdentityKey identityKey = sessionRecord.getIdentityKey();
|
IdentityKey identityKey = sessionRecord.getIdentityKey();
|
||||||
|
|
||||||
if (identityKey == null) {
|
if (identityKey == null) {
|
||||||
remoteIdentityFingerprint.setText("Recipient has no identity key.");
|
remoteIdentityFingerprint.setText(R.string.recipient_has_no_identity_key);
|
||||||
} else {
|
} else {
|
||||||
remoteIdentityFingerprint.setText(identityKey.getFingerprint());
|
remoteIdentityFingerprint.setText(identityKey.getFingerprint());
|
||||||
}
|
}
|
||||||
@ -125,7 +124,7 @@ public class VerifyIdentityActivity extends KeyVerifyingActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void initiateDisplay() {
|
protected void initiateDisplay() {
|
||||||
if (!IdentityKeyUtil.hasIdentityKey(this)) {
|
if (!IdentityKeyUtil.hasIdentityKey(this)) {
|
||||||
Toast.makeText(this, "You don't have an identity key!", Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.you_don_t_have_an_identity_key_exclamation, Toast.LENGTH_LONG).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +137,7 @@ public class VerifyIdentityActivity extends KeyVerifyingActivity {
|
|||||||
IdentityKey identityKey = sessionRecord.getIdentityKey();
|
IdentityKey identityKey = sessionRecord.getIdentityKey();
|
||||||
|
|
||||||
if (identityKey == null) {
|
if (identityKey == null) {
|
||||||
Toast.makeText(this, "Recipient has no identity key!", Toast.LENGTH_LONG);
|
Toast.makeText(this, R.string.recipient_has_no_identity_key_exclamation, Toast.LENGTH_LONG).show();
|
||||||
} else {
|
} else {
|
||||||
super.initiateScan();
|
super.initiateScan();
|
||||||
}
|
}
|
||||||
@ -146,12 +145,12 @@ public class VerifyIdentityActivity extends KeyVerifyingActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getScanString() {
|
protected String getScanString() {
|
||||||
return "Scan their key to compare";
|
return getString(R.string.scan_their_key_to_compare);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getDisplayString() {
|
protected String getDisplayString() {
|
||||||
return "Get my key scanned";
|
return getString(R.string.get_my_key_scanned);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -167,21 +166,21 @@ public class VerifyIdentityActivity extends KeyVerifyingActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getNotVerifiedMessage() {
|
protected String getNotVerifiedMessage() {
|
||||||
return "WARNING, the scanned key DOES NOT match! Please check the fingerprint text carefully.";
|
return getString(R.string.warning_the_scanned_key_does_not_match_please_check_the_fingerprint_text_carefully);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getNotVerifiedTitle() {
|
protected String getNotVerifiedTitle() {
|
||||||
return "NOT Verified!";
|
return getString(R.string.not_verified_exclamation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getVerifiedMessage() {
|
protected String getVerifiedMessage() {
|
||||||
return "Their key is correct. It is also necessary to verify your key with them as well.";
|
return getString(R.string.their_key_is_correct_it_is_also_necessary_to_verify_your_key_with_them_as_well);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getVerifiedTitle() {
|
protected String getVerifiedTitle() {
|
||||||
return "Verified!";
|
return getString(R.string.verified_exclamation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,19 +10,12 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms;
|
package org.thoughtcrime.securesms;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKey;
|
|
||||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|
||||||
import org.thoughtcrime.securesms.util.Dialogs;
|
|
||||||
import org.thoughtcrime.securesms.util.MemoryCleaner;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -33,52 +26,59 @@ import android.widget.EditText;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.crypto.IdentityKey;
|
||||||
|
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||||
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
|
import org.thoughtcrime.securesms.util.Dialogs;
|
||||||
|
import org.thoughtcrime.securesms.util.MemoryCleaner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity for verifying identities keys as they are imported.
|
* Activity for verifying identities keys as they are imported.
|
||||||
*
|
*
|
||||||
* @author Moxie Marlinspike
|
* @author Moxie Marlinspike
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class VerifyImportedIdentityActivity extends KeyScanningActivity {
|
public class VerifyImportedIdentityActivity extends KeyScanningActivity {
|
||||||
|
|
||||||
private MasterSecret masterSecret;
|
private MasterSecret masterSecret;
|
||||||
private String contactName;
|
private String contactName;
|
||||||
private IdentityKey identityKey;
|
private IdentityKey identityKey;
|
||||||
private EditText identityName;
|
private EditText identityName;
|
||||||
private TextView identityFingerprint;
|
private TextView identityFingerprint;
|
||||||
|
|
||||||
private Button compareButton;
|
private Button compareButton;
|
||||||
private Button verifiedButton;
|
private Button verifiedButton;
|
||||||
private Button cancelButton;
|
private Button cancelButton;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
setContentView(R.layout.verify_imported_identity_activity);
|
setContentView(R.layout.verify_imported_identity_activity);
|
||||||
|
|
||||||
initializeResources();
|
initializeResources();
|
||||||
initializeFingerprints();
|
initializeFingerprints();
|
||||||
initializeListeners();
|
initializeListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
MemoryCleaner.clean(masterSecret);
|
MemoryCleaner.clean(masterSecret);
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeListeners() {
|
private void initializeListeners() {
|
||||||
verifiedButton.setOnClickListener(new VerifiedButtonListener());
|
verifiedButton.setOnClickListener(new VerifiedButtonListener());
|
||||||
cancelButton.setOnClickListener(new CancelButtonListener());
|
cancelButton.setOnClickListener(new CancelButtonListener());
|
||||||
compareButton.setOnClickListener(new CompareButtonListener());
|
compareButton.setOnClickListener(new CompareButtonListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeFingerprints() {
|
private void initializeFingerprints() {
|
||||||
if (contactName != null)
|
if (contactName != null)
|
||||||
identityName.setText(contactName);
|
identityName.setText(contactName);
|
||||||
identityFingerprint.setText(identityKey.getFingerprint());
|
identityFingerprint.setText(identityKey.getFingerprint());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeResources() {
|
private void initializeResources() {
|
||||||
masterSecret = (MasterSecret)this.getIntent().getParcelableExtra("master_secret");
|
masterSecret = (MasterSecret)this.getIntent().getParcelableExtra("master_secret");
|
||||||
identityFingerprint = (TextView)findViewById(R.id.imported_identity);
|
identityFingerprint = (TextView)findViewById(R.id.imported_identity);
|
||||||
@ -89,31 +89,33 @@ public class VerifyImportedIdentityActivity extends KeyScanningActivity {
|
|||||||
cancelButton = (Button)findViewById(R.id.cancel_button);
|
cancelButton = (Button)findViewById(R.id.cancel_button);
|
||||||
compareButton = (Button)findViewById(R.id.compare_button);
|
compareButton = (Button)findViewById(R.id.compare_button);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CancelButtonListener implements View.OnClickListener {
|
private class CancelButtonListener implements View.OnClickListener {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CompareButtonListener implements View.OnClickListener {
|
private class CompareButtonListener implements View.OnClickListener {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
registerForContextMenu(compareButton);
|
registerForContextMenu(compareButton);
|
||||||
compareButton.showContextMenu();
|
compareButton.showContextMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class VerifiedButtonListener implements View.OnClickListener {
|
private class VerifiedButtonListener implements View.OnClickListener {
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (identityName.getText() == null || identityName.getText().length() == 0) {
|
if (identityName.getText() == null || identityName.getText().length() == 0) {
|
||||||
Toast.makeText(VerifyImportedIdentityActivity.this, "You must specify a name for this contact!", Toast.LENGTH_LONG);
|
Toast.makeText(VerifyImportedIdentityActivity.this,
|
||||||
|
R.string.you_must_specify_a_name_for_this_contact_exclamation,
|
||||||
|
Toast.LENGTH_LONG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(VerifyImportedIdentityActivity.this);
|
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(VerifyImportedIdentityActivity.this);
|
||||||
dialogBuilder.setTitle("Save Identity Key?");
|
dialogBuilder.setTitle(R.string.save_identity_key_question);
|
||||||
dialogBuilder.setIcon(android.R.drawable.ic_dialog_info);
|
dialogBuilder.setIcon(android.R.drawable.ic_dialog_info);
|
||||||
dialogBuilder.setMessage("Are you sure that you would like to mark this as a valid identity key for all future correspondence with " + identityName.getText() + "? You should only do this if you have actually verified the fingerprint.");
|
dialogBuilder.setMessage(String.format(getString(R.string.are_you_sure_that_you_would_like_to_mark_this_as_a_valid_identity_key_for_all_future_correspondence_with_s), identityName.getText()));
|
||||||
dialogBuilder.setCancelable(true);
|
dialogBuilder.setCancelable(true);
|
||||||
dialogBuilder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
dialogBuilder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface arg0, int arg1) {
|
public void onClick(DialogInterface arg0, int arg1) {
|
||||||
@ -121,8 +123,9 @@ public class VerifyImportedIdentityActivity extends KeyScanningActivity {
|
|||||||
DatabaseFactory.getIdentityDatabase(VerifyImportedIdentityActivity.this).saveIdentity(masterSecret, identityKey, identityName.getText().toString());
|
DatabaseFactory.getIdentityDatabase(VerifyImportedIdentityActivity.this).saveIdentity(masterSecret, identityKey, identityName.getText().toString());
|
||||||
} catch (InvalidKeyException ike) {
|
} catch (InvalidKeyException ike) {
|
||||||
Log.w("VerifiedButtonListener", ike);
|
Log.w("VerifiedButtonListener", ike);
|
||||||
Dialogs.displayAlert(VerifyImportedIdentityActivity.this, "Error saving identity key!",
|
Dialogs.displayAlert(VerifyImportedIdentityActivity.this,
|
||||||
"This identity key or an identity key with the same name already exists. Please edit your key database.",
|
getString(R.string.error_saving_identity_key_exclamation),
|
||||||
|
getString(R.string.this_identity_key_or_an_identity_key_with_the_same_name_already_exists_please_edit_your_key_database),
|
||||||
android.R.drawable.ic_dialog_alert);
|
android.R.drawable.ic_dialog_alert);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -134,15 +137,15 @@ public class VerifyImportedIdentityActivity extends KeyScanningActivity {
|
|||||||
dialogBuilder.show();
|
dialogBuilder.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getScanString() {
|
protected String getScanString() {
|
||||||
return "Scan to compare";
|
return getString(R.string.scan_to_compare);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getDisplayString() {
|
protected String getDisplayString() {
|
||||||
return "Get scanned to compare";
|
return getString(R.string.get_scanned_to_compare);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -157,21 +160,21 @@ public class VerifyImportedIdentityActivity extends KeyScanningActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getNotVerifiedMessage() {
|
protected String getNotVerifiedMessage() {
|
||||||
return "WARNING, the scanned key DOES NOT match!";
|
return getString(R.string.warning_the_scanned_key_does_not_match_exclamation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getNotVerifiedTitle() {
|
protected String getNotVerifiedTitle() {
|
||||||
return "NOT Verified!";
|
return getString(R.string.not_verified_exclamation2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getVerifiedMessage() {
|
protected String getVerifiedMessage() {
|
||||||
return "The scanned key matches!";
|
return getString(R.string.the_scanned_key_matches_exclamation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getVerifiedTitle() {
|
protected String getVerifiedTitle() {
|
||||||
return "Verified!";
|
return getString(R.string.verified_exclamation2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,10 +64,9 @@ public class VerifyKeysActivity extends KeyVerifyingActivity {
|
|||||||
protected void handleVerified() {
|
protected void handleVerified() {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||||
builder.setTitle("Mark Session Verified?");
|
builder.setTitle(R.string.mark_session_verified_question);
|
||||||
builder.setMessage("Are you sure that you have validated these fingerprints and " +
|
builder.setMessage(R.string.are_you_sure_that_you_have_validated_these_fingerprints_and_would_like_to_mark_this_session_as_verified);
|
||||||
"would like to mark this session as verified?");
|
builder.setPositiveButton(R.string.mark_verified2, new DialogInterface.OnClickListener() {
|
||||||
builder.setPositiveButton("Mark Verified", new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
SessionRecord sessionRecord = new SessionRecord(VerifyKeysActivity.this, masterSecret,
|
SessionRecord sessionRecord = new SessionRecord(VerifyKeysActivity.this, masterSecret,
|
||||||
@ -78,7 +77,7 @@ public class VerifyKeysActivity extends KeyVerifyingActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.setNegativeButton("Cancel", null);
|
builder.setNegativeButton(R.string.cancel, null);
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,12 +99,12 @@ public class VerifyKeysActivity extends KeyVerifyingActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getDisplayString() {
|
protected String getDisplayString() {
|
||||||
return "Get my fingerprint scanned";
|
return getString(R.string.get_my_fingerprint_scanned);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getScanString() {
|
protected String getScanString() {
|
||||||
return "Scan their fingerprint";
|
return getString(R.string.scan_their_fingerprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -120,22 +119,22 @@ public class VerifyKeysActivity extends KeyVerifyingActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getNotVerifiedMessage() {
|
protected String getNotVerifiedMessage() {
|
||||||
return "WARNING, the scanned key DOES NOT match! Please check the fingerprint text carefully.";
|
return getString(R.string.warning_the_scanned_key_does_not_match_please_check_the_fingerprint_text_carefully2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getNotVerifiedTitle() {
|
protected String getNotVerifiedTitle() {
|
||||||
return "NOT Verified!";
|
return getString(R.string.not_verified_exclamation3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getVerifiedMessage() {
|
protected String getVerifiedMessage() {
|
||||||
return "Their key is correct. It is also necessary to get your fingerprint scanned as well.";
|
return getString(R.string.their_key_is_correct_it_is_also_necessary_to_get_your_fingerprint_scanned_as_well);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getVerifiedTitle() {
|
protected String getVerifiedTitle() {
|
||||||
return "Verified!";
|
return getString(R.string.verified_exclamation3);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FingerprintKey implements SerializableKey {
|
private class FingerprintKey implements SerializableKey {
|
||||||
|
@ -47,7 +47,7 @@ public class ViewIdentityActivity extends KeyScanningActivity {
|
|||||||
|
|
||||||
private void initializeFingerprint() {
|
private void initializeFingerprint() {
|
||||||
if (identityKey == null) {
|
if (identityKey == null) {
|
||||||
identityFingerprint.setText("You do not have an identity key.");
|
identityFingerprint.setText(R.string.you_do_not_have_an_identity_key2);
|
||||||
} else {
|
} else {
|
||||||
identityFingerprint.setText(identityKey.getFingerprint());
|
identityFingerprint.setText(identityKey.getFingerprint());
|
||||||
}
|
}
|
||||||
@ -79,12 +79,12 @@ public class ViewIdentityActivity extends KeyScanningActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getScanString() {
|
protected String getScanString() {
|
||||||
return "Scan to compare";
|
return getString(R.string.scan_to_compare2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getDisplayString() {
|
protected String getDisplayString() {
|
||||||
return "Get scanned to compare";
|
return getString(R.string.get_scanned_to_compare2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -99,21 +99,21 @@ public class ViewIdentityActivity extends KeyScanningActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getNotVerifiedMessage() {
|
protected String getNotVerifiedMessage() {
|
||||||
return "WARNING, the scanned key DOES NOT match!";
|
return getString(R.string.warning_the_scanned_key_does_not_match_exclamation2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getNotVerifiedTitle() {
|
protected String getNotVerifiedTitle() {
|
||||||
return "NOT Verified!";
|
return getString(R.string.not_verified_exclamation4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getVerifiedMessage() {
|
protected String getVerifiedMessage() {
|
||||||
return "The scanned key matches!";
|
return getString(R.string.the_scanned_key_matches_exclamation2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getVerifiedTitle() {
|
protected String getVerifiedTitle() {
|
||||||
return "Verified!";
|
return getString(R.string.verified_exclamation4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package org.thoughtcrime.securesms.crypto;
|
|||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.database.LocalKeyRecord;
|
import org.thoughtcrime.securesms.database.LocalKeyRecord;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
@ -33,16 +34,16 @@ public class KeyExchangeInitiator {
|
|||||||
public static void initiate(final Context context, final MasterSecret masterSecret, final Recipient recipient, boolean promptOnExisting) {
|
public static void initiate(final Context context, final MasterSecret masterSecret, final Recipient recipient, boolean promptOnExisting) {
|
||||||
if (promptOnExisting && hasInitiatedSession(context, masterSecret, recipient)) {
|
if (promptOnExisting && hasInitiatedSession(context, masterSecret, recipient)) {
|
||||||
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
|
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
|
||||||
dialog.setTitle("Initiate Despite Existing Request?");
|
dialog.setTitle(R.string.initiate_despite_existing_request_question);
|
||||||
dialog.setMessage("You've already sent a session initiation request to this recipient, are you sure you'd like to send another? This will invalidate the first request.");
|
dialog.setMessage(R.string.youve_already_sent_a_session_initiation_request_to_this_recipient_are_you_sure);
|
||||||
dialog.setIcon(android.R.drawable.ic_dialog_alert);
|
dialog.setIcon(android.R.drawable.ic_dialog_alert);
|
||||||
dialog.setCancelable(true);
|
dialog.setCancelable(true);
|
||||||
dialog.setPositiveButton("Send", new DialogInterface.OnClickListener() {
|
dialog.setPositiveButton(R.string.send, new DialogInterface.OnClickListener() {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
initiateKeyExchange(context, masterSecret, recipient);
|
initiateKeyExchange(context, masterSecret, recipient);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dialog.setNegativeButton("Cancel", null);
|
dialog.setNegativeButton(R.string.cancel, null);
|
||||||
dialog.show();
|
dialog.show();
|
||||||
} else {
|
} else {
|
||||||
initiateKeyExchange(context, masterSecret, recipient);
|
initiateKeyExchange(context, masterSecret, recipient);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,24 +10,27 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.crypto;
|
package org.thoughtcrime.securesms.crypto;
|
||||||
|
|
||||||
import java.lang.ref.SoftReference;
|
import android.content.Context;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.database.MessageRecord;
|
import org.thoughtcrime.securesms.database.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
import org.thoughtcrime.securesms.protocol.Prefix;
|
import org.thoughtcrime.securesms.protocol.Prefix;
|
||||||
import org.thoughtcrime.securesms.util.InvalidMessageException;
|
import org.thoughtcrime.securesms.util.InvalidMessageException;
|
||||||
|
|
||||||
|
import java.lang.ref.SoftReference;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
public class MessageDisplayHelper {
|
public class MessageDisplayHelper {
|
||||||
|
|
||||||
private static final int MAX_CACHE_SIZE = 2000;
|
private static final int MAX_CACHE_SIZE = 2000;
|
||||||
|
|
||||||
private static final LinkedHashMap<String,SoftReference<String>> decryptedBodyCache = new LinkedHashMap<String,SoftReference<String>>() {
|
private static final LinkedHashMap<String,SoftReference<String>> decryptedBodyCache = new LinkedHashMap<String,SoftReference<String>>() {
|
||||||
@Override
|
@Override
|
||||||
protected boolean removeEldestEntry(Entry<String,SoftReference<String>> eldest) {
|
protected boolean removeEldestEntry(Entry<String,SoftReference<String>> eldest) {
|
||||||
@ -38,27 +41,27 @@ public class MessageDisplayHelper {
|
|||||||
private static boolean isUnreadableAsymmetricMessage(long type) {
|
private static boolean isUnreadableAsymmetricMessage(long type) {
|
||||||
return type == SmsDatabase.Types.FAILED_DECRYPT_TYPE;
|
return type == SmsDatabase.Types.FAILED_DECRYPT_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isInProcessAsymmetricMessage(String body, long type) {
|
private static boolean isInProcessAsymmetricMessage(String body, long type) {
|
||||||
return type == SmsDatabase.Types.DECRYPT_IN_PROGRESS_TYPE || (type == 0 && body.startsWith(Prefix.ASYMMETRIC_ENCRYPT)) || (type == 0 && body.startsWith(Prefix.ASYMMETRIC_LOCAL_ENCRYPT));
|
return type == SmsDatabase.Types.DECRYPT_IN_PROGRESS_TYPE || (type == 0 && body.startsWith(Prefix.ASYMMETRIC_ENCRYPT)) || (type == 0 && body.startsWith(Prefix.ASYMMETRIC_LOCAL_ENCRYPT));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isRogueAsymmetricMessage(long type) {
|
private static boolean isRogueAsymmetricMessage(long type) {
|
||||||
return type == SmsDatabase.Types.NO_SESSION_TYPE;
|
return type == SmsDatabase.Types.NO_SESSION_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isKeyExchange(String body) {
|
private static boolean isKeyExchange(String body) {
|
||||||
return body.startsWith(Prefix.KEY_EXCHANGE);
|
return body.startsWith(Prefix.KEY_EXCHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isProcessedKeyExchange(String body) {
|
private static boolean isProcessedKeyExchange(String body) {
|
||||||
return body.startsWith(Prefix.PROCESSED_KEY_EXCHANGE);
|
return body.startsWith(Prefix.PROCESSED_KEY_EXCHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isStaleKeyExchange(String body) {
|
private static boolean isStaleKeyExchange(String body) {
|
||||||
return body.startsWith(Prefix.STALE_KEY_EXCHANGE);
|
return body.startsWith(Prefix.STALE_KEY_EXCHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String checkCacheForBody(String body) {
|
private static String checkCacheForBody(String body) {
|
||||||
if (decryptedBodyCache.containsKey(body)) {
|
if (decryptedBodyCache.containsKey(body)) {
|
||||||
String decryptedBody = decryptedBodyCache.get(body).get();
|
String decryptedBody = decryptedBodyCache.get(body).get();
|
||||||
@ -67,16 +70,17 @@ public class MessageDisplayHelper {
|
|||||||
} else {
|
} else {
|
||||||
decryptedBodyCache.remove(body);
|
decryptedBodyCache.remove(body);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setDecryptedMessageBody(String body, MessageRecord message, MasterCipher bodyCipher) {
|
public static void setDecryptedMessageBody(Context context, String body,
|
||||||
|
MessageRecord message, MasterCipher bodyCipher)
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
if (body.startsWith(Prefix.SYMMETRIC_ENCRYPT)) {
|
if (body.startsWith(Prefix.SYMMETRIC_ENCRYPT)) {
|
||||||
String cacheResult = checkCacheForBody(body);
|
String cacheResult = checkCacheForBody(body);
|
||||||
if (cacheResult != null) {
|
if (cacheResult != null) {
|
||||||
body = cacheResult;
|
body = cacheResult;
|
||||||
@ -86,15 +90,15 @@ public class MessageDisplayHelper {
|
|||||||
body = decryptedBody;
|
body = decryptedBody;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUnreadableAsymmetricMessage(message.getType())) {
|
if (isUnreadableAsymmetricMessage(message.getType())) {
|
||||||
message.setBody("Bad encrypted message...");
|
message.setBody(context.getString(R.string.bad_encrypted_message));
|
||||||
message.setEmphasis(true);
|
message.setEmphasis(true);
|
||||||
} else if (isInProcessAsymmetricMessage(body, message.getType())) {
|
} else if (isInProcessAsymmetricMessage(body, message.getType())) {
|
||||||
message.setBody("Decrypting, please wait...");
|
message.setBody(context.getString(R.string.decrypting_please_wait));
|
||||||
message.setEmphasis(true);
|
message.setEmphasis(true);
|
||||||
} else if (isRogueAsymmetricMessage(message.getType())) {
|
} else if (isRogueAsymmetricMessage(message.getType())) {
|
||||||
message.setBody("Message encrypted for non-existent session...");
|
message.setBody(context.getString(R.string.message_encrypted_for_non_existing_session));
|
||||||
message.setEmphasis(true);
|
message.setEmphasis(true);
|
||||||
} else if (isKeyExchange(body)) {
|
} else if (isKeyExchange(body)) {
|
||||||
message.setKeyExchange(true);
|
message.setKeyExchange(true);
|
||||||
@ -111,11 +115,11 @@ public class MessageDisplayHelper {
|
|||||||
} else {
|
} else {
|
||||||
message.setBody(body);
|
message.setBody(body);
|
||||||
message.setEmphasis(false);
|
message.setEmphasis(false);
|
||||||
}
|
}
|
||||||
} catch (InvalidMessageException ime) {
|
} catch (InvalidMessageException ime) {
|
||||||
message.setBody("Decryption error: local message corrupted, MAC doesn't match. Potential tampering?");
|
message.setBody(context.getString(R.string.decryption_error_local_message_corrupted_mac_doesn_t_match_potential_tampering_question));
|
||||||
message.setEmphasis(true);
|
message.setEmphasis(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,25 +10,25 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.database;
|
package org.thoughtcrime.securesms.database;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteDatabase.CursorFactory;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
|
||||||
import android.database.sqlite.SQLiteDatabase.CursorFactory;
|
|
||||||
|
|
||||||
public class CanonicalAddressDatabase {
|
public class CanonicalAddressDatabase {
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = 1;
|
private static final int DATABASE_VERSION = 1;
|
||||||
@ -36,22 +36,22 @@ public class CanonicalAddressDatabase {
|
|||||||
private static final String TABLE = "canonical_addresses";
|
private static final String TABLE = "canonical_addresses";
|
||||||
private static final String ID_COLUMN = "_id";
|
private static final String ID_COLUMN = "_id";
|
||||||
private static final String ADDRESS_COLUMN = "address";
|
private static final String ADDRESS_COLUMN = "address";
|
||||||
|
|
||||||
private static final String DATABASE_CREATE = "CREATE TABLE " + TABLE + " (" + ID_COLUMN + " integer PRIMARY KEY, " + ADDRESS_COLUMN + " TEXT NOT NULL);";
|
private static final String DATABASE_CREATE = "CREATE TABLE " + TABLE + " (" + ID_COLUMN + " integer PRIMARY KEY, " + ADDRESS_COLUMN + " TEXT NOT NULL);";
|
||||||
private static final String[] ID_PROJECTION = {ID_COLUMN};
|
private static final String[] ID_PROJECTION = {ID_COLUMN};
|
||||||
private static final String SELECTION = "PHONE_NUMBERS_EQUAL(" + ADDRESS_COLUMN + ", ?)";
|
private static final String SELECTION = "PHONE_NUMBERS_EQUAL(" + ADDRESS_COLUMN + ", ?)";
|
||||||
private static final Object lock = new Object();
|
private static final Object lock = new Object();
|
||||||
|
|
||||||
private static CanonicalAddressDatabase instance;
|
private static CanonicalAddressDatabase instance;
|
||||||
private final DatabaseHelper databaseHelper;
|
private final DatabaseHelper databaseHelper;
|
||||||
private final HashMap<String,Long> addressCache = new HashMap<String,Long>();
|
private final HashMap<String,Long> addressCache = new HashMap<String,Long>();
|
||||||
private final Map<String,String> idCache = Collections.synchronizedMap(new HashMap<String,String>());
|
private final Map<String,String> idCache = Collections.synchronizedMap(new HashMap<String,String>());
|
||||||
|
|
||||||
public static CanonicalAddressDatabase getInstance(Context context) {
|
public static CanonicalAddressDatabase getInstance(Context context) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
if (instance == null)
|
if (instance == null)
|
||||||
instance = new CanonicalAddressDatabase(context);
|
instance = new CanonicalAddressDatabase(context);
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,71 +59,71 @@ public class CanonicalAddressDatabase {
|
|||||||
private CanonicalAddressDatabase(Context context) {
|
private CanonicalAddressDatabase(Context context) {
|
||||||
databaseHelper = new DatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
|
databaseHelper = new DatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAddressFromId(String id) {
|
public String getAddressFromId(String id) {
|
||||||
if (id == null || id.trim().equals("")) return "Anonymous";
|
if (id == null || id.trim().equals("")) return "Anonymous";
|
||||||
|
|
||||||
String cachedAddress = idCache.get(id);
|
String cachedAddress = idCache.get(id);
|
||||||
if (cachedAddress != null)
|
if (cachedAddress != null)
|
||||||
return cachedAddress;
|
return cachedAddress;
|
||||||
|
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
cursor = db.query(TABLE, null, ID_COLUMN + " = ?", new String[] {id+""}, null, null, null);
|
cursor = db.query(TABLE, null, ID_COLUMN + " = ?", new String[] {id+""}, null, null, null);
|
||||||
|
|
||||||
if (!cursor.moveToFirst())
|
if (!cursor.moveToFirst())
|
||||||
return "Anonymous";
|
return "Anonymous";
|
||||||
|
|
||||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS_COLUMN));
|
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS_COLUMN));
|
||||||
|
|
||||||
if (address == null || address.trim().equals("")) {
|
if (address == null || address.trim().equals("")) {
|
||||||
return "Anonymous";
|
return "Anonymous";
|
||||||
} else {
|
} else {
|
||||||
idCache.put(id, address);
|
idCache.put(id, address);
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null)
|
if (cursor != null)
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
databaseHelper.close();
|
databaseHelper.close();
|
||||||
instance = null;
|
instance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getCanonicalAddress(String address) {
|
public long getCanonicalAddress(String address) {
|
||||||
long canonicalAddress;
|
long canonicalAddress;
|
||||||
|
|
||||||
if ((canonicalAddress = getCanonicalAddressFromCache(address)) != -1)
|
if ((canonicalAddress = getCanonicalAddressFromCache(address)) != -1)
|
||||||
return canonicalAddress;
|
return canonicalAddress;
|
||||||
|
|
||||||
canonicalAddress = getCanonicalAddressFromDatabase(address);
|
canonicalAddress = getCanonicalAddressFromDatabase(address);
|
||||||
addressCache.put(address, canonicalAddress);
|
addressCache.put(address, canonicalAddress);
|
||||||
|
|
||||||
return canonicalAddress;
|
return canonicalAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> getCanonicalAddresses(List<String> addresses) {
|
public List<Long> getCanonicalAddresses(List<String> addresses) {
|
||||||
List<Long> addressList = new LinkedList<Long>();
|
List<Long> addressList = new LinkedList<Long>();
|
||||||
|
|
||||||
for (String address : addresses) {
|
for (String address : addresses) {
|
||||||
addressList.add(getCanonicalAddress(address));
|
addressList.add(getCanonicalAddress(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
return addressList;
|
return addressList;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getCanonicalAddressFromCache(String address) {
|
private long getCanonicalAddressFromCache(String address) {
|
||||||
if (addressCache.containsKey(address))
|
if (addressCache.containsKey(address))
|
||||||
return new Long(addressCache.get(address));
|
return new Long(addressCache.get(address));
|
||||||
|
|
||||||
return -1L;
|
return -1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getCanonicalAddressFromDatabase(String address) {
|
private long getCanonicalAddressFromDatabase(String address) {
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
try {
|
try {
|
||||||
@ -132,21 +132,21 @@ public class CanonicalAddressDatabase {
|
|||||||
cursor = db.query(TABLE, ID_PROJECTION, SELECTION, selectionArguments, null, null, null);
|
cursor = db.query(TABLE, ID_PROJECTION, SELECTION, selectionArguments, null, null, null);
|
||||||
|
|
||||||
if (cursor.getCount() == 0 || !cursor.moveToFirst()) {
|
if (cursor.getCount() == 0 || !cursor.moveToFirst()) {
|
||||||
ContentValues contentValues = new ContentValues(1);
|
ContentValues contentValues = new ContentValues(1);
|
||||||
contentValues.put(ADDRESS_COLUMN, address);
|
contentValues.put(ADDRESS_COLUMN, address);
|
||||||
|
|
||||||
return db.insert(TABLE, ADDRESS_COLUMN, contentValues);
|
return db.insert(TABLE, ADDRESS_COLUMN, contentValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cursor.getLong(cursor.getColumnIndexOrThrow(ID_COLUMN));
|
return cursor.getLong(cursor.getColumnIndexOrThrow(ID_COLUMN));
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DatabaseHelper extends SQLiteOpenHelper {
|
private static class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
public DatabaseHelper(Context context, String name, CursorFactory factory, int version) {
|
public DatabaseHelper(Context context, String name, CursorFactory factory, int version) {
|
||||||
@ -161,6 +161,6 @@ public class CanonicalAddressDatabase {
|
|||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,36 +10,36 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.database;
|
package org.thoughtcrime.securesms.database;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
public class CanonicalSessionMigrator {
|
public class CanonicalSessionMigrator {
|
||||||
|
|
||||||
private static void migrateSession(File sessionFile, File sessionsDirectory, long canonicalAddress) {
|
private static void migrateSession(File sessionFile, File sessionsDirectory, long canonicalAddress) {
|
||||||
File canonicalSessionFile = new File(sessionsDirectory.getAbsolutePath() + File.separatorChar + canonicalAddress);
|
File canonicalSessionFile = new File(sessionsDirectory.getAbsolutePath() + File.separatorChar + canonicalAddress);
|
||||||
sessionFile.renameTo(canonicalSessionFile);
|
sessionFile.renameTo(canonicalSessionFile);
|
||||||
Log.w("CanonicalSessionMigrator", "Moving: " + sessionFile.toString() + " to " + canonicalSessionFile.toString());
|
Log.w("CanonicalSessionMigrator", "Moving: " + sessionFile.toString() + " to " + canonicalSessionFile.toString());
|
||||||
|
|
||||||
File canonicalSessionFileLocal = new File(sessionsDirectory.getAbsolutePath() + File.separatorChar + canonicalAddress + "-local");
|
File canonicalSessionFileLocal = new File(sessionsDirectory.getAbsolutePath() + File.separatorChar + canonicalAddress + "-local");
|
||||||
File localFile = new File(sessionFile.getAbsolutePath() + "-local");
|
File localFile = new File(sessionFile.getAbsolutePath() + "-local");
|
||||||
if (localFile.exists())
|
if (localFile.exists())
|
||||||
localFile.renameTo(canonicalSessionFileLocal);
|
localFile.renameTo(canonicalSessionFileLocal);
|
||||||
|
|
||||||
Log.w("CanonicalSessionMigrator", "Moving " + localFile + " to " + canonicalSessionFileLocal);
|
Log.w("CanonicalSessionMigrator", "Moving " + localFile + " to " + canonicalSessionFileLocal);
|
||||||
|
|
||||||
File canonicalSessionFileRemote = new File(sessionsDirectory.getAbsolutePath() + File.separatorChar + canonicalAddress + "-remote");
|
File canonicalSessionFileRemote = new File(sessionsDirectory.getAbsolutePath() + File.separatorChar + canonicalAddress + "-remote");
|
||||||
File remoteFile = new File(sessionFile.getAbsolutePath() + "-remote");
|
File remoteFile = new File(sessionFile.getAbsolutePath() + "-remote");
|
||||||
if (remoteFile.exists())
|
if (remoteFile.exists())
|
||||||
remoteFile.renameTo(canonicalSessionFileRemote);
|
remoteFile.renameTo(canonicalSessionFileRemote);
|
||||||
|
|
||||||
Log.w("CanonicalSessionMigrator", "Moving " + remoteFile + " to " + canonicalSessionFileRemote);
|
Log.w("CanonicalSessionMigrator", "Moving " + remoteFile + " to " + canonicalSessionFileRemote);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -47,24 +47,24 @@ public class CanonicalSessionMigrator {
|
|||||||
public static void migrateSessions(Context context) {
|
public static void migrateSessions(Context context) {
|
||||||
if (context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).getBoolean("canonicalized", false))
|
if (context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).getBoolean("canonicalized", false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CanonicalAddressDatabase canonicalDb = CanonicalAddressDatabase.getInstance(context);
|
CanonicalAddressDatabase canonicalDb = CanonicalAddressDatabase.getInstance(context);
|
||||||
File rootDirectory = context.getFilesDir();
|
File rootDirectory = context.getFilesDir();
|
||||||
File sessionsDirectory = new File(rootDirectory.getAbsolutePath() + File.separatorChar + "sessions");
|
File sessionsDirectory = new File(rootDirectory.getAbsolutePath() + File.separatorChar + "sessions");
|
||||||
sessionsDirectory.mkdir();
|
sessionsDirectory.mkdir();
|
||||||
|
|
||||||
String[] files = rootDirectory.list();
|
String[] files = rootDirectory.list();
|
||||||
|
|
||||||
for (int i=0;i<files.length;i++) {
|
for (int i=0;i<files.length;i++) {
|
||||||
File item = new File(rootDirectory.getAbsolutePath() + File.separatorChar + files[i]);
|
File item = new File(rootDirectory.getAbsolutePath() + File.separatorChar + files[i]);
|
||||||
|
|
||||||
if (!item.isDirectory() && files[i].matches("[0-9]+")) {
|
if (!item.isDirectory() && files[i].matches("[0-9]+")) {
|
||||||
long canonicalAddress = canonicalDb.getCanonicalAddress(files[i]);
|
long canonicalAddress = canonicalDb.getCanonicalAddress(files[i]);
|
||||||
migrateSession(item, sessionsDirectory, canonicalAddress);
|
migrateSession(item, sessionsDirectory, canonicalAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).edit().putBoolean("canonicalized", true).commit();
|
context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).edit().putBoolean("canonicalized", true).commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,17 +10,14 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.database;
|
package org.thoughtcrime.securesms.database;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import android.content.Context;
|
||||||
import java.io.FileNotFoundException;
|
import android.util.Log;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||||
import org.thoughtcrime.securesms.crypto.KeyPair;
|
import org.thoughtcrime.securesms.crypto.KeyPair;
|
||||||
@ -28,41 +25,43 @@ import org.thoughtcrime.securesms.crypto.KeyUtil;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.Hex;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import java.io.FileInputStream;
|
||||||
import android.util.Log;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
|
||||||
public class LocalKeyRecord extends Record {
|
public class LocalKeyRecord extends Record {
|
||||||
|
|
||||||
private static final Object FILE_LOCK = new Object();
|
private static final Object FILE_LOCK = new Object();
|
||||||
|
|
||||||
private KeyPair localCurrentKeyPair;
|
private KeyPair localCurrentKeyPair;
|
||||||
private KeyPair localNextKeyPair;
|
private KeyPair localNextKeyPair;
|
||||||
|
|
||||||
private final MasterCipher masterCipher;
|
private final MasterCipher masterCipher;
|
||||||
private final MasterSecret masterSecret;
|
private final MasterSecret masterSecret;
|
||||||
|
|
||||||
public LocalKeyRecord(Context context, MasterSecret masterSecret, Recipient recipient) {
|
public LocalKeyRecord(Context context, MasterSecret masterSecret, Recipient recipient) {
|
||||||
super(context, getFileNameForRecipient(context, recipient));
|
super(context, getFileNameForRecipient(context, recipient));
|
||||||
this.masterSecret = masterSecret;
|
this.masterSecret = masterSecret;
|
||||||
this.masterCipher = new MasterCipher(masterSecret);
|
this.masterCipher = new MasterCipher(masterSecret);
|
||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasRecord(Context context, Recipient recipient) {
|
public static boolean hasRecord(Context context, Recipient recipient) {
|
||||||
Log.w("LocalKeyRecord", "Checking: " + getFileNameForRecipient(context, recipient));
|
Log.w("LocalKeyRecord", "Checking: " + getFileNameForRecipient(context, recipient));
|
||||||
return Record.hasRecord(context, getFileNameForRecipient(context, recipient));
|
return Record.hasRecord(context, getFileNameForRecipient(context, recipient));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void delete(Context context, Recipient recipient) {
|
public static void delete(Context context, Recipient recipient) {
|
||||||
Record.delete(context, getFileNameForRecipient(context, recipient));
|
Record.delete(context, getFileNameForRecipient(context, recipient));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getFileNameForRecipient(Context context, Recipient recipient) {
|
private static String getFileNameForRecipient(Context context, Recipient recipient) {
|
||||||
return CanonicalAddressDatabase.getInstance(context).getCanonicalAddress(recipient.getNumber()) + "-local";
|
return CanonicalAddressDatabase.getInstance(context).getCanonicalAddress(recipient.getNumber()) + "-local";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void advanceKeyIfNecessary(int keyId) {
|
public void advanceKeyIfNecessary(int keyId) {
|
||||||
Log.w("LocalKeyRecord", "Remote client acknowledges receiving key id: " + keyId);
|
Log.w("LocalKeyRecord", "Remote client acknowledges receiving key id: " + keyId);
|
||||||
if (keyId == localNextKeyPair.getId()) {
|
if (keyId == localNextKeyPair.getId()) {
|
||||||
@ -70,77 +69,77 @@ public class LocalKeyRecord extends Record {
|
|||||||
this.localNextKeyPair = new KeyPair(this.localNextKeyPair.getId()+1, KeyUtil.generateKeyPair(), masterSecret);
|
this.localNextKeyPair = new KeyPair(this.localNextKeyPair.getId()+1, KeyUtil.generateKeyPair(), masterSecret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentKeyPair(KeyPair localCurrentKeyPair) {
|
public void setCurrentKeyPair(KeyPair localCurrentKeyPair) {
|
||||||
this.localCurrentKeyPair = localCurrentKeyPair;
|
this.localCurrentKeyPair = localCurrentKeyPair;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNextKeyPair(KeyPair localNextKeyPair) {
|
public void setNextKeyPair(KeyPair localNextKeyPair) {
|
||||||
this.localNextKeyPair = localNextKeyPair;
|
this.localNextKeyPair = localNextKeyPair;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyPair getCurrentKeyPair() {
|
public KeyPair getCurrentKeyPair() {
|
||||||
return this.localCurrentKeyPair;
|
return this.localCurrentKeyPair;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyPair getNextKeyPair() {
|
public KeyPair getNextKeyPair() {
|
||||||
return this.localNextKeyPair;
|
return this.localNextKeyPair;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyPair getKeyPairForId(int id) throws InvalidKeyIdException {
|
public KeyPair getKeyPairForId(int id) throws InvalidKeyIdException {
|
||||||
if (this.localCurrentKeyPair.getId() == id) return this.localCurrentKeyPair;
|
if (this.localCurrentKeyPair.getId() == id) return this.localCurrentKeyPair;
|
||||||
else if (this.localNextKeyPair.getId() == id) return this.localNextKeyPair;
|
else if (this.localNextKeyPair.getId() == id) return this.localNextKeyPair;
|
||||||
else throw new InvalidKeyIdException("No local key for ID: " + id);
|
else throw new InvalidKeyIdException("No local key for ID: " + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
synchronized (FILE_LOCK) {
|
synchronized (FILE_LOCK) {
|
||||||
try {
|
try {
|
||||||
RandomAccessFile file = openRandomAccessFile();
|
RandomAccessFile file = openRandomAccessFile();
|
||||||
FileChannel out = file.getChannel();
|
FileChannel out = file.getChannel();
|
||||||
out.position(0);
|
out.position(0);
|
||||||
|
|
||||||
writeKeyPair(localCurrentKeyPair, out);
|
writeKeyPair(localCurrentKeyPair, out);
|
||||||
writeKeyPair(localNextKeyPair, out);
|
writeKeyPair(localNextKeyPair, out);
|
||||||
|
|
||||||
out.force(true);
|
out.force(true);
|
||||||
out.truncate(out.position());
|
out.truncate(out.position());
|
||||||
out.close();
|
out.close();
|
||||||
file.close();
|
file.close();
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.w("keyrecord", ioe);
|
Log.w("keyrecord", ioe);
|
||||||
// XXX
|
// XXX
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadData() {
|
private void loadData() {
|
||||||
Log.w("LocalKeyRecord", "Loading local key record...");
|
Log.w("LocalKeyRecord", "Loading local key record...");
|
||||||
synchronized (FILE_LOCK) {
|
synchronized (FILE_LOCK) {
|
||||||
try {
|
try {
|
||||||
FileInputStream in = this.openInputStream();
|
FileInputStream in = this.openInputStream();
|
||||||
localCurrentKeyPair = readKeyPair(in);
|
localCurrentKeyPair = readKeyPair(in);
|
||||||
localNextKeyPair = readKeyPair(in);
|
localNextKeyPair = readKeyPair(in);
|
||||||
in.close();
|
in.close();
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Log.w("LocalKeyRecord", "No local keypair set found.");
|
Log.w("LocalKeyRecord", "No local keypair set found.");
|
||||||
return;
|
return;
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.w("keyrecord", ioe);
|
Log.w("keyrecord", ioe);
|
||||||
// XXX
|
// XXX
|
||||||
} catch (InvalidKeyException ike) {
|
} catch (InvalidKeyException ike) {
|
||||||
Log.w("LocalKeyRecord", ike);
|
Log.w("LocalKeyRecord", ike);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeKeyPair(KeyPair keyPair, FileChannel out) throws IOException {
|
private void writeKeyPair(KeyPair keyPair, FileChannel out) throws IOException {
|
||||||
byte[] keyPairBytes = keyPair.toBytes();
|
byte[] keyPairBytes = keyPair.toBytes();
|
||||||
writeBlob(keyPairBytes, out);
|
writeBlob(keyPairBytes, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeyPair readKeyPair(FileInputStream in) throws IOException, InvalidKeyException {
|
private KeyPair readKeyPair(FileInputStream in) throws IOException, InvalidKeyException {
|
||||||
byte[] keyPairBytes = readBlob(in);
|
byte[] keyPairBytes = readBlob(in);
|
||||||
return new KeyPair(keyPairBytes, masterCipher);
|
return new KeyPair(keyPairBytes, masterCipher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,16 +10,21 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.database;
|
package org.thoughtcrime.securesms.database;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import android.content.ContentValues;
|
||||||
import java.util.HashSet;
|
import android.content.Context;
|
||||||
import java.util.Set;
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
@ -34,16 +39,13 @@ import ws.com.google.android.mms.pdu.PduBody;
|
|||||||
import ws.com.google.android.mms.pdu.PduHeaders;
|
import ws.com.google.android.mms.pdu.PduHeaders;
|
||||||
import ws.com.google.android.mms.pdu.RetrieveConf;
|
import ws.com.google.android.mms.pdu.RetrieveConf;
|
||||||
import ws.com.google.android.mms.pdu.SendReq;
|
import ws.com.google.android.mms.pdu.SendReq;
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
import java.io.UnsupportedEncodingException;
|
||||||
import android.database.Cursor;
|
import java.util.HashSet;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import java.util.Set;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
public class MmsDatabase extends Database {
|
public class MmsDatabase extends Database {
|
||||||
|
|
||||||
public static final String TABLE_NAME = "mms";
|
public static final String TABLE_NAME = "mms";
|
||||||
public static final String ID = "_id";
|
public static final String ID = "_id";
|
||||||
private static final String THREAD_ID = "thread_id";
|
private static final String THREAD_ID = "thread_id";
|
||||||
@ -74,7 +76,7 @@ public class MmsDatabase extends Database {
|
|||||||
private static final String RESPONSE_TEXT = "resp_txt";
|
private static final String RESPONSE_TEXT = "resp_txt";
|
||||||
private static final String DELIVERY_TIME = "d_tm";
|
private static final String DELIVERY_TIME = "d_tm";
|
||||||
private static final String DELIVERY_REPORT = "d_rpt";
|
private static final String DELIVERY_REPORT = "d_rpt";
|
||||||
|
|
||||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " +
|
||||||
THREAD_ID + " INTEGER, " + DATE + " INTEGER, " + MESSAGE_BOX + " INTEGER, " +
|
THREAD_ID + " INTEGER, " + DATE + " INTEGER, " + MESSAGE_BOX + " INTEGER, " +
|
||||||
READ + " INTEGER DEFAULT 0, " + MESSAGE_ID + " TEXT, " + SUBJECT + " TEXT, " +
|
READ + " INTEGER DEFAULT 0, " + MESSAGE_ID + " TEXT, " + SUBJECT + " TEXT, " +
|
||||||
@ -83,21 +85,21 @@ public class MmsDatabase extends Database {
|
|||||||
MMS_VERSION + " INTEGER, " + MESSAGE_SIZE + " INTEGER, " + PRIORITY + " INTEGER, " +
|
MMS_VERSION + " INTEGER, " + MESSAGE_SIZE + " INTEGER, " + PRIORITY + " INTEGER, " +
|
||||||
READ_REPORT + " INTEGER, " + REPORT_ALLOWED + " INTEGER, " + RESPONSE_STATUS + " INTEGER, " +
|
READ_REPORT + " INTEGER, " + REPORT_ALLOWED + " INTEGER, " + RESPONSE_STATUS + " INTEGER, " +
|
||||||
STATUS + " INTEGER, " + TRANSACTION_ID + " TEXT, " + RETRIEVE_STATUS + " INTEGER, " +
|
STATUS + " INTEGER, " + TRANSACTION_ID + " TEXT, " + RETRIEVE_STATUS + " INTEGER, " +
|
||||||
RETRIEVE_TEXT + " TEXT, " + RETRIEVE_TEXT_CS + " INTEGER, " + READ_STATUS + " INTEGER, " +
|
RETRIEVE_TEXT + " TEXT, " + RETRIEVE_TEXT_CS + " INTEGER, " + READ_STATUS + " INTEGER, " +
|
||||||
CONTENT_CLASS + " INTEGER, " + RESPONSE_TEXT + " TEXT, " + DELIVERY_TIME + " INTEGER, " +
|
CONTENT_CLASS + " INTEGER, " + RESPONSE_TEXT + " TEXT, " + DELIVERY_TIME + " INTEGER, " +
|
||||||
DELIVERY_REPORT + " INTEGER);";
|
DELIVERY_REPORT + " INTEGER);";
|
||||||
|
|
||||||
public MmsDatabase(Context context, SQLiteOpenHelper databaseHelper) {
|
public MmsDatabase(Context context, SQLiteOpenHelper databaseHelper) {
|
||||||
super(context, databaseHelper);
|
super(context, databaseHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMessageCountForThread(long threadId) {
|
public int getMessageCountForThread(long threadId) {
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = db.query(TABLE_NAME, new String[] {"COUNT(*)"}, THREAD_ID + " = ?", new String[] {threadId+""}, null, null, null);
|
cursor = db.query(TABLE_NAME, new String[] {"COUNT(*)"}, THREAD_ID + " = ?", new String[] {threadId+""}, null, null, null);
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToFirst())
|
if (cursor != null && cursor.moveToFirst())
|
||||||
return cursor.getInt(0);
|
return cursor.getInt(0);
|
||||||
} finally {
|
} finally {
|
||||||
@ -107,14 +109,14 @@ public class MmsDatabase extends Database {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getThreadIdForMessage(long id) {
|
public long getThreadIdForMessage(long id) {
|
||||||
String sql = "SELECT " + THREAD_ID + " FROM " + TABLE_NAME + " WHERE " + ID + " = ?";
|
String sql = "SELECT " + THREAD_ID + " FROM " + TABLE_NAME + " WHERE " + ID + " = ?";
|
||||||
String[] sqlArgs = new String[] {id+""};
|
String[] sqlArgs = new String[] {id+""};
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
|
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = db.rawQuery(sql, sqlArgs);
|
cursor = db.rawQuery(sql, sqlArgs);
|
||||||
if (cursor != null && cursor.moveToFirst())
|
if (cursor != null && cursor.moveToFirst())
|
||||||
@ -126,8 +128,8 @@ public class MmsDatabase extends Database {
|
|||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getThreadIdForHeaders(PduHeaders headers) throws RecipientFormattingException {
|
private long getThreadIdForHeaders(PduHeaders headers) throws RecipientFormattingException {
|
||||||
try {
|
try {
|
||||||
EncodedStringValue encodedString = headers.getEncodedStringValue(PduHeaders.FROM);
|
EncodedStringValue encodedString = headers.getEncodedStringValue(PduHeaders.FROM);
|
||||||
String fromString = new String(encodedString.getTextString(), CharacterSets.MIMENAME_ISO_8859_1);
|
String fromString = new String(encodedString.getTextString(), CharacterSets.MIMENAME_ISO_8859_1);
|
||||||
@ -137,28 +139,28 @@ public class MmsDatabase extends Database {
|
|||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessageRecipient(long messageId) {
|
public String getMessageRecipient(long messageId) {
|
||||||
try {
|
try {
|
||||||
PduHeaders headers = new PduHeaders();
|
PduHeaders headers = new PduHeaders();
|
||||||
MmsAddressDatabase database = DatabaseFactory.getMmsAddressDatabase(context);
|
MmsAddressDatabase database = DatabaseFactory.getMmsAddressDatabase(context);
|
||||||
database.getAddressesForId(messageId, headers);
|
database.getAddressesForId(messageId, headers);
|
||||||
|
|
||||||
EncodedStringValue encodedFrom = headers.getEncodedStringValue(PduHeaders.FROM);
|
EncodedStringValue encodedFrom = headers.getEncodedStringValue(PduHeaders.FROM);
|
||||||
if (encodedFrom != null)
|
if (encodedFrom != null)
|
||||||
return new String(encodedFrom.getTextString(), CharacterSets.MIMENAME_ISO_8859_1);
|
return new String(encodedFrom.getTextString(), CharacterSets.MIMENAME_ISO_8859_1);
|
||||||
else
|
else
|
||||||
return "Anonymous";
|
return context.getString(R.string.anonymous);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateResponseStatus(long messageId, int status) {
|
public void updateResponseStatus(long messageId, int status) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(RESPONSE_STATUS, status);
|
contentValues.put(RESPONSE_STATUS, status);
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,73 +168,73 @@ public class MmsDatabase extends Database {
|
|||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_SENT_FAILED);
|
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_SENT_FAILED);
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[]{messageId+""});
|
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[]{messageId+""});
|
||||||
notifyConversationListeners(getThreadIdForMessage(messageId));
|
notifyConversationListeners(getThreadIdForMessage(messageId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markAsSent(long messageId, byte[] mmsId, long status) {
|
public void markAsSent(long messageId, byte[] mmsId, long status) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(RESPONSE_STATUS, status);
|
contentValues.put(RESPONSE_STATUS, status);
|
||||||
contentValues.put(MESSAGE_ID, new String(mmsId));
|
contentValues.put(MESSAGE_ID, new String(mmsId));
|
||||||
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_SENT);
|
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_SENT);
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
||||||
notifyConversationListeners(getThreadIdForMessage(messageId));
|
notifyConversationListeners(getThreadIdForMessage(messageId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markAsSecureSent(long messageId, byte[] mmsId, long status) {
|
public void markAsSecureSent(long messageId, byte[] mmsId, long status) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(RESPONSE_STATUS, status);
|
contentValues.put(RESPONSE_STATUS, status);
|
||||||
contentValues.put(MESSAGE_ID, new String(mmsId));
|
contentValues.put(MESSAGE_ID, new String(mmsId));
|
||||||
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_SECURE_SENT);
|
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_SECURE_SENT);
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
||||||
notifyConversationListeners(getThreadIdForMessage(messageId));
|
notifyConversationListeners(getThreadIdForMessage(messageId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markDownloadState(long messageId, long state) {
|
public void markDownloadState(long messageId, long state) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(STATUS, state);
|
contentValues.put(STATUS, state);
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
||||||
notifyConversationListeners(getThreadIdForMessage(messageId));
|
notifyConversationListeners(getThreadIdForMessage(messageId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markAsNoSession(long messageId, long threadId) {
|
public void markAsNoSession(long messageId, long threadId) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_NO_SESSION_INBOX);
|
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_NO_SESSION_INBOX);
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markAsDecryptFailed(long messageId, long threadId) {
|
public void markAsDecryptFailed(long messageId, long threadId) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_DECRYPT_FAILED_INBOX);
|
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_DECRYPT_FAILED_INBOX);
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMessagesRead(long threadId) {
|
public void setMessagesRead(long threadId) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(READ, 1);
|
contentValues.put(READ, 1);
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, THREAD_ID + " = ?", new String[] {threadId+""});
|
database.update(TABLE_NAME, contentValues, THREAD_ID + " = ?", new String[] {threadId+""});
|
||||||
}
|
}
|
||||||
|
|
||||||
public NotificationInd getNotificationMessage(long messageId) throws MmsException {
|
public NotificationInd getNotificationMessage(long messageId) throws MmsException {
|
||||||
PduHeaders headers = getHeadersForId(messageId);
|
PduHeaders headers = getHeadersForId(messageId);
|
||||||
return new NotificationInd(headers);
|
return new NotificationInd(headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MultimediaMessagePdu getMediaMessage(long messageId) throws MmsException {
|
public MultimediaMessagePdu getMediaMessage(long messageId) throws MmsException {
|
||||||
PduHeaders headers = getHeadersForId(messageId);
|
PduHeaders headers = getHeadersForId(messageId);
|
||||||
PartDatabase partDatabase = getPartDatabase();
|
PartDatabase partDatabase = getPartDatabase();
|
||||||
@ -240,7 +242,7 @@ public class MmsDatabase extends Database {
|
|||||||
|
|
||||||
return new MultimediaMessagePdu(headers, body);
|
return new MultimediaMessagePdu(headers, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SendReq getSendRequest(long messageId) throws MmsException {
|
public SendReq getSendRequest(long messageId) throws MmsException {
|
||||||
PduHeaders headers = getHeadersForId(messageId);
|
PduHeaders headers = getHeadersForId(messageId);
|
||||||
PartDatabase partDatabase = getPartDatabase();
|
PartDatabase partDatabase = getPartDatabase();
|
||||||
@ -248,26 +250,26 @@ public class MmsDatabase extends Database {
|
|||||||
|
|
||||||
return new SendReq(headers, body, messageId, headers.getMessageBox());
|
return new SendReq(headers, body, messageId, headers.getMessageBox());
|
||||||
}
|
}
|
||||||
|
|
||||||
public SendReq[] getOutgoingMessages() throws MmsException {
|
public SendReq[] getOutgoingMessages() throws MmsException {
|
||||||
MmsAddressDatabase addr = DatabaseFactory.getMmsAddressDatabase(context);
|
MmsAddressDatabase addr = DatabaseFactory.getMmsAddressDatabase(context);
|
||||||
PartDatabase parts = getPartDatabase();
|
PartDatabase parts = getPartDatabase();
|
||||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = database.query(TABLE_NAME, null, MESSAGE_BOX + " = ? OR " + MESSAGE_BOX + " = ?", new String[] {Types.MESSAGE_BOX_OUTBOX+"", Types.MESSAGE_BOX_SECURE_OUTBOX+""}, null, null, null);
|
cursor = database.query(TABLE_NAME, null, MESSAGE_BOX + " = ? OR " + MESSAGE_BOX + " = ?", new String[] {Types.MESSAGE_BOX_OUTBOX+"", Types.MESSAGE_BOX_SECURE_OUTBOX+""}, null, null, null);
|
||||||
|
|
||||||
if (cursor == null || cursor.getCount() == 0)
|
if (cursor == null || cursor.getCount() == 0)
|
||||||
return new SendReq[0];
|
return new SendReq[0];
|
||||||
|
|
||||||
SendReq[] requests = new SendReq[cursor.getCount()];
|
SendReq[] requests = new SendReq[cursor.getCount()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||||
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
|
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
|
||||||
PduHeaders headers = getHeadersFromCursor(cursor);
|
PduHeaders headers = getHeadersFromCursor(cursor);
|
||||||
addr.getAddressesForId(messageId, headers);
|
addr.getAddressesForId(messageId, headers);
|
||||||
PduBody body = parts.getParts(messageId, true);
|
PduBody body = parts.getParts(messageId, true);
|
||||||
requests[i++] = new SendReq(headers, body, messageId, outboxType);
|
requests[i++] = new SendReq(headers, body, messageId, outboxType);
|
||||||
@ -277,34 +279,34 @@ public class MmsDatabase extends Database {
|
|||||||
} finally {
|
} finally {
|
||||||
if (cursor != null)
|
if (cursor != null)
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertMessageReceived(MultimediaMessagePdu retrieved, String contentLocation, long threadId, long mailbox) throws MmsException {
|
private long insertMessageReceived(MultimediaMessagePdu retrieved, String contentLocation, long threadId, long mailbox) throws MmsException {
|
||||||
PduHeaders headers = retrieved.getPduHeaders();
|
PduHeaders headers = retrieved.getPduHeaders();
|
||||||
ContentValues contentValues = getContentValuesFromHeader(headers);
|
ContentValues contentValues = getContentValuesFromHeader(headers);
|
||||||
|
|
||||||
contentValues.put(MESSAGE_BOX, mailbox);
|
contentValues.put(MESSAGE_BOX, mailbox);
|
||||||
contentValues.put(THREAD_ID, threadId);
|
contentValues.put(THREAD_ID, threadId);
|
||||||
contentValues.put(CONTENT_LOCATION, contentLocation);
|
contentValues.put(CONTENT_LOCATION, contentLocation);
|
||||||
contentValues.put(STATUS, Types.DOWNLOAD_INITIALIZED);
|
contentValues.put(STATUS, Types.DOWNLOAD_INITIALIZED);
|
||||||
|
|
||||||
long messageId = insertMediaMessage(retrieved, contentValues);
|
long messageId = insertMediaMessage(retrieved, contentValues);
|
||||||
return messageId;
|
return messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long insertMessageReceived(RetrieveConf retrieved, String contentLocation, long threadId) throws MmsException {
|
public long insertMessageReceived(RetrieveConf retrieved, String contentLocation, long threadId) throws MmsException {
|
||||||
return insertMessageReceived(retrieved, contentLocation, threadId, Types.MESSAGE_BOX_INBOX);
|
return insertMessageReceived(retrieved, contentLocation, threadId, Types.MESSAGE_BOX_INBOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long insertSecureMessageReceived(RetrieveConf retrieved, String contentLocation, long threadId) throws MmsException {
|
public long insertSecureMessageReceived(RetrieveConf retrieved, String contentLocation, long threadId) throws MmsException {
|
||||||
return insertMessageReceived(retrieved, contentLocation, threadId, Types.MESSAGE_BOX_DECRYPTING_INBOX);
|
return insertMessageReceived(retrieved, contentLocation, threadId, Types.MESSAGE_BOX_DECRYPTING_INBOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long insertSecureDecryptedMessageReceived(MultimediaMessagePdu retrieved, long threadId) throws MmsException {
|
public long insertSecureDecryptedMessageReceived(MultimediaMessagePdu retrieved, long threadId) throws MmsException {
|
||||||
return insertMessageReceived(retrieved, "", threadId, Types.MESSAGE_BOX_SECURE_INBOX);
|
return insertMessageReceived(retrieved, "", threadId, Types.MESSAGE_BOX_SECURE_INBOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long insertMessageReceived(NotificationInd notification) {
|
public long insertMessageReceived(NotificationInd notification) {
|
||||||
try {
|
try {
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
@ -312,47 +314,47 @@ public class MmsDatabase extends Database {
|
|||||||
ContentValues contentValues = getContentValuesFromHeader(headers);
|
ContentValues contentValues = getContentValuesFromHeader(headers);
|
||||||
long threadId = getThreadIdForHeaders(headers);
|
long threadId = getThreadIdForHeaders(headers);
|
||||||
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||||
|
|
||||||
Log.w("MmsDatabse", "Message received type: " + headers.getOctet(PduHeaders.MESSAGE_TYPE));
|
Log.w("MmsDatabse", "Message received type: " + headers.getOctet(PduHeaders.MESSAGE_TYPE));
|
||||||
|
|
||||||
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_INBOX);
|
contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_INBOX);
|
||||||
contentValues.put(THREAD_ID, threadId);
|
contentValues.put(THREAD_ID, threadId);
|
||||||
contentValues.put(STATUS, Types.DOWNLOAD_INITIALIZED);
|
contentValues.put(STATUS, Types.DOWNLOAD_INITIALIZED);
|
||||||
if (!contentValues.containsKey(DATE))
|
if (!contentValues.containsKey(DATE))
|
||||||
contentValues.put(DATE, System.currentTimeMillis() / 1000);
|
contentValues.put(DATE, System.currentTimeMillis() / 1000);
|
||||||
|
|
||||||
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
||||||
addressDatabase.insertAddressesForId(messageId, headers);
|
addressDatabase.insertAddressesForId(messageId, headers);
|
||||||
|
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
||||||
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
||||||
|
|
||||||
return messageId;
|
return messageId;
|
||||||
} catch (RecipientFormattingException rfe) {
|
} catch (RecipientFormattingException rfe) {
|
||||||
Log.w("MmsDatabase", rfe);
|
Log.w("MmsDatabase", rfe);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long insertMessageSent(SendReq sendRequest, long threadId, boolean isSecure) throws MmsException {
|
public long insertMessageSent(SendReq sendRequest, long threadId, boolean isSecure) throws MmsException {
|
||||||
PduHeaders headers = sendRequest.getPduHeaders();
|
PduHeaders headers = sendRequest.getPduHeaders();
|
||||||
ContentValues contentValues = getContentValuesFromHeader(headers);
|
ContentValues contentValues = getContentValuesFromHeader(headers);
|
||||||
|
|
||||||
if (!isSecure) contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_OUTBOX);
|
if (!isSecure) contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_OUTBOX);
|
||||||
else contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_SECURE_OUTBOX);
|
else contentValues.put(MESSAGE_BOX, Types.MESSAGE_BOX_SECURE_OUTBOX);
|
||||||
|
|
||||||
contentValues.put(THREAD_ID, threadId);
|
contentValues.put(THREAD_ID, threadId);
|
||||||
contentValues.put(READ, 1);
|
contentValues.put(READ, 1);
|
||||||
|
|
||||||
long messageId = insertMediaMessage(sendRequest, contentValues);
|
long messageId = insertMediaMessage(sendRequest, contentValues);
|
||||||
DatabaseFactory.getThreadDatabase(context).setRead(threadId);
|
DatabaseFactory.getThreadDatabase(context).setRead(threadId);
|
||||||
return messageId;
|
return messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertMediaMessage(MultimediaMessagePdu message, ContentValues contentValues) throws MmsException {
|
private long insertMediaMessage(MultimediaMessagePdu message, ContentValues contentValues) throws MmsException {
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
||||||
PduBody body = message.getBody();
|
PduBody body = message.getBody();
|
||||||
PartDatabase partsDatabase = getPartDatabase();
|
PartDatabase partsDatabase = getPartDatabase();
|
||||||
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||||
@ -363,83 +365,83 @@ public class MmsDatabase extends Database {
|
|||||||
notifyConversationListeners(contentValues.getAsLong(THREAD_ID));
|
notifyConversationListeners(contentValues.getAsLong(THREAD_ID));
|
||||||
DatabaseFactory.getThreadDatabase(context).update(contentValues.getAsLong(THREAD_ID));
|
DatabaseFactory.getThreadDatabase(context).update(contentValues.getAsLong(THREAD_ID));
|
||||||
|
|
||||||
return messageId;
|
return messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(long messageId) {
|
public void delete(long messageId) {
|
||||||
long threadId = getThreadIdForMessage(messageId);
|
long threadId = getThreadIdForMessage(messageId);
|
||||||
MmsAddressDatabase addrDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
MmsAddressDatabase addrDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||||
PartDatabase partDatabase = DatabaseFactory.getPartDatabase(context);
|
PartDatabase partDatabase = DatabaseFactory.getPartDatabase(context);
|
||||||
partDatabase.deleteParts(messageId);
|
partDatabase.deleteParts(messageId);
|
||||||
addrDatabase.deleteAddressesForId(messageId);
|
addrDatabase.deleteAddressesForId(messageId);
|
||||||
|
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
database.delete(TABLE_NAME, ID_WHERE, new String[] {messageId+""});
|
database.delete(TABLE_NAME, ID_WHERE, new String[] {messageId+""});
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
DatabaseFactory.getThreadDatabase(context).update(threadId);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void deleteThread(long threadId) {
|
public void deleteThread(long threadId) {
|
||||||
Set<Long> singleThreadSet = new HashSet<Long>();
|
Set<Long> singleThreadSet = new HashSet<Long>();
|
||||||
singleThreadSet.add(threadId);
|
singleThreadSet.add(threadId);
|
||||||
deleteThreads(singleThreadSet);
|
deleteThreads(singleThreadSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ void deleteThreads(Set<Long> threadIds) {
|
/*package*/ void deleteThreads(Set<Long> threadIds) {
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
String where = "";
|
String where = "";
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
|
||||||
for (long threadId : threadIds) {
|
for (long threadId : threadIds) {
|
||||||
where += THREAD_ID + " = '" + threadId + "' OR ";
|
where += THREAD_ID + " = '" + threadId + "' OR ";
|
||||||
}
|
}
|
||||||
|
|
||||||
where = where.substring(0, where.length() - 4);
|
where = where.substring(0, where.length() - 4);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = db.query(TABLE_NAME, new String[] {ID}, where, null, null, null, null);
|
cursor = db.query(TABLE_NAME, new String[] {ID}, where, null, null, null, null);
|
||||||
|
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
delete(cursor.getLong(0));
|
delete(cursor.getLong(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null)
|
if (cursor != null)
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void deleteAllThreads() {
|
public void deleteAllThreads() {
|
||||||
DatabaseFactory.getPartDatabase(context).deleteAllParts();
|
DatabaseFactory.getPartDatabase(context).deleteAllParts();
|
||||||
DatabaseFactory.getMmsAddressDatabase(context).deleteAllAddresses();
|
DatabaseFactory.getMmsAddressDatabase(context).deleteAllAddresses();
|
||||||
|
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
database.delete(TABLE_NAME, null, null);
|
database.delete(TABLE_NAME, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cursor getCarrierMmsInformation() {
|
public Cursor getCarrierMmsInformation() {
|
||||||
Uri uri = Uri.withAppendedPath(Uri.parse("content://telephony/carriers"), "current");
|
Uri uri = Uri.withAppendedPath(Uri.parse("content://telephony/carriers"), "current");
|
||||||
String selection = "type = 'mms'";
|
String selection = "type = 'mms'";
|
||||||
|
|
||||||
return context.getContentResolver().query(uri, null, selection, null, null);
|
return context.getContentResolver().query(uri, null, selection, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PduHeaders getHeadersForId(long messageId) throws MmsException {
|
private PduHeaders getHeadersForId(long messageId) throws MmsException {
|
||||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = database.query(TABLE_NAME, null, ID_WHERE, new String[] {messageId+""}, null, null, null);
|
cursor = database.query(TABLE_NAME, null, ID_WHERE, new String[] {messageId+""}, null, null, null);
|
||||||
|
|
||||||
if (cursor == null || !cursor.moveToFirst())
|
if (cursor == null || !cursor.moveToFirst())
|
||||||
throw new MmsException("No headers available at ID: " + messageId);
|
throw new MmsException("No headers available at ID: " + messageId);
|
||||||
|
|
||||||
PduHeaders headers = getHeadersFromCursor(cursor);
|
PduHeaders headers = getHeadersFromCursor(cursor);
|
||||||
long messageBox = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
|
long messageBox = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
|
||||||
MmsAddressDatabase addr = DatabaseFactory.getMmsAddressDatabase(context);
|
MmsAddressDatabase addr = DatabaseFactory.getMmsAddressDatabase(context);
|
||||||
|
|
||||||
addr.getAddressesForId(messageId, headers);
|
addr.getAddressesForId(messageId, headers);
|
||||||
headers.setMessageBox(messageBox);
|
headers.setMessageBox(messageBox);
|
||||||
|
|
||||||
@ -447,13 +449,13 @@ public class MmsDatabase extends Database {
|
|||||||
} finally {
|
} finally {
|
||||||
if (cursor != null)
|
if (cursor != null)
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PduHeaders getHeadersFromCursor(Cursor cursor) throws InvalidHeaderValueException {
|
private PduHeaders getHeadersFromCursor(Cursor cursor) throws InvalidHeaderValueException {
|
||||||
PduHeaders headers = new PduHeaders();
|
PduHeaders headers = new PduHeaders();
|
||||||
PduHeadersBuilder phb = new PduHeadersBuilder(headers, cursor);
|
PduHeadersBuilder phb = new PduHeadersBuilder(headers, cursor);
|
||||||
|
|
||||||
phb.add(RETRIEVE_TEXT, RETRIEVE_TEXT_CS, PduHeaders.RETRIEVE_TEXT);
|
phb.add(RETRIEVE_TEXT, RETRIEVE_TEXT_CS, PduHeaders.RETRIEVE_TEXT);
|
||||||
phb.add(SUBJECT, SUBJECT_CHARSET, PduHeaders.SUBJECT);
|
phb.add(SUBJECT, SUBJECT_CHARSET, PduHeaders.SUBJECT);
|
||||||
phb.addText(CONTENT_LOCATION, PduHeaders.CONTENT_LOCATION);
|
phb.addText(CONTENT_LOCATION, PduHeaders.CONTENT_LOCATION);
|
||||||
@ -475,14 +477,14 @@ public class MmsDatabase extends Database {
|
|||||||
phb.addLong(DELIVERY_TIME, PduHeaders.DELIVERY_TIME);
|
phb.addLong(DELIVERY_TIME, PduHeaders.DELIVERY_TIME);
|
||||||
phb.addLong(EXPIRY, PduHeaders.EXPIRY);
|
phb.addLong(EXPIRY, PduHeaders.EXPIRY);
|
||||||
phb.addLong(MESSAGE_SIZE, PduHeaders.MESSAGE_SIZE);
|
phb.addLong(MESSAGE_SIZE, PduHeaders.MESSAGE_SIZE);
|
||||||
|
|
||||||
return phb.getHeaders();
|
return phb.getHeaders();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContentValues getContentValuesFromHeader(PduHeaders headers) {
|
private ContentValues getContentValuesFromHeader(PduHeaders headers) {
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
ContentValuesBuilder cvb = new ContentValuesBuilder(contentValues);
|
ContentValuesBuilder cvb = new ContentValuesBuilder(contentValues);
|
||||||
|
|
||||||
cvb.add(RETRIEVE_TEXT, RETRIEVE_TEXT_CS, headers.getEncodedStringValue(PduHeaders.RETRIEVE_TEXT));
|
cvb.add(RETRIEVE_TEXT, RETRIEVE_TEXT_CS, headers.getEncodedStringValue(PduHeaders.RETRIEVE_TEXT));
|
||||||
cvb.add(SUBJECT, SUBJECT_CHARSET, headers.getEncodedStringValue(PduHeaders.SUBJECT));
|
cvb.add(SUBJECT, SUBJECT_CHARSET, headers.getEncodedStringValue(PduHeaders.SUBJECT));
|
||||||
cvb.add(CONTENT_LOCATION, headers.getTextString(PduHeaders.CONTENT_LOCATION));
|
cvb.add(CONTENT_LOCATION, headers.getTextString(PduHeaders.CONTENT_LOCATION));
|
||||||
@ -505,15 +507,15 @@ public class MmsDatabase extends Database {
|
|||||||
cvb.add(DELIVERY_TIME, headers.getLongInteger(PduHeaders.DELIVERY_TIME));
|
cvb.add(DELIVERY_TIME, headers.getLongInteger(PduHeaders.DELIVERY_TIME));
|
||||||
cvb.add(EXPIRY, headers.getLongInteger(PduHeaders.EXPIRY));
|
cvb.add(EXPIRY, headers.getLongInteger(PduHeaders.EXPIRY));
|
||||||
cvb.add(MESSAGE_SIZE, headers.getLongInteger(PduHeaders.MESSAGE_SIZE));
|
cvb.add(MESSAGE_SIZE, headers.getLongInteger(PduHeaders.MESSAGE_SIZE));
|
||||||
|
|
||||||
return cvb.getContentValues();
|
return cvb.getContentValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected PartDatabase getPartDatabase() {
|
protected PartDatabase getPartDatabase() {
|
||||||
return DatabaseFactory.getPartDatabase(context);
|
return DatabaseFactory.getPartDatabase(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Types {
|
public static class Types {
|
||||||
public static final String MMS_ERROR_TYPE = "err_type";
|
public static final String MMS_ERROR_TYPE = "err_type";
|
||||||
|
|
||||||
@ -527,9 +529,9 @@ public class MmsDatabase extends Database {
|
|||||||
public static final int MESSAGE_BOX_SECURE_INBOX = 8;
|
public static final int MESSAGE_BOX_SECURE_INBOX = 8;
|
||||||
public static final int MESSAGE_BOX_NO_SESSION_INBOX = 9;
|
public static final int MESSAGE_BOX_NO_SESSION_INBOX = 9;
|
||||||
public static final int MESSAGE_BOX_DECRYPT_FAILED_INBOX = 10;
|
public static final int MESSAGE_BOX_DECRYPT_FAILED_INBOX = 10;
|
||||||
|
|
||||||
public static final int MESSAGE_BOX_SENT_FAILED = 12;
|
public static final int MESSAGE_BOX_SENT_FAILED = 12;
|
||||||
|
|
||||||
public static final int DOWNLOAD_INITIALIZED = 1;
|
public static final int DOWNLOAD_INITIALIZED = 1;
|
||||||
public static final int DOWNLOAD_NO_CONNECTIVITY = 2;
|
public static final int DOWNLOAD_NO_CONNECTIVITY = 2;
|
||||||
public static final int DOWNLOAD_CONNECTING = 3;
|
public static final int DOWNLOAD_CONNECTING = 3;
|
||||||
@ -540,15 +542,15 @@ public class MmsDatabase extends Database {
|
|||||||
public static boolean isSecureMmsBox(long mailbox) {
|
public static boolean isSecureMmsBox(long mailbox) {
|
||||||
return mailbox == Types.MESSAGE_BOX_SECURE_OUTBOX || mailbox == Types.MESSAGE_BOX_SECURE_SENT || mailbox == Types.MESSAGE_BOX_SECURE_INBOX;
|
return mailbox == Types.MESSAGE_BOX_SECURE_OUTBOX || mailbox == Types.MESSAGE_BOX_SECURE_SENT || mailbox == Types.MESSAGE_BOX_SECURE_INBOX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isOutgoingMmsBox(long mailbox) {
|
public static boolean isOutgoingMmsBox(long mailbox) {
|
||||||
return mailbox == Types.MESSAGE_BOX_OUTBOX || mailbox == Types.MESSAGE_BOX_SENT || mailbox == Types.MESSAGE_BOX_SECURE_OUTBOX || mailbox == Types.MESSAGE_BOX_SENT_FAILED || mailbox == Types.MESSAGE_BOX_SECURE_SENT;
|
return mailbox == Types.MESSAGE_BOX_OUTBOX || mailbox == Types.MESSAGE_BOX_SENT || mailbox == Types.MESSAGE_BOX_SECURE_OUTBOX || mailbox == Types.MESSAGE_BOX_SENT_FAILED || mailbox == Types.MESSAGE_BOX_SECURE_SENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPendingMmsBox(long mailbox) {
|
public static boolean isPendingMmsBox(long mailbox) {
|
||||||
return mailbox == Types.MESSAGE_BOX_OUTBOX || mailbox == MESSAGE_BOX_SECURE_OUTBOX;
|
return mailbox == Types.MESSAGE_BOX_OUTBOX || mailbox == MESSAGE_BOX_SECURE_OUTBOX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFailedMmsBox(long mailbox) {
|
public static boolean isFailedMmsBox(long mailbox) {
|
||||||
return mailbox == Types.MESSAGE_BOX_SENT_FAILED;
|
return mailbox == Types.MESSAGE_BOX_SENT_FAILED;
|
||||||
}
|
}
|
||||||
@ -557,22 +559,22 @@ public class MmsDatabase extends Database {
|
|||||||
return status == DOWNLOAD_INITIALIZED || status == DOWNLOAD_NO_CONNECTIVITY || status == DOWNLOAD_SOFT_FAILURE;
|
return status == DOWNLOAD_INITIALIZED || status == DOWNLOAD_NO_CONNECTIVITY || status == DOWNLOAD_SOFT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getLabelForStatus(int status) {
|
public static String getLabelForStatus(Context context, int status) {
|
||||||
Log.w("MmsDatabase", "Getting label for status: " + status);
|
Log.w("MmsDatabase", "Getting label for status: " + status);
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case DOWNLOAD_CONNECTING: return "Connecting to MMS server...";
|
case DOWNLOAD_CONNECTING: return context.getString(R.string.connecting_to_mms_server);
|
||||||
case DOWNLOAD_INITIALIZED: return "Downloading MMS...";
|
case DOWNLOAD_INITIALIZED: return context.getString(R.string.downloading_mms);
|
||||||
case DOWNLOAD_HARD_FAILURE: return "MMS Download failed!";
|
case DOWNLOAD_HARD_FAILURE: return context.getString(R.string.mms_download_failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Downloading...";
|
return context.getString(R.string.downloading);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isHardError(int status) {
|
public static boolean isHardError(int status) {
|
||||||
return status == DOWNLOAD_HARD_FAILURE;
|
return status == DOWNLOAD_HARD_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,19 +10,22 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.database;
|
package org.thoughtcrime.securesms.database;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import android.content.Context;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ConversationItem;
|
import org.thoughtcrime.securesms.ConversationItem;
|
||||||
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class MmsMessageRecord extends MessageRecord {
|
public class MmsMessageRecord extends MessageRecord {
|
||||||
|
|
||||||
private SlideDeck slideDeck;
|
private SlideDeck slideDeck;
|
||||||
@ -33,14 +36,14 @@ public class MmsMessageRecord extends MessageRecord {
|
|||||||
private long mailbox;
|
private long mailbox;
|
||||||
private int status;
|
private int status;
|
||||||
private byte[] transactionId;
|
private byte[] transactionId;
|
||||||
|
|
||||||
public MmsMessageRecord(MessageRecord record, SlideDeck slideDeck, long mailbox) {
|
public MmsMessageRecord(Context context, MessageRecord record, SlideDeck slideDeck, long mailbox) {
|
||||||
super(record);
|
super(record);
|
||||||
this.slideDeck = slideDeck;
|
this.slideDeck = slideDeck;
|
||||||
this.isNotification = false;
|
this.isNotification = false;
|
||||||
this.mailbox = mailbox;
|
this.mailbox = mailbox;
|
||||||
|
|
||||||
setBodyIfTextAvailable();
|
setBodyIfTextAvailable(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MmsMessageRecord(MessageRecord record, byte[] contentLocation, long messageSize, long expiry, int status, byte[] transactionId) {
|
public MmsMessageRecord(MessageRecord record, byte[] contentLocation, long messageSize, long expiry, int status, byte[] transactionId) {
|
||||||
@ -52,53 +55,54 @@ public class MmsMessageRecord extends MessageRecord {
|
|||||||
this.status = status;
|
this.status = status;
|
||||||
this.transactionId = transactionId;
|
this.transactionId = transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getTransactionId() {
|
public byte[] getTransactionId() {
|
||||||
return transactionId;
|
return transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getStatus() {
|
public int getStatus() {
|
||||||
return this.status;
|
return this.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOutgoing() {
|
public boolean isOutgoing() {
|
||||||
return MmsDatabase.Types.isOutgoingMmsBox(mailbox);
|
return MmsDatabase.Types.isOutgoingMmsBox(mailbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPending() {
|
public boolean isPending() {
|
||||||
return MmsDatabase.Types.isPendingMmsBox(mailbox);
|
return MmsDatabase.Types.isPendingMmsBox(mailbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFailed() {
|
public boolean isFailed() {
|
||||||
return MmsDatabase.Types.isFailedMmsBox(mailbox);
|
return MmsDatabase.Types.isFailedMmsBox(mailbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSecure() {
|
public boolean isSecure() {
|
||||||
return MmsDatabase.Types.isSecureMmsBox(mailbox);
|
return MmsDatabase.Types.isSecureMmsBox(mailbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the double-dispatch pattern, don't refactor
|
// This is the double-dispatch pattern, don't refactor
|
||||||
// this into the base class.
|
// this into the base class.
|
||||||
|
@Override
|
||||||
public void setOnConversationItem(ConversationItem item) {
|
public void setOnConversationItem(ConversationItem item) {
|
||||||
item.setMessageRecord(this);
|
item.setMessageRecord(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getContentLocation() {
|
public byte[] getContentLocation() {
|
||||||
return contentLocation;
|
return contentLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getMessageSize() {
|
public long getMessageSize() {
|
||||||
return (messageSize + 1023) / 1024;
|
return (messageSize + 1023) / 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getExpiration() {
|
public long getExpiration() {
|
||||||
return expiry * 1000;
|
return expiry * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNotification() {
|
public boolean isNotification() {
|
||||||
return isNotification;
|
return isNotification;
|
||||||
}
|
}
|
||||||
@ -106,41 +110,42 @@ public class MmsMessageRecord extends MessageRecord {
|
|||||||
public SlideDeck getSlideDeck() {
|
public SlideDeck getSlideDeck() {
|
||||||
return slideDeck;
|
return slideDeck;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setBodyFromSlidesIfTextAvailable() {
|
private void setBodyFromSlidesIfTextAvailable() {
|
||||||
List<Slide> slides = slideDeck.getSlides();
|
List<Slide> slides = slideDeck.getSlides();
|
||||||
Iterator<Slide> i = slides.iterator();
|
Iterator<Slide> i = slides.iterator();
|
||||||
|
|
||||||
while (i.hasNext()) {
|
while (i.hasNext()) {
|
||||||
Slide slide = i.next();
|
Slide slide = i.next();
|
||||||
|
|
||||||
if (slide.hasText())
|
if (slide.hasText())
|
||||||
setBody(slide.getText());
|
setBody(slide.getText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setBodyIfTextAvailable() {
|
private void setBodyIfTextAvailable(Context context) {
|
||||||
switch ((int)mailbox) {
|
switch ((int)mailbox) {
|
||||||
case MmsDatabase.Types.MESSAGE_BOX_DECRYPTING_INBOX:
|
case MmsDatabase.Types.MESSAGE_BOX_DECRYPTING_INBOX:
|
||||||
setBody("Decrypting MMS, please wait...");
|
setBody(context.getString(R.string.decrypting_mms_please_wait));
|
||||||
setEmphasis(true);
|
setEmphasis(true);
|
||||||
return;
|
return;
|
||||||
case MmsDatabase.Types.MESSAGE_BOX_DECRYPT_FAILED_INBOX:
|
case MmsDatabase.Types.MESSAGE_BOX_DECRYPT_FAILED_INBOX:
|
||||||
setBody("Bad encrypted MMS message...");
|
setBody(context.getString(R.string.bad_encrypted_mms_message));
|
||||||
setEmphasis(true);
|
setEmphasis(true);
|
||||||
return;
|
return;
|
||||||
case MmsDatabase.Types.MESSAGE_BOX_NO_SESSION_INBOX:
|
case MmsDatabase.Types.MESSAGE_BOX_NO_SESSION_INBOX:
|
||||||
setBody("MMS message encrypted for non-existing session...");
|
setBody(context
|
||||||
|
.getString(R.string.mms_message_encrypted_for_non_existing_session));
|
||||||
setEmphasis(true);
|
setEmphasis(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setBodyFromSlidesIfTextAvailable();
|
setBodyFromSlidesIfTextAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMms() {
|
public boolean isMms() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,29 +10,29 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.database;
|
package org.thoughtcrime.securesms.database;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.crypto.IdentityKey;
|
||||||
|
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||||
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKey;
|
|
||||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A disk record representing a current session.
|
* A disk record representing a current session.
|
||||||
*
|
*
|
||||||
* @author Moxie Marlinspike
|
* @author Moxie Marlinspike
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -40,29 +40,29 @@ public class SessionRecord extends Record {
|
|||||||
private static final int CURRENT_VERSION_MARKER = 0X55555556;
|
private static final int CURRENT_VERSION_MARKER = 0X55555556;
|
||||||
private static final int[] VALID_VERSION_MARKERS = {CURRENT_VERSION_MARKER, 0X55555555};
|
private static final int[] VALID_VERSION_MARKERS = {CURRENT_VERSION_MARKER, 0X55555555};
|
||||||
private static final Object FILE_LOCK = new Object();
|
private static final Object FILE_LOCK = new Object();
|
||||||
|
|
||||||
private int counter;
|
private int counter;
|
||||||
private byte[] localFingerprint;
|
private byte[] localFingerprint;
|
||||||
private byte[] remoteFingerprint;
|
private byte[] remoteFingerprint;
|
||||||
private int sessionVersion;
|
private int sessionVersion;
|
||||||
|
|
||||||
private IdentityKey identityKey;
|
private IdentityKey identityKey;
|
||||||
private SessionKey sessionKeyRecord;
|
private SessionKey sessionKeyRecord;
|
||||||
private boolean verifiedSessionKey;
|
private boolean verifiedSessionKey;
|
||||||
|
|
||||||
private final MasterSecret masterSecret;
|
private final MasterSecret masterSecret;
|
||||||
|
|
||||||
public SessionRecord(Context context, MasterSecret masterSecret, Recipient recipient) {
|
public SessionRecord(Context context, MasterSecret masterSecret, Recipient recipient) {
|
||||||
super(context, getFileNameForRecipient(context, recipient));
|
super(context, getFileNameForRecipient(context, recipient));
|
||||||
this.masterSecret = masterSecret;
|
this.masterSecret = masterSecret;
|
||||||
this.sessionVersion = 31337;
|
this.sessionVersion = 31337;
|
||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void delete(Context context, Recipient recipient) {
|
public static void delete(Context context, Recipient recipient) {
|
||||||
Record.delete(context, getFileNameForRecipient(context, recipient));
|
Record.delete(context, getFileNameForRecipient(context, recipient));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasSession(Context context, Recipient recipient) {
|
public static boolean hasSession(Context context, Recipient recipient) {
|
||||||
Log.w("LocalKeyRecord", "Checking: " + getFileNameForRecipient(context, recipient));
|
Log.w("LocalKeyRecord", "Checking: " + getFileNameForRecipient(context, recipient));
|
||||||
return Record.hasRecord(context, getFileNameForRecipient(context, recipient));
|
return Record.hasRecord(context, getFileNameForRecipient(context, recipient));
|
||||||
@ -71,87 +71,87 @@ public class SessionRecord extends Record {
|
|||||||
private static String getFileNameForRecipient(Context context, Recipient recipient) {
|
private static String getFileNameForRecipient(Context context, Recipient recipient) {
|
||||||
return CanonicalAddressDatabase.getInstance(context).getCanonicalAddress(recipient.getNumber()) + "";
|
return CanonicalAddressDatabase.getInstance(context).getCanonicalAddress(recipient.getNumber()) + "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSessionKey(SessionKey sessionKeyRecord) {
|
public void setSessionKey(SessionKey sessionKeyRecord) {
|
||||||
this.sessionKeyRecord = sessionKeyRecord;
|
this.sessionKeyRecord = sessionKeyRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSessionId(byte[] localFingerprint, byte[] remoteFingerprint) {
|
public void setSessionId(byte[] localFingerprint, byte[] remoteFingerprint) {
|
||||||
this.localFingerprint = localFingerprint;
|
this.localFingerprint = localFingerprint;
|
||||||
this.remoteFingerprint = remoteFingerprint;
|
this.remoteFingerprint = remoteFingerprint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIdentityKey(IdentityKey identityKey) {
|
public void setIdentityKey(IdentityKey identityKey) {
|
||||||
this.identityKey = identityKey;
|
this.identityKey = identityKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSessionVersion() {
|
public int getSessionVersion() {
|
||||||
return (sessionVersion == 31337 ? 0 : sessionVersion);
|
return (sessionVersion == 31337 ? 0 : sessionVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSessionVersion(int sessionVersion) {
|
public void setSessionVersion(int sessionVersion) {
|
||||||
this.sessionVersion = sessionVersion;
|
this.sessionVersion = sessionVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCounter() {
|
public int getCounter() {
|
||||||
return this.counter;
|
return this.counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incrementCounter() {
|
public void incrementCounter() {
|
||||||
this.counter++;
|
this.counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getLocalFingerprint() {
|
public byte[] getLocalFingerprint() {
|
||||||
return this.localFingerprint;
|
return this.localFingerprint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getRemoteFingerprint() {
|
public byte[] getRemoteFingerprint() {
|
||||||
return this.remoteFingerprint;
|
return this.remoteFingerprint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IdentityKey getIdentityKey() {
|
public IdentityKey getIdentityKey() {
|
||||||
return this.identityKey;
|
return this.identityKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVerifiedSessionKey(boolean verifiedSessionKey) {
|
public void setVerifiedSessionKey(boolean verifiedSessionKey) {
|
||||||
this.verifiedSessionKey = verifiedSessionKey;
|
this.verifiedSessionKey = verifiedSessionKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVerifiedSession() {
|
public boolean isVerifiedSession() {
|
||||||
return this.verifiedSessionKey;
|
return this.verifiedSessionKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeIdentityKey(FileChannel out) throws IOException {
|
private void writeIdentityKey(FileChannel out) throws IOException {
|
||||||
if (identityKey == null) writeBlob(new byte[0], out);
|
if (identityKey == null) writeBlob(new byte[0], out);
|
||||||
else writeBlob(identityKey.serialize(), out);
|
else writeBlob(identityKey.serialize(), out);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidVersionMarker(int versionMarker) {
|
private boolean isValidVersionMarker(int versionMarker) {
|
||||||
for (int i=0;i<VALID_VERSION_MARKERS.length;i++)
|
for (int i=0;i<VALID_VERSION_MARKERS.length;i++)
|
||||||
if (versionMarker == VALID_VERSION_MARKERS[i])
|
if (versionMarker == VALID_VERSION_MARKERS[i])
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readIdentityKey(FileInputStream in) throws IOException {
|
private void readIdentityKey(FileInputStream in) throws IOException {
|
||||||
try {
|
try {
|
||||||
byte[] blob = readBlob(in);
|
byte[] blob = readBlob(in);
|
||||||
|
|
||||||
if (blob.length == 0) this.identityKey = null;
|
if (blob.length == 0) this.identityKey = null;
|
||||||
else this.identityKey = new IdentityKey(blob, 0);
|
else this.identityKey = new IdentityKey(blob, 0);
|
||||||
} catch (InvalidKeyException ike) {
|
} catch (InvalidKeyException ike) {
|
||||||
throw new AssertionError(ike);
|
throw new AssertionError(ike);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
synchronized (FILE_LOCK) {
|
synchronized (FILE_LOCK) {
|
||||||
try {
|
try {
|
||||||
RandomAccessFile file = openRandomAccessFile();
|
RandomAccessFile file = openRandomAccessFile();
|
||||||
FileChannel out = file.getChannel();
|
FileChannel out = file.getChannel();
|
||||||
out.position(0);
|
out.position(0);
|
||||||
|
|
||||||
writeInteger(CURRENT_VERSION_MARKER, out);
|
writeInteger(CURRENT_VERSION_MARKER, out);
|
||||||
writeInteger(counter, out);
|
writeInteger(counter, out);
|
||||||
writeBlob(localFingerprint, out);
|
writeBlob(localFingerprint, out);
|
||||||
@ -159,10 +159,10 @@ public class SessionRecord extends Record {
|
|||||||
writeInteger(sessionVersion, out);
|
writeInteger(sessionVersion, out);
|
||||||
writeIdentityKey(out);
|
writeIdentityKey(out);
|
||||||
writeInteger(verifiedSessionKey ? 1 : 0, out);
|
writeInteger(verifiedSessionKey ? 1 : 0, out);
|
||||||
|
|
||||||
if (sessionKeyRecord != null)
|
if (sessionKeyRecord != null)
|
||||||
writeBlob(sessionKeyRecord.serialize(), out);
|
writeBlob(sessionKeyRecord.serialize(), out);
|
||||||
|
|
||||||
out.truncate(out.position());
|
out.truncate(out.position());
|
||||||
file.close();
|
file.close();
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
@ -176,32 +176,32 @@ public class SessionRecord extends Record {
|
|||||||
try {
|
try {
|
||||||
FileInputStream in = this.openInputStream();
|
FileInputStream in = this.openInputStream();
|
||||||
int versionMarker = readInteger(in);
|
int versionMarker = readInteger(in);
|
||||||
|
|
||||||
// Sigh, always put a version number on everything.
|
// Sigh, always put a version number on everything.
|
||||||
if (!isValidVersionMarker(versionMarker)) {
|
if (!isValidVersionMarker(versionMarker)) {
|
||||||
this.counter = versionMarker;
|
this.counter = versionMarker;
|
||||||
this.localFingerprint = readBlob(in);
|
this.localFingerprint = readBlob(in);
|
||||||
this.remoteFingerprint = readBlob(in);
|
this.remoteFingerprint = readBlob(in);
|
||||||
this.sessionVersion = 31337;
|
this.sessionVersion = 31337;
|
||||||
|
|
||||||
if (in.available() != 0)
|
if (in.available() != 0)
|
||||||
this.sessionKeyRecord = new SessionKey(readBlob(in), masterSecret);
|
this.sessionKeyRecord = new SessionKey(readBlob(in), masterSecret);
|
||||||
|
|
||||||
in.close();
|
in.close();
|
||||||
} else {
|
} else {
|
||||||
this.counter = readInteger(in);
|
this.counter = readInteger(in);
|
||||||
this.localFingerprint = readBlob(in);
|
this.localFingerprint = readBlob(in);
|
||||||
this.remoteFingerprint = readBlob(in);
|
this.remoteFingerprint = readBlob(in);
|
||||||
this.sessionVersion = readInteger(in);
|
this.sessionVersion = readInteger(in);
|
||||||
|
|
||||||
if (versionMarker >= 0X55555556) {
|
if (versionMarker >= 0X55555556) {
|
||||||
readIdentityKey(in);
|
readIdentityKey(in);
|
||||||
this.verifiedSessionKey = (readInteger(in) == 1) ? true : false;
|
this.verifiedSessionKey = (readInteger(in) == 1) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in.available() != 0)
|
if (in.available() != 0)
|
||||||
this.sessionKeyRecord = new SessionKey(readBlob(in), masterSecret);
|
this.sessionKeyRecord = new SessionKey(readBlob(in), masterSecret);
|
||||||
|
|
||||||
in.close();
|
in.close();
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
@ -216,12 +216,12 @@ public class SessionRecord extends Record {
|
|||||||
|
|
||||||
public SessionKey getSessionKey(int localKeyId, int remoteKeyId) {
|
public SessionKey getSessionKey(int localKeyId, int remoteKeyId) {
|
||||||
if (this.sessionKeyRecord == null) return null;
|
if (this.sessionKeyRecord == null) return null;
|
||||||
|
|
||||||
if ((this.sessionKeyRecord.getLocalKeyId() == localKeyId) &&
|
if ((this.sessionKeyRecord.getLocalKeyId() == localKeyId) &&
|
||||||
(this.sessionKeyRecord.getRemoteKeyId() == remoteKeyId))
|
(this.sessionKeyRecord.getRemoteKeyId() == remoteKeyId))
|
||||||
return this.sessionKeyRecord;
|
return this.sessionKeyRecord;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,12 +10,15 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.mms;
|
package org.thoughtcrime.securesms.mms;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessageRecord;
|
import org.thoughtcrime.securesms.database.MessageRecord;
|
||||||
@ -26,8 +29,6 @@ import ws.com.google.android.mms.MmsException;
|
|||||||
import ws.com.google.android.mms.pdu.MultimediaMessagePdu;
|
import ws.com.google.android.mms.pdu.MultimediaMessagePdu;
|
||||||
import ws.com.google.android.mms.pdu.NotificationInd;
|
import ws.com.google.android.mms.pdu.NotificationInd;
|
||||||
import ws.com.google.android.mms.pdu.PduHeaders;
|
import ws.com.google.android.mms.pdu.PduHeaders;
|
||||||
import android.content.Context;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
public class MmsFactory {
|
public class MmsFactory {
|
||||||
|
|
||||||
@ -39,11 +40,11 @@ public class MmsFactory {
|
|||||||
return getMediaMmsRecord(context, masterSecret, record, box);
|
return getMediaMmsRecord(context, masterSecret, record, box);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MmsMessageRecord getNotificationMmsRecord(Context context, MessageRecord record) throws MmsException {
|
private static MmsMessageRecord getNotificationMmsRecord(Context context, MessageRecord record) throws MmsException {
|
||||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||||
NotificationInd notification = database.getNotificationMessage(record.getId());
|
NotificationInd notification = database.getNotificationMessage(record.getId());
|
||||||
return new MmsMessageRecord(record, notification.getContentLocation(), notification.getMessageSize(),
|
return new MmsMessageRecord(record, notification.getContentLocation(), notification.getMessageSize(),
|
||||||
notification.getExpiry(), notification.getStatus(), notification.getTransactionId());
|
notification.getExpiry(), notification.getStatus(), notification.getTransactionId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,9 +53,9 @@ public class MmsFactory {
|
|||||||
MultimediaMessagePdu msg = database.getMediaMessage(record.getId());
|
MultimediaMessagePdu msg = database.getMediaMessage(record.getId());
|
||||||
SlideDeck slideDeck = new SlideDeck(context, masterSecret, msg.getBody());
|
SlideDeck slideDeck = new SlideDeck(context, masterSecret, msg.getBody());
|
||||||
|
|
||||||
return new MmsMessageRecord(record, slideDeck, box);
|
return new MmsMessageRecord(context, record, slideDeck, box);
|
||||||
}
|
}
|
||||||
|
|
||||||
// private static void setBodyIfText(SlideModel slide, MessageRecord record) {
|
// private static void setBodyIfText(SlideModel slide, MessageRecord record) {
|
||||||
// if ((slide != null) && slide.hasText()) {
|
// if ((slide != null) && slide.hasText()) {
|
||||||
// TextModel tm = slide.getText();
|
// TextModel tm = slide.getText();
|
||||||
@ -64,15 +65,15 @@ public class MmsFactory {
|
|||||||
// } else {
|
// } else {
|
||||||
// record.setBody(tm.getText());
|
// record.setBody(tm.getText());
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// private static SlideshowModel getSlideshowModel(Context context, long messageId) throws MmsException {
|
// private static SlideshowModel getSlideshowModel(Context context, long messageId) throws MmsException {
|
||||||
// LayoutManager.init(context);
|
// LayoutManager.init(context);
|
||||||
// MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
// MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||||
// MultimediaMessagePdu msg = database.getMediaMessage(messageId);
|
// MultimediaMessagePdu msg = database.getMediaMessage(messageId);
|
||||||
// return SlideshowModel.createFromPduBody(context, msg.getBody());
|
// return SlideshowModel.createFromPduBody(context, msg.getBody());
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,15 +10,12 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.preferences;
|
package org.thoughtcrime.securesms.preferences;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
|
||||||
import org.thoughtcrime.securesms.R;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
@ -30,25 +27,28 @@ import android.util.AttributeSet;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
|
import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import android.widget.SeekBar.OnSeekBarChangeListener;
|
|
||||||
|
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||||
|
import org.thoughtcrime.securesms.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List preference for LED blink pattern notification.
|
* List preference for LED blink pattern notification.
|
||||||
*
|
*
|
||||||
* @author Moxie Marlinspike
|
* @author Moxie Marlinspike
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class LedBlinkPatternListPreference extends ListPreference implements OnSeekBarChangeListener {
|
public class LedBlinkPatternListPreference extends ListPreference implements OnSeekBarChangeListener {
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private SeekBar seekBarOn;
|
private SeekBar seekBarOn;
|
||||||
private SeekBar seekBarOff;
|
private SeekBar seekBarOff;
|
||||||
|
|
||||||
private TextView seekBarOnLabel;
|
private TextView seekBarOnLabel;
|
||||||
private TextView seekBarOffLabel;
|
private TextView seekBarOffLabel;
|
||||||
|
|
||||||
private boolean dialogInProgress;
|
private boolean dialogInProgress;
|
||||||
|
|
||||||
public LedBlinkPatternListPreference(Context context) {
|
public LedBlinkPatternListPreference(Context context) {
|
||||||
@ -62,9 +62,9 @@ public class LedBlinkPatternListPreference extends ListPreference implements OnS
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDialogClosed(boolean positiveResult) {
|
protected void onDialogClosed(boolean positiveResult) {
|
||||||
super.onDialogClosed(positiveResult);
|
super.onDialogClosed(positiveResult);
|
||||||
|
|
||||||
if (positiveResult) {
|
if (positiveResult) {
|
||||||
String blinkPattern = PreferenceManager.getDefaultSharedPreferences(context).getString(ApplicationPreferencesActivity.LED_BLINK_PREF, "500,2000");
|
String blinkPattern = PreferenceManager.getDefaultSharedPreferences(context).getString(ApplicationPreferencesActivity.LED_BLINK_PREF, "500,2000");
|
||||||
if (blinkPattern.equals("custom")) showDialog();
|
if (blinkPattern.equals("custom")) showDialog();
|
||||||
@ -77,7 +77,7 @@ public class LedBlinkPatternListPreference extends ListPreference implements OnS
|
|||||||
seekBarOn.setProgress(Integer.parseInt(patternArray[0]));
|
seekBarOn.setProgress(Integer.parseInt(patternArray[0]));
|
||||||
seekBarOff.setProgress(Integer.parseInt(patternArray[1]));
|
seekBarOff.setProgress(Integer.parseInt(patternArray[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeDialog(View view) {
|
private void initializeDialog(View view) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_info);
|
builder.setIcon(android.R.drawable.ic_dialog_info);
|
||||||
@ -88,7 +88,7 @@ public class LedBlinkPatternListPreference extends ListPreference implements OnS
|
|||||||
builder.setPositiveButton(android.R.string.ok, new CustomDialogClickListener());
|
builder.setPositiveButton(android.R.string.ok, new CustomDialogClickListener());
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showDialog() {
|
private void showDialog() {
|
||||||
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
View view = inflater.inflate(R.layout.led_pattern_dialog, null);
|
View view = inflater.inflate(R.layout.led_pattern_dialog, null);
|
||||||
@ -104,12 +104,12 @@ public class LedBlinkPatternListPreference extends ListPreference implements OnS
|
|||||||
initializeSeekBarValues();
|
initializeSeekBarValues();
|
||||||
initializeDialog(view);
|
initializeDialog(view);
|
||||||
dialogInProgress = true;
|
dialogInProgress = true;
|
||||||
|
|
||||||
dialogInProgress = true;
|
dialogInProgress = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(Parcelable state) {
|
protected void onRestoreInstanceState(Parcelable state) {
|
||||||
super.onRestoreInstanceState(state);
|
super.onRestoreInstanceState(state);
|
||||||
if (dialogInProgress) {
|
if (dialogInProgress) {
|
||||||
showDialog();
|
showDialog();
|
||||||
@ -117,7 +117,7 @@ public class LedBlinkPatternListPreference extends ListPreference implements OnS
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected View onCreateDialogView() {
|
protected View onCreateDialogView() {
|
||||||
dialogInProgress = false;
|
dialogInProgress = false;
|
||||||
return super.onCreateDialogView();
|
return super.onCreateDialogView();
|
||||||
}
|
}
|
||||||
@ -138,25 +138,25 @@ public class LedBlinkPatternListPreference extends ListPreference implements OnS
|
|||||||
|
|
||||||
private class CustomDialogCancelListener implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
|
private class CustomDialogCancelListener implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
dialogInProgress = false;
|
dialogInProgress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCancel(DialogInterface dialog) {
|
public void onCancel(DialogInterface dialog) {
|
||||||
dialogInProgress = false;
|
dialogInProgress = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CustomDialogClickListener implements DialogInterface.OnClickListener {
|
private class CustomDialogClickListener implements DialogInterface.OnClickListener {
|
||||||
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
String pattern = seekBarOnLabel.getText() + "," + seekBarOffLabel.getText();
|
String pattern = seekBarOnLabel.getText() + "," + seekBarOffLabel.getText();
|
||||||
dialogInProgress = false;
|
dialogInProgress = false;
|
||||||
|
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
preferences.edit().putString(ApplicationPreferencesActivity.LED_BLINK_PREF_CUSTOM, pattern).commit();
|
preferences.edit().putString(ApplicationPreferencesActivity.LED_BLINK_PREF_CUSTOM, pattern).commit();
|
||||||
Toast.makeText(context, "Custom LED blink pattern set!", Toast.LENGTH_LONG).show();
|
Toast.makeText(context, "Custom LED blink pattern set!", Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,7 +10,7 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
@ -20,17 +20,17 @@ package org.thoughtcrime.securesms.protocol;
|
|||||||
* Prefixes for identifying encrypted message types. In hindsight, seems
|
* Prefixes for identifying encrypted message types. In hindsight, seems
|
||||||
* like these could have been DB columns or a single DB column with a bitmask
|
* like these could have been DB columns or a single DB column with a bitmask
|
||||||
* or something.
|
* or something.
|
||||||
*
|
*
|
||||||
* @author Moxie Marlinspike
|
* @author Moxie Marlinspike
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class Prefix {
|
public class Prefix {
|
||||||
|
|
||||||
public static final String KEY_EXCHANGE = "?TextSecureKeyExchange";
|
public static final String KEY_EXCHANGE = "?TextSecureKeyExchange";
|
||||||
public static final String SYMMETRIC_ENCRYPT = "?TextSecureLocalEncrypt";
|
public static final String SYMMETRIC_ENCRYPT = "?TextSecureLocalEncrypt";
|
||||||
public static final String ASYMMETRIC_ENCRYPT = "?TextSecureAsymmetricEncrypt";
|
public static final String ASYMMETRIC_ENCRYPT = "?TextSecureAsymmetricEncrypt";
|
||||||
public static final String ASYMMETRIC_LOCAL_ENCRYPT = "?TextSecureAsymmetricLocalEncrypt";
|
public static final String ASYMMETRIC_LOCAL_ENCRYPT = "?TextSecureAsymmetricLocalEncrypt";
|
||||||
public static final String PROCESSED_KEY_EXCHANGE = "?TextSecureKeyExchangd";
|
public static final String PROCESSED_KEY_EXCHANGE = "?TextSecureKeyExchangd";
|
||||||
public static final String STALE_KEY_EXCHANGE = "?TextSecureKeyExchangs";
|
public static final String STALE_KEY_EXCHANGE = "?TextSecureKeyExchangs";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ public class ApplicationMigrationService extends Service
|
|||||||
|
|
||||||
private Notification initializeBackgroundNotification() {
|
private Notification initializeBackgroundNotification() {
|
||||||
Intent intent = new Intent(this, ConversationListActivity.class);
|
Intent intent = new Intent(this, ConversationListActivity.class);
|
||||||
Notification notification = new Notification(R.drawable.icon, "Migrating",
|
Notification notification = new Notification(R.drawable.icon, getString(R.string.migrating),
|
||||||
System.currentTimeMillis());
|
System.currentTimeMillis());
|
||||||
|
|
||||||
notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;
|
notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;
|
||||||
@ -89,7 +89,7 @@ public class ApplicationMigrationService extends Service
|
|||||||
|
|
||||||
notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
|
notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
|
||||||
notification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);
|
notification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);
|
||||||
notification.contentView.setTextViewText(R.id.status_text, "Migrating System Text Messages");
|
notification.contentView.setTextViewText(R.id.status_text, getString(R.string.migrating_system_text_messages));
|
||||||
notification.contentView.setProgressBar(R.id.status_progress, 10000, 0, false);
|
notification.contentView.setProgressBar(R.id.status_progress, 10000, 0, false);
|
||||||
|
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
|
@ -142,10 +142,13 @@ public class KeyCachingService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void foregroundService() {
|
private void foregroundService() {
|
||||||
Notification notification = new Notification(R.drawable.icon_cached, "TextSecure Passphrase Cached", System.currentTimeMillis());
|
Notification notification = new Notification(R.drawable.icon_cached,
|
||||||
|
getString(R.string.textsecure_passphrase_cached),
|
||||||
|
System.currentTimeMillis());
|
||||||
Intent intent = new Intent(this, ConversationListActivity.class);
|
Intent intent = new Intent(this, ConversationListActivity.class);
|
||||||
PendingIntent launchIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
|
PendingIntent launchIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
|
||||||
notification.setLatestEventInfo(getApplicationContext(), "TextSecure Cached", "TextSecure Passphrase Cached", launchIntent);
|
notification.setLatestEventInfo(getApplicationContext(), getString(R.string.textsecure_cached),
|
||||||
|
getString(R.string.textsecure_passphrase_cached), launchIntent);
|
||||||
|
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
startForeground(SERVICE_RUNNING_ID, notification);
|
startForeground(SERVICE_RUNNING_ID, notification);
|
||||||
|
@ -54,31 +54,27 @@ public class MessageNotifier {
|
|||||||
|
|
||||||
public static final int NOTIFICATION_ID = 1338;
|
public static final int NOTIFICATION_ID = 1338;
|
||||||
|
|
||||||
private static String buildTickerMessage(int count, Recipients recipients) {
|
private static String buildTickerMessage(Context context, int count, Recipients recipients) {
|
||||||
Recipient recipient = recipients.getPrimaryRecipient();
|
Recipient recipient = recipients.getPrimaryRecipient();
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
builder.append('(');
|
|
||||||
builder.append(count);
|
|
||||||
builder.append(')');
|
|
||||||
builder.append(" New messages");
|
|
||||||
|
|
||||||
if (recipient != null) {
|
if (recipient == null) {
|
||||||
builder.append(", most recent from: ");
|
return String.format(context.getString(R.string._d_new_messages), count);
|
||||||
builder.append(recipient.getName() == null ? recipient.getNumber() : recipient.getName());
|
} else {
|
||||||
|
return String.format(context.getString(R.string._d_new_messages_most_recent_from_s), count,
|
||||||
|
recipient.getName() == null ? recipient.getNumber() : recipient.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String buildTitleMessage(int count) {
|
private static String buildTitleMessage(Context context, int count) {
|
||||||
return "(" + count + ") New Messages";
|
return String.format(context.getString(R.string._d_new_messages), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String buildSubtitleMessage(Recipients recipients) {
|
private static String buildSubtitleMessage(Context context, Recipients recipients) {
|
||||||
Recipient recipient = recipients.getPrimaryRecipient();
|
Recipient recipient = recipients.getPrimaryRecipient();
|
||||||
|
|
||||||
if (recipient != null) {
|
if (recipient != null) {
|
||||||
return "Most recent from: " + (recipient.getName() == null ? recipient.getNumber() : recipient.getName());
|
return String.format(context.getString(R.string.most_recent_from_s),
|
||||||
|
(recipient.getName() == null ? recipient.getNumber() : recipient.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -98,15 +94,15 @@ public class MessageNotifier {
|
|||||||
private static Recipients getMostRecentRecipients(Context context, Cursor c) {
|
private static Recipients getMostRecentRecipients(Context context, Cursor c) {
|
||||||
if (c != null && c.moveToLast()) {
|
if (c != null && c.moveToLast()) {
|
||||||
try {
|
try {
|
||||||
String type = c.getString(c.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
|
String type = c.getString(c.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
|
||||||
|
|
||||||
if (type.equals("sms"))
|
if (type.equals("sms"))
|
||||||
return getSmsRecipient(context, c);
|
return getSmsRecipient(context, c);
|
||||||
else
|
else
|
||||||
return getMmsRecipient(context, c);
|
return getMmsRecipient(context, c);
|
||||||
|
|
||||||
} catch (RecipientFormattingException e) {
|
} catch (RecipientFormattingException e) {
|
||||||
return new Recipients(new LinkedList<Recipient>());
|
return new Recipients(new LinkedList<Recipient>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,8 +122,8 @@ public class MessageNotifier {
|
|||||||
Log.w("SmsNotifier", "Adding thread_id to pending intent: " + threadId);
|
Log.w("SmsNotifier", "Adding thread_id to pending intent: " + threadId);
|
||||||
|
|
||||||
if (recipients.getPrimaryRecipient() != null) {
|
if (recipients.getPrimaryRecipient() != null) {
|
||||||
intent.putExtra("recipients", recipients);
|
intent.putExtra("recipients", recipients);
|
||||||
intent.putExtra("thread_id", threadId);
|
intent.putExtra("thread_id", threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||||
@ -180,9 +176,9 @@ public class MessageNotifier {
|
|||||||
else if (c == null || !c.moveToFirst()) return;
|
else if (c == null || !c.moveToFirst()) return;
|
||||||
|
|
||||||
Recipients recipients = getMostRecentRecipients(context, c);
|
Recipients recipients = getMostRecentRecipients(context, c);
|
||||||
String ticker = buildTickerMessage(c.getCount(), recipients);
|
String ticker = buildTickerMessage(context, c.getCount(), recipients);
|
||||||
String title = buildTitleMessage(c.getCount());
|
String title = buildTitleMessage(context, c.getCount());
|
||||||
String subtitle = buildSubtitleMessage(recipients);
|
String subtitle = buildSubtitleMessage(context, recipients);
|
||||||
PendingIntent launchIntent = buildPendingIntent(context, c, recipients);
|
PendingIntent launchIntent = buildPendingIntent(context, c, recipients);
|
||||||
|
|
||||||
sendNotification(context, manager, launchIntent, ticker, title, subtitle, signal);
|
sendNotification(context, manager, launchIntent, ticker, title, subtitle, signal);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011 Whisper Systems
|
* Copyright (C) 2011 Whisper Systems
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@ -10,7 +10,7 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
@ -26,7 +26,7 @@ public class Dialogs {
|
|||||||
alertDialog.setTitle(title);
|
alertDialog.setTitle(title);
|
||||||
alertDialog.setMessage(message);
|
alertDialog.setMessage(message);
|
||||||
alertDialog.setIcon(icon);
|
alertDialog.setIcon(icon);
|
||||||
alertDialog.setPositiveButton("Ok", null);
|
alertDialog.setPositiveButton(android.R.string.ok, null);
|
||||||
alertDialog.show();
|
alertDialog.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|