Added code to send messages with extended encoding

This commit is contained in:
Christian Basler 2016-12-05 12:37:32 +01:00
parent 96af8e0750
commit 4be1f1e505
10 changed files with 336 additions and 35 deletions

View File

@ -36,13 +36,13 @@ android {
} }
} }
ext.jabitVersion = '2.0.4' //ext.jabitVersion = '2.0.4'
ext.jabitVersion = 'feature-extended-encoding-SNAPSHOT'
dependencies { dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.0.0' compile 'com.android.support:appcompat-v7:25.0.1'
compile 'com.android.support:support-v4:25.0.0' compile 'com.android.support:support-v4:25.0.1'
compile 'com.android.support:design:25.0.0' compile 'com.android.support:design:25.0.1'
compile 'com.android.support.constraint:constraint-layout:1.0.0-beta1'
compile "ch.dissem.jabit:jabit-core:$jabitVersion" compile "ch.dissem.jabit:jabit-core:$jabitVersion"
compile "ch.dissem.jabit:jabit-networking:$jabitVersion" compile "ch.dissem.jabit:jabit-networking:$jabitVersion"
@ -73,6 +73,7 @@ dependencies {
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19' testCompile 'org.mockito:mockito-core:1.10.19'
compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4'
} }
idea.module { idea.module {

View File

@ -28,6 +28,8 @@ import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext; import ch.dissem.bitmessage.entity.Plaintext;
import static ch.dissem.bitmessage.entity.Plaintext.Encoding.EXTENDED;
/** /**
* Compose a new message. * Compose a new message.
*/ */
@ -37,6 +39,8 @@ public class ComposeMessageActivity extends AppCompatActivity {
public static final String EXTRA_SUBJECT = "ch.dissem.abit.Message.SUBJECT"; public static final String EXTRA_SUBJECT = "ch.dissem.abit.Message.SUBJECT";
public static final String EXTRA_CONTENT = "ch.dissem.abit.Message.CONTENT"; public static final String EXTRA_CONTENT = "ch.dissem.abit.Message.CONTENT";
public static final String EXTRA_BROADCAST = "ch.dissem.abit.Message.IS_BROADCAST"; public static final String EXTRA_BROADCAST = "ch.dissem.abit.Message.IS_BROADCAST";
public static final String EXTRA_ENCODING = "ch.dissem.abit.Message.ENCODING";
public static final String EXTRA_PARENT = "ch.dissem.abit.Message.PARENT";
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -69,14 +73,22 @@ public class ComposeMessageActivity extends AppCompatActivity {
private static Intent getReplyIntent(Context ctx, Plaintext item) { private static Intent getReplyIntent(Context ctx, Plaintext item) {
Intent replyIntent = new Intent(ctx, ComposeMessageActivity.class); Intent replyIntent = new Intent(ctx, ComposeMessageActivity.class);
replyIntent.putExtra(EXTRA_RECIPIENT, item.getFrom());
BitmessageAddress receivingIdentity = item.getTo(); BitmessageAddress receivingIdentity = item.getTo();
if (receivingIdentity.isChan()) { if (receivingIdentity.isChan()) {
// reply to chan, not to the sender of the message
replyIntent.putExtra(EXTRA_RECIPIENT, receivingIdentity);
// I hate when people send as chan, so it won't be the default behaviour. // I hate when people send as chan, so it won't be the default behaviour.
replyIntent.putExtra(EXTRA_IDENTITY, Singleton.getIdentity(ctx)); replyIntent.putExtra(EXTRA_IDENTITY, Singleton.getIdentity(ctx));
} else { } else {
replyIntent.putExtra(EXTRA_RECIPIENT, item.getFrom());
replyIntent.putExtra(EXTRA_IDENTITY, receivingIdentity); replyIntent.putExtra(EXTRA_IDENTITY, receivingIdentity);
} }
// if the original message was sent using extended encoding, use it as well
// so features like threading can be supported
if (item.getEncoding() == EXTENDED) {
replyIntent.putExtra(EXTRA_ENCODING, EXTENDED);
replyIntent.putExtra(EXTRA_PARENT, item);
}
String prefix; String prefix;
if (item.getSubject().length() >= 3 && item.getSubject().substring(0, 3) if (item.getSubject().length() >= 3 && item.getSubject().substring(0, 3)
.equalsIgnoreCase("RE:")) { .equalsIgnoreCase("RE:")) {

View File

@ -16,6 +16,7 @@
package ch.dissem.apps.abit; package ch.dissem.apps.abit;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -27,18 +28,28 @@ import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AutoCompleteTextView; import android.widget.AutoCompleteTextView;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Toast;
import java.util.List; import java.util.List;
import ch.dissem.apps.abit.adapter.ContactAdapter; import ch.dissem.apps.abit.adapter.ContactAdapter;
import ch.dissem.apps.abit.dialog.SelectEncodingDialogFragment;
import ch.dissem.apps.abit.service.Singleton; import ch.dissem.apps.abit.service.Singleton;
import ch.dissem.bitmessage.BitmessageContext;
import ch.dissem.bitmessage.entity.BitmessageAddress; import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.valueobject.ExtendedEncoding;
import static android.app.Activity.RESULT_OK;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_BROADCAST; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_BROADCAST;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_CONTENT; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_CONTENT;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_ENCODING;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_IDENTITY; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_IDENTITY;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_PARENT;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_RECIPIENT; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_RECIPIENT;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_SUBJECT; import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_SUBJECT;
import static ch.dissem.bitmessage.entity.Plaintext.Type.BROADCAST;
import static ch.dissem.bitmessage.entity.Plaintext.Type.MSG;
/** /**
* Compose a new message. * Compose a new message.
@ -52,6 +63,8 @@ public class ComposeMessageFragment extends Fragment {
private EditText subjectInput; private EditText subjectInput;
private EditText bodyInput; private EditText bodyInput;
private boolean broadcast; private boolean broadcast;
private Plaintext.Encoding encoding;
private Plaintext parent;
/** /**
* Mandatory empty constructor for the fragment manager to instantiate the * Mandatory empty constructor for the fragment manager to instantiate the
@ -79,6 +92,14 @@ public class ComposeMessageFragment extends Fragment {
if (getArguments().containsKey(EXTRA_CONTENT)) { if (getArguments().containsKey(EXTRA_CONTENT)) {
content = getArguments().getString(EXTRA_CONTENT); content = getArguments().getString(EXTRA_CONTENT);
} }
if (getArguments().containsKey(EXTRA_ENCODING)) {
encoding = (Plaintext.Encoding) getArguments().getSerializable(EXTRA_ENCODING);
} else {
encoding = Plaintext.Encoding.SIMPLE;
}
if (getArguments().containsKey(EXTRA_PARENT)) {
parent = (Plaintext) getArguments().getSerializable(EXTRA_PARENT);
}
} else { } else {
throw new RuntimeException("No identity set for ComposeMessageFragment"); throw new RuntimeException("No identity set for ComposeMessageFragment");
} }
@ -145,10 +166,33 @@ public class ComposeMessageFragment extends Fragment {
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.send: case R.id.send:
send();
return true;
case R.id.select_encoding:
SelectEncodingDialogFragment encodingDialog = new SelectEncodingDialogFragment();
encodingDialog.setTargetFragment(this, 0);
encodingDialog.show(getFragmentManager(), "select encoding dialog");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 0 && resultCode == RESULT_OK) {
encoding = (Plaintext.Encoding) data.getSerializableExtra(EXTRA_ENCODING);
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void send() {
Plaintext.Builder builder;
BitmessageContext bmc = Singleton.getBitmessageContext(getContext());
if (broadcast) { if (broadcast) {
Singleton.getBitmessageContext(getContext()).broadcast(identity, builder = new Plaintext.Builder(BROADCAST)
subjectInput.getText().toString(), .from(identity);
bodyInput.getText().toString());
} else { } else {
String inputString = recipientInput.getText().toString(); String inputString = recipientInput.getText().toString();
if (recipient == null || !recipient.toString().equals(inputString)) { if (recipient == null || !recipient.toString().equals(inputString)) {
@ -166,15 +210,39 @@ public class ComposeMessageFragment extends Fragment {
} }
} }
} }
Singleton.getBitmessageContext(getContext()).send(identity, recipient, builder = new Plaintext.Builder(MSG)
.from(identity)
.to(recipient);
}
switch (encoding) {
case SIMPLE:
builder.message(
subjectInput.getText().toString(), subjectInput.getText().toString(),
bodyInput.getText().toString()); bodyInput.getText().toString()
} );
getActivity().finish(); break;
return true; case EXTENDED:
builder.message(
new ExtendedEncoding.Builder()
.message()
.subject(subjectInput.getText().toString())
.body(bodyInput.getText().toString())
.build()
);
break;
default: default:
return super.onOptionsItemSelected(item); Toast.makeText(
getContext(),
getContext().getString(R.string.error_unsupported_encoding, encoding),
Toast.LENGTH_LONG
).show();
builder.message(
subjectInput.getText().toString(),
bodyInput.getText().toString()
);
} }
bmc.send(builder.build());
getActivity().finish();
} }
} }

View File

@ -0,0 +1,98 @@
/*
* Copyright 2016 Christian Basler
*
* 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.
*/
package ch.dissem.apps.abit.dialog;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatDialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioGroup;
import android.widget.Toast;
import ch.dissem.apps.abit.ImportIdentityActivity;
import ch.dissem.apps.abit.MainActivity;
import ch.dissem.apps.abit.R;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Plaintext;
import ch.dissem.bitmessage.entity.payload.Pubkey;
import static android.app.Activity.RESULT_OK;
import static ch.dissem.apps.abit.ComposeMessageActivity.EXTRA_ENCODING;
import static ch.dissem.bitmessage.entity.Plaintext.Encoding.EXTENDED;
import static ch.dissem.bitmessage.entity.Plaintext.Encoding.SIMPLE;
/**
* @author Christian Basler
*/
public class SelectEncodingDialogFragment extends AppCompatDialogFragment {
private Plaintext.Encoding encoding;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
if (getArguments() != null && getArguments().containsKey(EXTRA_ENCODING)) {
encoding = (Plaintext.Encoding) getArguments().getSerializable(EXTRA_ENCODING);
}
if (encoding == null) {
encoding = SIMPLE;
}
getDialog().setTitle(R.string.select_encoding_title);
View view = inflater.inflate(R.layout.dialog_select_message_encoding, container, false);
final RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.radioGroup);
switch (encoding) {
case SIMPLE:
radioGroup.check(R.id.simple);
break;
case EXTENDED:
radioGroup.check(R.id.extended);
break;
}
view.findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (radioGroup.getCheckedRadioButtonId()) {
case R.id.extended:
encoding = EXTENDED;
break;
case R.id.simple:
break;
default:
encoding = SIMPLE;
return;
}
Intent result = new Intent();
result.putExtra(EXTRA_ENCODING, encoding);
getTargetFragment().onActivityResult(getTargetRequestCode(), RESULT_OK, result);
dismiss();
}
});
view.findViewById(R.id.dismiss).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
return view;
}
}

View File

@ -199,8 +199,6 @@ public class AndroidAddressRepository implements AddressRepository {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
address.getPubkey().writeUnencrypted(out); address.getPubkey().writeUnencrypted(out);
values.put(COLUMN_PUBLIC_KEY, out.toByteArray()); values.put(COLUMN_PUBLIC_KEY, out.toByteArray());
} else {
values.put(COLUMN_PUBLIC_KEY, (byte[]) null);
} }
if (address.getPrivateKey() != null) { if (address.getPrivateKey() != null) {
values.put(COLUMN_PRIVATE_KEY, Encode.bytes(address.getPrivateKey())); values.put(COLUMN_PRIVATE_KEY, Encode.bytes(address.getPrivateKey()));

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Christian Basler
~
~ 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M8,3A2,2 0 0,0 6,5V9A2,2 0 0,1 4,11H3V13H4A2,2 0 0,1 6,15V19A2,2 0 0,0 8,21H10V19H8V14A2,2 0 0,0 6,12A2,2 0 0,0 8,10V5H10V3M16,3A2,2 0 0,1 18,5V9A2,2 0 0,0 20,11H21V13H20A2,2 0 0,0 18,15V19A2,2 0 0,1 16,21H14V19H16V14A2,2 0 0,1 18,12A2,2 0 0,1 16,10V5H14V3H16Z" />
</vector>

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2016 Christian Basler
~
~ 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.
-->
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="18dp"
android:paddingEnd="24dp"
android:paddingStart="24dp"
android:paddingTop="18dp">
<TextView
android:id="@+id/description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/select_encoding_warning"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintTop_creator="1"/>
<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingBottom="24dp"
android:paddingTop="24dp"
app:layout_constraintLeft_toLeftOf="@+id/description"
app:layout_constraintRight_toRightOf="@+id/description"
app:layout_constraintTop_toBottomOf="@+id/description">
<RadioButton
android:id="@+id/simple"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:text="SIMPLE"/>
<RadioButton
android:id="@+id/extended"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:text="EXTENDED"/>
</RadioGroup>
<Button
android:id="@+id/ok"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ok"
android:textColor="@color/colorAccent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintRight_toRightOf="@+id/radioGroup"
app:layout_constraintTop_toBottomOf="@+id/radioGroup"
tools:layout_constraintRight_creator="1"
tools:layout_constraintTop_creator="1"/>
<Button
android:id="@+id/dismiss"
style="?android:attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel"
android:textColor="@color/colorAccent"
app:layout_constraintRight_toLeftOf="@+id/ok"
app:layout_constraintTop_toBottomOf="@+id/radioGroup"/>
</android.support.constraint.ConstraintLayout>

View File

@ -6,4 +6,10 @@
app:showAsAction="always" app:showAsAction="always"
android:icon="@drawable/ic_action_send" android:icon="@drawable/ic_action_send"
android:title="@string/send"/> android:title="@string/send"/>
<item
android:id="@+id/select_encoding"
app:showAsAction="never"
android:icon="@drawable/ic_action_encoding"
android:title="Select encoding"
/>
</menu> </menu>

View File

@ -110,4 +110,5 @@ Als Alternative kann in den Einstellungen ein vertrauenswürdiger Knoten konfigu
<string name="status_received">empfangen</string> <string name="status_received">empfangen</string>
<string name="status_sent">gesendet</string> <string name="status_sent">gesendet</string>
<string name="status_sent_acknowledged">Empfang bestätigt</string> <string name="status_sent_acknowledged">Empfang bestätigt</string>
<string name="error_unsupported_encoding">Codierung %s wird nicht unterstützt, es wird SIMPLE verwendet.</string>
</resources> </resources>

View File

@ -109,4 +109,7 @@ As an alternative you could configure a trusted node in the settings, but as of
<string name="status_sent">sent</string> <string name="status_sent">sent</string>
<string name="status_received">received</string> <string name="status_received">received</string>
<string name="outbox">Outbox</string> <string name="outbox">Outbox</string>
<string name="error_unsupported_encoding">Unsupported encoding %s, using SIMPLE instead.</string>
<string name="select_encoding_warning">EXTENDED is a new encoding that\s not widely supported yet but has some interesting features. To stay on the save side, select SIMPLE.</string>
<string name="select_encoding_title">Select Message Encoding</string>
</resources> </resources>