Browse Source

added qr code in AddContactActivity,
design improvements,

Sofian Benissa 3 years ago
parent
commit
19b6f4f765

+ 4 - 2
app/build.gradle

@@ -7,7 +7,7 @@ android {
         targetCompatibility JavaVersion.VERSION_1_8
     }
     defaultConfig {
-        applicationId "com.dx.anonymousmessenger"
+        applicationId "com.example.anonymousmessenger"
         minSdkVersion 23
         targetSdkVersion 30
         versionCode 17
@@ -54,7 +54,9 @@ dependencies {
     implementation project(path: ':T0rlib4Droid')
 //    implementation project(path: ':libsignal-protocol-java')
 //    implementation 'org.whispersystems:signal-protocol-android:2.8.1'
-    implementation 'com.google.protobuf:protobuf-java:3.9.2'
+    implementation 'com.google.zxing:core:3.0.1'
+    implementation 'me.dm7.barcodescanner:zxing:1.9.13'
+    implementation 'com.google.protobuf:protobuf-java:3.9.2' //later versions min api 26+
     implementation 'androidx.recyclerview:recyclerview:1.1.0'
     implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
     testImplementation 'junit:junit:4.13.1'

+ 2 - 0
app/src/main/AndroidManifest.xml

@@ -3,6 +3,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     package="com.dx.anonymousmessenger">
 
+    <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
@@ -28,6 +29,7 @@
         android:theme="@style/AppTheme"
         tools:replace="android:allowBackup"
         android:extractNativeLibs="true">
+        <activity android:name=".qr.SimpleScannerActivity" />
         <activity android:name=".NotepadActivity" />
         <activity android:name=".FileViewerActivity" />
         <activity android:name=".TipsActivity" />

+ 118 - 2
app/src/main/java/com/dx/anonymousmessenger/AddContactActivity.java

@@ -1,30 +1,47 @@
 package com.dx.anonymousmessenger;
 
+import android.Manifest;
 import android.app.AlertDialog;
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.os.Bundle;
 import android.os.Looper;
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.transition.Explode;
 import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.ImageView;
 import android.widget.TextView;
 import android.widget.Toast;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.content.ContextCompat;
 
 import com.dx.anonymousmessenger.db.DbHelper;
 import com.dx.anonymousmessenger.messages.MessageSender;
+import com.dx.anonymousmessenger.qr.SimpleScannerActivity;
 import com.dx.anonymousmessenger.tor.TorClientSocks4;
 import com.google.android.material.snackbar.Snackbar;
 import com.google.android.material.textfield.TextInputEditText;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.QRCodeWriter;
 
 import org.whispersystems.libsignal.SignalProtocolAddress;
 
+import java.util.ArrayList;
 import java.util.Objects;
 
 import static android.content.ClipDescription.MIMETYPE_TEXT_PLAIN;
@@ -33,6 +50,8 @@ public class AddContactActivity extends AppCompatActivity {
 
     TextView tv;
     TextInputEditText contact;
+    final int QR_RESULT_CODE = 0;
+    final int CAMERA_REQUEST_CODE = 1;
 
     @Override
     public boolean onSupportNavigateUp() {
@@ -107,7 +126,9 @@ public class AddContactActivity extends AppCompatActivity {
                                         MessageSender.sendKeyExchangeMessage((DxApplication)getApplication(),s.toString().trim());
                                     }
                                 }
-                                finish();
+                                runOnUiThread(()->{
+                                    finish();
+                                });
                             }catch (Exception e){
                                 e.printStackTrace();
                                 Log.e("FAILED TO SAVE CONTACT", "SAME " );
@@ -128,6 +149,60 @@ public class AddContactActivity extends AppCompatActivity {
             }
         });
 
+        Button scan = findViewById(R.id.btn_scan_contact);
+        scan.setOnClickListener((v)->{
+            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
+                Intent intent = new Intent(this,SimpleScannerActivity.class);
+                intent.putExtra("SCAN_MODE", "ADD_CONTACT");
+                startActivityForResult(intent, QR_RESULT_CODE);
+            }else{
+                requestPermissions(
+                    new String[] { Manifest.permission.CAMERA },
+                    CAMERA_REQUEST_CODE);
+            }
+        });
+
+        QRCodeWriter writer = new QRCodeWriter();
+        try {
+            BitMatrix bitMatrix = writer.encode(((DxApplication)getApplication()).getHostname(), BarcodeFormat.QR_CODE, 512, 512);
+            int width = bitMatrix.getWidth();
+            int height = bitMatrix.getHeight();
+            Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+            for (int x = 0; x < width; x++) {
+                for (int y = 0; y < height; y++) {
+                    bmp.setPixel(x, y, bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE);
+                }
+            }
+            ImageView qr = ((ImageView) findViewById(R.id.qr_my_address));
+            qr.setImageBitmap(bmp);
+            qr.setOnClickListener((v) -> {
+                try{
+                    ImageView newQr = new ImageView(context);
+                    newQr.setImageBitmap(bmp);
+//                    newQr.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+                    ViewGroup parentViewGroup = (ViewGroup) newQr.getParent();
+                    if (parentViewGroup != null) {
+                        parentViewGroup.removeView(newQr);
+                        parentViewGroup.removeAllViews();
+                    }
+                    View view = new View(context);
+                    ArrayList<View>  viewArrayList = new ArrayList<>();
+                    viewArrayList.add(newQr);
+                    view.addChildrenForAccessibility(viewArrayList);
+                    AlertDialog.Builder builder =
+                        new AlertDialog.Builder(context).
+                            setMessage("Message above the image").
+                            setPositiveButton("OK", (dialog, which) -> dialog.dismiss()).
+                            setView(newQr);
+                    builder.create().show();
+                }catch (Exception e) {
+                    e.printStackTrace();
+                }
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
         Thread.setDefaultUncaughtExceptionHandler((paramThread, paramThrowable) -> {
             new Thread() {
                 @Override
@@ -170,7 +245,7 @@ public class AddContactActivity extends AppCompatActivity {
 
                     new AlertDialog.Builder(context,R.style.AppAlertDialog)
                             .setTitle(R.string.add_contact)
-                            .setMessage(getString(R.string.confirm_add_contact)+s.toString()+" ?")
+                            .setMessage(getString(R.string.confirm_add_contact)+s+" ?")
                             .setIcon(android.R.drawable.ic_dialog_alert)
                             .setPositiveButton(android.R.string.yes, (dialog, whichButton) -> new Thread(() ->
                             {
@@ -198,4 +273,45 @@ public class AddContactActivity extends AppCompatActivity {
             }
         }
     }
+
+    public void getCameraPerms(){
+        if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
+            new AlertDialog.Builder(getApplicationContext(),R.style.AppAlertDialog)
+                .setTitle(R.string.cam_perm_ask_title)
+                .setMessage(R.string.why_need_cam)
+                .setIcon(android.R.drawable.ic_dialog_alert)
+                .setPositiveButton(R.string.ask_for_cam_btn, (dialog, which) -> requestPermissions(
+                        new String[] { Manifest.permission.CAMERA },
+                        CAMERA_REQUEST_CODE))
+                .setNegativeButton(R.string.no_thanks, (dialog, which) -> {
+                });
+        } else {
+            requestPermissions(
+                new String[] { Manifest.permission.CAMERA },
+                CAMERA_REQUEST_CODE);
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (requestCode == QR_RESULT_CODE) {
+            if (resultCode == RESULT_OK) {
+                finish();
+            }
+        }
+    }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+        if (requestCode == CAMERA_REQUEST_CODE) {
+            new AlertDialog.Builder(this,R.style.AppAlertDialog)
+                .setTitle(R.string.denied_microphone)
+                .setMessage(R.string.denied_microphone_help)
+                .setIcon(android.R.drawable.ic_dialog_alert)
+                .setPositiveButton(R.string.ask_me_again, (dialog, which) -> getCameraPerms())
+                .setNegativeButton(R.string.no_thanks, (dialog, which) -> {
+                });
+        }
+    }
 }

+ 25 - 37
app/src/main/java/com/dx/anonymousmessenger/MessageListActivity.java

@@ -774,6 +774,19 @@ public class MessageListActivity extends AppCompatActivity implements ActivityCo
 
     @Override
     public void onBackPressed() {
+        if(mediaRecyclerView.getVisibility()==View.VISIBLE){
+            mediaRecyclerView.setVisibility(View.GONE);
+            send.setVisibility(View.VISIBLE);
+            audio.setVisibility(View.VISIBLE);
+            file.setVisibility(View.VISIBLE);
+            txt.setVisibility(View.VISIBLE);
+            if(quoteTextTyping.getText().length()>0){
+                quoteTextTyping.setVisibility(View.VISIBLE);
+                quoteSenderTyping.setVisibility(View.VISIBLE);
+            }
+            picsHelp.setVisibility(View.GONE);
+            return;
+        }
         super.onBackPressed();
         onSupportNavigateUp();
     }
@@ -878,27 +891,15 @@ public class MessageListActivity extends AppCompatActivity implements ActivityCo
 
     @Override
     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
-        if (requestCode == REQUEST_CODE) {// If request is cancelled, the result arrays are empty.
-//            if (grantResults.length > 0 &&
-//                    grantResults[0] == PackageManager.PERMISSION_GRANTED) {
-//                // Permission is granted. Continue the action or workflow
-//                // in your app.
-//            } else {
-                new AlertDialog.Builder(this,R.style.AppAlertDialog)
-                        .setTitle(R.string.denied_microphone)
-                        .setMessage(R.string.denied_microphone_help)
-                        .setIcon(android.R.drawable.ic_dialog_alert)
-                        .setPositiveButton(R.string.ask_me_again, (dialog, which) -> getMicrophonePerms())
-                        .setNegativeButton(R.string.no_thanks, (dialog, which) -> {
-                        });
-                // Explain to the user that the feature is unavailable because
-                // the features requires a permission that the user has denied.
-                // At the same time, respect the user's decision. Don't link to
-                // system settings in an effort to convince the user to change
-                // their decision.
-//            }
-        }//else if(requestCode == READ_STORAGE_REQUEST_CODE){
-        //}
+        if (requestCode == REQUEST_CODE) {
+            new AlertDialog.Builder(this,R.style.AppAlertDialog)
+                .setTitle(R.string.denied_microphone)
+                .setMessage(R.string.denied_microphone_help)
+                .setIcon(android.R.drawable.ic_dialog_alert)
+                .setPositiveButton(R.string.ask_me_again, (dialog, which) -> getMicrophonePerms())
+                .setNegativeButton(R.string.no_thanks, (dialog, which) -> {
+                });
+        }
     }
 
 //    @Override
@@ -939,17 +940,7 @@ public class MessageListActivity extends AppCompatActivity implements ActivityCo
     }
 
     public void getMicrophonePerms(){
-//        if (ContextCompat.checkSelfPermission(
-//                this, Manifest.permission.RECORD_AUDIO) ==
-//                PackageManager.PERMISSION_GRANTED) {
-//            // You can use the API that requires the permission.
-//
-//        } else
-            if (shouldShowRequestPermissionRationale(Manifest.permission.RECORD_AUDIO)) {
-            // In an educational UI, explain to the user why your app requires this
-            // permission for a specific feature to behave as expected. In this UI,
-            // include a "cancel" or "no thanks" button that allows the user to
-            // continue using your app without granting the permission.
+        if (shouldShowRequestPermissionRationale(Manifest.permission.RECORD_AUDIO)) {
             new AlertDialog.Builder(getApplicationContext(),R.style.AppAlertDialog)
                 .setTitle(R.string.mic_perm_ask_title)
                 .setMessage(R.string.why_need_mic)
@@ -958,14 +949,11 @@ public class MessageListActivity extends AppCompatActivity implements ActivityCo
                         new String[] { Manifest.permission.RECORD_AUDIO },
                         REQUEST_CODE))
                 .setNegativeButton(R.string.no_thanks, (dialog, which) -> {
-
                 });
         } else {
-            // You can directly ask for the permission.
-            // The registered ActivityResultCallback gets the result of this request.
             requestPermissions(
-                    new String[] { Manifest.permission.RECORD_AUDIO },
-                    REQUEST_CODE);
+                new String[] { Manifest.permission.RECORD_AUDIO },
+                REQUEST_CODE);
         }
     }
 

+ 2 - 2
app/src/main/java/com/dx/anonymousmessenger/VerifyIdentityActivity.java

@@ -36,9 +36,9 @@ public class VerifyIdentityActivity extends AppCompatActivity {
                 byte[] theirKey =
                         ((DxApplication) getApplication()).getEntity().getStore().getIdentity(new SignalProtocolAddress(fullAddress,1)).serialize();
                 if(myKey==theirKey){
-                    tv.setText(Hex.toString(myKey));
+                    runOnUiThread(()-> tv.setText(Hex.toString(myKey)));
                 }else{
-                    tv.setText(Hex.toString(myKey,theirKey));
+                    runOnUiThread(()-> tv.setText(Hex.toString(myKey,theirKey)));
                 }
             }catch (Exception ignored) {
                 runOnUiThread(()-> tv.setText(R.string.identity_verification_fail));

+ 1 - 0
app/src/main/java/com/dx/anonymousmessenger/messages/MessageListAdapter.java

@@ -449,6 +449,7 @@ public class MessageListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHo
                         notifyDataSetChanged();
                         notifyItemChanged(mMessageList.indexOf(message));
                         playPauseButton.setImageDrawable(getDrawable(mContext,R.drawable.ic_baseline_play_arrow_24));
+                        //todo if screen on play the next one
                     }catch (Exception e) {e.printStackTrace();}
                 };
                 mainHandler.post(myRunnable);

+ 110 - 0
app/src/main/java/com/dx/anonymousmessenger/qr/SimpleScannerActivity.java

@@ -0,0 +1,110 @@
+package com.dx.anonymousmessenger.qr;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.dx.anonymousmessenger.DxApplication;
+import com.dx.anonymousmessenger.R;
+import com.dx.anonymousmessenger.db.DbHelper;
+import com.dx.anonymousmessenger.messages.MessageSender;
+import com.dx.anonymousmessenger.tor.TorClientSocks4;
+import com.google.android.material.snackbar.Snackbar;
+import com.google.zxing.Result;
+
+import org.whispersystems.libsignal.SignalProtocolAddress;
+
+import me.dm7.barcodescanner.zxing.ZXingScannerView;
+
+public class SimpleScannerActivity extends Activity implements ZXingScannerView.ResultHandler {
+    private ZXingScannerView mScannerView;
+
+    @Override
+    public void onCreate(Bundle state) {
+        super.onCreate(state);
+        mScannerView = new ZXingScannerView(this);   // Programmatically initialize the scanner view
+        setContentView(mScannerView);                // Set the scanner view as the content view
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+//        mScannerView.setFlash(true);
+//        mScannerView.setAutoFocus(true);
+        mScannerView.setBorderColor(getColor(R.color.dx_night_940));
+        mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
+        mScannerView.startCamera();          // Start camera on resume
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mScannerView.stopCamera();           // Stop camera on pause
+    }
+
+    @Override
+    public void handleResult(Result rawResult) {
+        String s = rawResult.getText();
+
+        new Thread(()->{
+            //add the contact if valid
+            if(s.equals(((DxApplication)getApplication()).getHostname())){
+                runOnUiThread(()->{
+                    Snackbar.make(mScannerView, R.string.cant_add_self,Snackbar.LENGTH_SHORT).show();
+                    finish();
+                });
+                return;
+            }
+            if(s.trim().length()<56 || !s.trim().endsWith(".onion")){
+                runOnUiThread(()->{
+                    mScannerView.resumeCameraPreview(this);
+                });
+                return;
+            }
+            try{
+                if(DbHelper.contactExists(s,(DxApplication)getApplication())){
+                    runOnUiThread(()->{
+                        Snackbar.make(mScannerView, R.string.contact_exists,Snackbar.LENGTH_SHORT).show();
+                        finish();
+                    });
+                    return;
+                }
+
+                boolean b = DbHelper.saveContact(s.trim(), ((DxApplication) getApplication()));
+                if(!b){
+                    Log.e("FAILED TO SAVE CONTACT", "SAME " );
+                    runOnUiThread(()->{
+                        Snackbar.make(mScannerView, R.string.cant_add_contact,Snackbar.LENGTH_SHORT).show();
+                        finish();
+                    });
+                    return;
+                }
+                runOnUiThread(()->{
+                    Snackbar.make(mScannerView, R.string.contact_added,Snackbar.LENGTH_SHORT).show();
+                    if (getParent() == null) {
+                        setResult(Activity.RESULT_OK);
+                    } else {
+                        getParent().setResult(Activity.RESULT_OK);
+                    }
+                });
+                if(TorClientSocks4.testAddress((DxApplication)getApplication(),s.trim())){
+                    if(!((DxApplication)getApplication()).getEntity().getStore().containsSession(new SignalProtocolAddress(s.trim(),1))){
+                        MessageSender.sendKeyExchangeMessage((DxApplication)getApplication(),s.trim());
+                    }
+                }
+                finish();
+                return;
+            }catch (Exception e){
+                e.printStackTrace();
+                Log.e("FAILED TO SAVE CONTACT", "SAME " );
+                runOnUiThread(()->{
+                    Snackbar.make(mScannerView, R.string.cant_add_contact,Snackbar.LENGTH_SHORT).show();
+                    finish();
+                });
+            }
+            // If you would like to resume scanning, call this method below:
+            mScannerView.resumeCameraPreview(this);
+        }).start();
+    }
+}
+

+ 1 - 1
app/src/main/java/com/dx/anonymousmessenger/tor/ServerSocketViaTor.java

@@ -185,9 +185,9 @@ public class ServerSocketViaTor {
 //                    }
                     Socket sock = socket.accept();
                     if(sockets.get() >= ALLOWED_CONCURRENT_CONNECTIONS){
+                        sock.close();
                         Log.e("TOO MANY SOCKETS","open sockets: "+sockets);
 //                        Thread.sleep(200);
-                        sock.close();
                         continue;
                     }
                     sockets.getAndIncrement();

+ 0 - 140
app/src/main/java/com/dx/anonymousmessenger/tor/ServerSocketViaTorV3.java

@@ -1,140 +0,0 @@
-//package com.dx.anonymousmessenger.tor;
-//
-//import android.content.Context;
-//import android.util.Log;
-//
-//import com.dx.anonymousmessenger.DxApplication;
-//import com.jrummyapps.android.shell.CommandResult;
-//import com.jrummyapps.android.shell.Shell;
-//
-//import net.sf.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
-//
-//import org.torproject.android.binary.TorResourceInstaller;
-//
-//import java.io.DataInputStream;
-//import java.io.DataOutputStream;
-//import java.io.File;
-//import java.io.IOException;
-//import java.net.InetSocketAddress;
-//import java.net.Socket;
-//import java.net.SocketAddress;
-//import java.net.SocketException;
-//
-//public class ServerSocketViaTorV3 {
-//    private static final int READ_TIMEOUT_MILLISECONDS = 30000;
-//    private static final int CONNECT_TIMEOUT_MILLISECONDS = 60000;
-//    public void moin(Context ctx){
-//    try {
-//        TorResourceInstaller torResourceInstaller = new TorResourceInstaller(ctx , ctx.getFilesDir());
-//
-//        File fileTorBin = torResourceInstaller.installResources();
-//        File fileTorRc = torResourceInstaller.getTorrcFile();
-//
-//        boolean success = fileTorBin != null && fileTorBin.canExecute();
-//
-//        String message = "Tor install success? " + success;
-//        logNotice(message);
-//
-//        if (success) {
-//            runTorShellCmd(fileTorBin, fileTorRc, ctx);
-////            torResourceInstaller.updateTorConfigCustom()
-//        }
-//
-//
-//
-//    } catch (Exception e) {
-//        e.printStackTrace();
-//        logNotice(e.getMessage());
-//    }
-//}
-//
-//    public Socket socks4aConnection(String networkHost,int networkPort,String socksHost,int socksPort) throws IOException {
-////        String socksHost = "127.0.0.1";
-////        int socksPort = 9050;
-////        String networkHost = "";
-////        int networkPort = 5780;
-//        Socket socket = new Socket();
-//        socket.setSoTimeout(READ_TIMEOUT_MILLISECONDS);
-//        SocketAddress socksAddress = new InetSocketAddress(socksHost, socksPort);
-//        socket.connect(socksAddress, CONNECT_TIMEOUT_MILLISECONDS);
-//
-//        DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
-//        outputStream.write((byte) 0x04);
-//        outputStream.write((byte) 0x01);
-//        outputStream.writeShort((short) networkPort);
-//        outputStream.writeInt(0x01);
-//        outputStream.write((byte) 0x00);
-//        outputStream.write(networkHost.getBytes());
-//        outputStream.write((byte) 0x00);
-//
-//        DataInputStream inputStream = new DataInputStream(socket.getInputStream());
-//        byte firstByte = inputStream.readByte();
-//        byte secondByte = inputStream.readByte();
-//        if (firstByte != (byte) 0x00 || secondByte != (byte) 0x5a) {
-//            socket.close();
-//            throw new IOException("SOCKS4a connect failed, got " + firstByte + " - " + secondByte +
-//                    ", but expected 0x00 - 0x5a");
-//        }
-//        inputStream.readShort();
-//        inputStream.readInt();
-//        return socket;
-//    }
-//
-//    private void logNotice(String notice) {
-//        Log.d(notice, notice);
-//    }
-//
-//    private void logNotice(String notice, Exception e) {
-//        logNotice(notice);
-//        Log.e("SampleTor", "error occurred", e);
-//    }
-//
-//    private boolean runTorShellCmd(File fileTor, File fileTorrc, Context ctx) throws Exception {
-//        File appCacheHome = ctx.getDir(SampleTorServiceConstants.DIRECTORY_TOR_DATA, DxApplication.MODE_PRIVATE);
-//
-//        if (!fileTorrc.exists()) {
-//            logNotice("torrc not installed: " + fileTorrc.getCanonicalPath());
-//            return false;
-//        }
-//
-//        String torCmdString = fileTor.getCanonicalPath()
-//                + " DataDirectory " + appCacheHome.getCanonicalPath()
-//                + " --defaults-torrc " + fileTorrc;
-//
-//        int exitCode = -1;
-//
-//        try {
-//            exitCode = exec(torCmdString + " --verify-config", true);
-//        } catch (Exception e) {
-//            logNotice("Tor configuration did not verify: " + e.getMessage(), e);
-//            return false;
-//        }
-//
-//        try {
-//            exitCode = exec(torCmdString, true);
-//        } catch (Exception e) {
-//            logNotice("Tor was unable to start: " + e.getMessage(), e);
-//            return false;
-//        }
-//
-//        if (exitCode != 0) {
-//            logNotice("Tor did not start. Exit:" + exitCode);
-//            return false;
-//        }
-//
-//        return true;
-//    }
-//
-//
-//    private int exec(String cmd, boolean wait) throws Exception {
-//        CommandResult shellResult = Shell.run(cmd);
-//
-//        //  debug("CMD: " + cmd + "; SUCCESS=" + shellResult.isSuccessful());
-//
-//        if (!shellResult.isSuccessful()) {
-//            throw new Exception("Error: " + shellResult.exitCode + " ERR=" + shellResult.getStderr() + " OUT=" + shellResult.getStdout());
-//        }
-//
-//        return shellResult.exitCode;
-//    }
-//}

+ 1 - 1
app/src/main/res/drawable/rounded_shape.xml

@@ -4,7 +4,7 @@
     android:shape="rectangle"   >
     <gradient
         android:startColor="#2E0027"
-        android:endColor="#17061E"
+        android:endColor="#2E0027"
         android:angle="180"/>
 <!--    <solid-->
 <!--        android:color="@color/dx_brand_green" >-->

+ 34 - 9
app/src/main/res/layout/activity_add_contact.xml

@@ -1,42 +1,57 @@
 <?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    xmlns:android="http://schemas.android.com/apk/res/android">
+    android:layout_margin="4dp"
+    android:layout_marginTop="0dp"
+    android:layout_marginBottom="8dp">
+
+    <Button
+        android:id="@+id/btn_scan_contact"
+        style="@style/DXSendButton"
+        android:layout_width="64dp"
+        android:layout_height="45dp"
+        android:layout_margin="8dp"
+        android:animateLayoutChanges="true"
+        android:background="@drawable/button_ripple"
+        android:text="@string/scan"
+        app:layout_constraintBottom_toBottomOf="@+id/qr_my_address"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@+id/qr_my_address"
+        app:layout_constraintTop_toTopOf="@+id/qr_my_address" />
 
     <TextView
         android:id="@+id/txt_lbl_myaddress"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="16dp"
         android:fontFamily="monospace"
         android:padding="20dp"
         android:text="@string/myaddress"
         android:textSize="22sp"
-        app:layout_constraintBottom_toTopOf="@+id/txt_myaddress"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent" />
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
 
     <TextView
         android:id="@+id/txt_myaddress"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_margin="14dp"
+        android:layout_margin="8dp"
         android:background="@drawable/button_ripple"
         android:padding="24dp"
         android:text="@string/myaddress"
         android:textSize="@dimen/text_size_large"
-        app:layout_constraintBottom_toTopOf="@+id/txt_lbl_contact_address"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintHorizontal_bias="0.498"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
+        app:layout_constraintTop_toBottomOf="@+id/txt_lbl_myaddress" />
 
     <TextView
         android:id="@+id/txt_lbl_contact_address"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_margin="40dp"
+        android:layout_margin="10dp"
         android:fontFamily="monospace"
         android:padding="20dp"
         android:text="@string/lbl_contact_address"
@@ -66,4 +81,14 @@
             android:textSize="@dimen/text_size_medium" />
     </com.google.android.material.textfield.TextInputLayout>
 
+    <ImageView
+        android:id="@+id/qr_my_address"
+        android:layout_width="100dp"
+        android:layout_height="100dp"
+        android:layout_margin="8dp"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/txt_myaddress"
+        app:srcCompat="@drawable/ic_stat_name" />
+
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 4 - 1
app/src/main/res/layout/activity_message_list.xml

@@ -228,6 +228,8 @@
             android:id="@+id/layout_pics"
             android:layout_width="0dp"
             android:layout_height="match_parent"
+            android:layout_marginTop="15dp"
+            android:layout_marginBottom="15dp"
             android:animateLayoutChanges="true"
             android:background="#DA221E2A"
             android:orientation="horizontal"
@@ -244,7 +246,7 @@
                 android:layout_weight="0.25"
                 android:animateLayoutChanges="true"
                 android:contentDescription="@string/recording"
-                app:srcCompat="@android:drawable/ic_menu_report_image" />
+                app:srcCompat="@android:drawable/ic_menu_revert" />
 
             <TextView
                 android:id="@+id/txt_pic_help"
@@ -256,6 +258,7 @@
                 android:gravity="center"
                 android:text="@string/pic_help"
                 android:textColor="@color/red_500"
+                android:textSize="24sp"
                 android:textStyle="bold" />
         </LinearLayout>
 

+ 5 - 0
app/src/main/res/values/strings.xml

@@ -272,5 +272,10 @@
     <string name="delete_note">Delete</string>
     <string name="open_link_question">Open this link?</string>
     <string name="open_link_describe">Opening links outside tor browser could deanonymize you, only do this if you trust the link or use tor browser</string>
+    <string name="scan">Scan QR-code</string>
+    <string name="contact_added">Added contact</string>
+    <string name="cam_perm_ask_title">Camera permission</string>
+    <string name="why_need_cam">QR scanning won\'t work without camera permission</string>
+    <string name="ask_for_cam_btn">Ok</string>
 
 </resources>

+ 63 - 0
log.txt

@@ -0,0 +1,63 @@
+1611573537|9fd0c24b-bumped to version 0.6.5 vc17, new release.
+1611525266|8ed98d90-bumped to version 0.6.5 vc17, new release.
+1611524489|9fc35385-design fixes, added auto add contact from clipboard in add contact view.
+1611513788|586468fd-added SignalProtocol to the project,
+1611429754|7a37fcfa-added a warning when opening links, made form colors better for visibility.
+1611014772|a3d2d8ec-took out a non-needed library
+1610889310|f9988e52-changed to com.dx.anonymousmessenger.
+1610822034|0729920c-added app metadata to repo for fdroid.
+1610801880|ca3b35d9-Merge branch 'master' of https://github.com/AnonymousMessenger/AnonymousMessenger
+1610801484|22ba6bf5-Merge branch 'master' of https://git.anonymousmessenger.ly/dx/AnonymousMessenger
+1610766042|cb0fd82d-many fixes and some design changes.
+1610568658|baac6e3e-Add 'LICENSE'
+1610562418|daf5185f-Update README.md
+1610562384|df0ac7e8-Update README.md
+1610561314|a3005bc0-Update README.md
+1610561257|9d7aba8e-Merge pull request #1 from AnonymousMessenger/add-license-1
+1610561218|53d4f150-Create LICENSE
+1610561031|3f130e59-Create README.md
+1610557920|b5811dc0-few fixes here n there.
+1610545656|cca85893-added Estonian with a friend's help, version bump to 0.6.4-15,
+1610543702|68364b50-fixed jniLibs for Android 11 which is required for the play store,
+1609597852|9246bc16-added notepad,
+1609516415|b7182e09-android broadcasts now only have the first 10 digits of addresses, added DbHelper.getFullAddress that takes those 10 digits,
+1609449602|f704dc08-emojis are now 3x bigger in messages,
+1609321916|c424b723-Fixed refreshing messages in MessageListActivity and AppFragment, randomized local onion service port to allow more instances to run, added icon but its not perfect on every phone yet, added tor output and i18ned it, bug fixes,
+1608963441|0bdf981d-Changed icons to fawkes mask public domain picture
+1608850291|b1aa400a-More security tips added
+1608783463|7b17b8e9-DOS protection fixed
+1608771328|b2e3e229-fixing git history
+1608706866|79e7729f-temporarily disabled file sending, many bug fixes (key exchange, views, animations), added security tips, added about text,
+1605920294|d1e472e6-added file messages views,
+1605770644|2e2ec86b-removed video, fixed message delivery update, less MessageListActivity animation,
+1605750418|15465ba2-boot receiver reworked and fixed
+1605578849|7fb72dbe-password now only stored in binary in memory
+1605491628|c4fd886a-semi dns leak fixed
+1604169606|0dd62a9e-auto key exchange fixed, bug fixes, boot reminder added,
+1603731665|1f877458-auto key exchange added with pinging, better syncing, bug fixes, attempt on video playing EncryptedDataSource failed but there's still hope, started using version code, more translations available, license view added but needs work, about and help pages to be filled with text later, less tor output to save memory,
+1602558888|e9d529ef-better syncing, my profile view added, can change nickname, AudioPlayer improved, bug fixes,
+1602499891|000b0f5b-saving images to shared storage done, bug fixes,
+1602187274|27dd5e36-added sending/displaying/fullscreen/receiving images with captions, bug fixes, removed extra images from apk,
+1602187159|7b7470b9-added sending/displaying/fullscreen/receiving images with captions, bug fixes, removed extra images from apk,
+1601730155|cf74945b-some design improvements (a few), global error catching, syncing stabilized,
+1601675844|47c0a841-some design improvements (a few), less output on hold up, split tor output into two intents, some memory management changes, syncing is done right after online checks in AppFragment, deleting files with messages done, some flow enhancements, more try's, more threads,
+1601136877|5f409f7b-many more design improvements (a few), scroll down button stabilized, added gotoContact and restart tor buttons to hold up, fixed AppActivity init bugs, fixed hold up  goto AppActivity, some memory management changes, some strings moved to values,
+1601101900|e2ecabab-many more design improvements (a lot), scroll down button added to MessageListActivity,
+1600990744|9655eb92-some design improvements (buttons n such), quoted message fast travel done, some cleaning work
+1600976093|e74b71e5-some design improvements (contact item), really really fixed an issue with changing contacts nickname in MessageListActivity
+1600972447|f199263e-some design improvements (send button), really fixed an issue with changing contacts nickname in MessageListActivity
+1600968945|3832050b-some design improvements, fixed an issue with changing contacts nickname in MessageListActivity fixed duplicate response key exchange message,
+1600967341|6ae3a930-finally the audio message part is fully functional now, needs some design improvements, AudioPlayer has an issue when ui updates, need to use same code for pictures, need to encrypt tor files,
+1599423032|f97b8838-better views for dark mode including dialog (again) other fixes and improvements like the mute/speaker buttons in call
+1599354570|907b8e21-better views for dark mode including dialog fixed tor restart (again)
+1599168840|b779e779-code inspection fixes
+1599164304|bf6216b9-minor improvements
+1599108985|f8aaa51f-calls are much better now memory leaks i think needs a full recheck views and performance i think still ok but do better keyexchange for users eyes calls are there but need some work do send files n pics n audio n video needs a profile view and settings view
+1598532109|11d9a9f4-memory leaks i think still ok views and performance i think still ok change AddContactFragment to activity done Signal protocol library added and working but do better keyexchange for users eyes calls are there but need ALOT of work do PTT, regular calls with resync every lag, stream mode do send files n pics n audio n video needs a profile view and settings view
+1597119495|73a98d2a-fixed memory leaks views and performance work done change AddContactFragment to activity Signal protocol library added needs a profile view and settings view
+1596913904|1f78a9d2-Messaging still fast, feels like the first time changed server and client code again (now very good) foreground service done with ConnectionStateMonitor all good fully recoverable from bad internet needs a better contact view ui with features like delete needs a profile view and settings view need to do seens n signal protocol
+1596224675|9fe8b881-Messaging changed to JsonObject for security but maybe slower? changed server and client code again (see if faster or not) redo login in MessageQueue need to do seens n signal protocol
+1596031835|9d17c88e-Messaging works really well n fast faster Server (by a lot) redo login in MessageQueue need to do seens n signal protocol
+1595926590|cd71b084-Messaging works needs deep debugging faster Server redo login in MessageQueue
+1595782258|9b3bc8ff-Setup is done secure storage is done need to work on design need to finish add contact
+1595113460|50ca6451-Setup is basically done need to do secure storage to save account and then go back to main activity and check if account is saved to start entry activity (to be written)