diff --git a/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java b/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java index 95ce443..704726d 100644 --- a/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java +++ b/app/src/main/java/ch/dissem/apps/abit/AddressDetailFragment.java @@ -20,13 +20,11 @@ import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; -import android.graphics.Bitmap; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.text.Editable; import android.text.TextWatcher; -import android.util.Base64; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -39,29 +37,14 @@ import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; -import com.google.zxing.BarcodeFormat; -import com.google.zxing.MultiFormatWriter; -import com.google.zxing.WriterException; -import com.google.zxing.common.BitMatrix; import com.mikepenz.community_material_typeface_library.CommunityMaterial; import com.mikepenz.google_material_typeface_library.GoogleMaterial; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - import ch.dissem.apps.abit.service.Singleton; import ch.dissem.apps.abit.util.Drawables; import ch.dissem.bitmessage.entity.BitmessageAddress; -import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.wif.WifExporter; -import static android.graphics.Color.BLACK; -import static android.graphics.Color.WHITE; -import static android.util.Base64.URL_SAFE; - /** * A fragment representing a single Message detail screen. @@ -70,7 +53,6 @@ import static android.util.Base64.URL_SAFE; * on handsets. */ public class AddressDetailFragment extends Fragment { - private static final Logger LOG = LoggerFactory.getLogger(AddressDetailFragment.class); /** * The fragment argument representing the item ID that this fragment * represents. @@ -78,8 +60,6 @@ public class AddressDetailFragment extends Fragment { public static final String ARG_ITEM = "item"; public static final String EXPORT_POSTFIX = ".keys.dat"; - private static final int QR_CODE_SIZE = 350; - /** * The content this fragment is presenting. */ @@ -263,50 +243,12 @@ public class AddressDetailFragment extends Fragment { // QR code ImageView qrCode = (ImageView) rootView.findViewById(R.id.qr_code); - qrCode.setImageBitmap(qrCode(item)); + qrCode.setImageBitmap(Drawables.qrCode(item)); } return rootView; } - Bitmap qrCode(BitmessageAddress address) { - StringBuilder link = new StringBuilder("bitmessage:"); - link.append(address.getAddress()); - if (address.getAlias() != null) { - link.append("?label=").append(address.getAlias()); - } - if (address.getPubkey() != null) { - link.append(address.getAlias() == null ? '?' : '&'); - ByteArrayOutputStream pubkey = new ByteArrayOutputStream(); - try { - address.getPubkey().writeUnencrypted(pubkey); - } catch (IOException e) { - throw new ApplicationException(e); - } - link.append("pubkey=").append(Base64.encodeToString(pubkey.toByteArray(), URL_SAFE)); - } - BitMatrix result; - try { - result = new MultiFormatWriter().encode(link.toString(), - BarcodeFormat.QR_CODE, QR_CODE_SIZE, QR_CODE_SIZE, null); - } catch (WriterException e) { - LOG.error(e.getMessage(), e); - return null; - } - int w = result.getWidth(); - int h = result.getHeight(); - int[] pixels = new int[w * h]; - for (int y = 0; y < h; y++) { - int offset = y * w; - for (int x = 0; x < w; x++) { - pixels[offset + x] = result.get(x, y) ? BLACK : WHITE; - } - } - Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - bitmap.setPixels(pixels, 0, QR_CODE_SIZE, 0, 0, w, h); - return bitmap; - } - @Override public void onPause() { if (item != null) { diff --git a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java index e7aaa9a..d744b99 100644 --- a/app/src/main/java/ch/dissem/apps/abit/MainActivity.java +++ b/app/src/main/java/ch/dissem/apps/abit/MainActivity.java @@ -16,16 +16,23 @@ package ch.dissem.apps.abit; +import android.app.Dialog; +import android.content.DialogInterface; import android.content.Intent; import android.graphics.Point; +import android.graphics.drawable.ColorDrawable; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; +import android.view.Display; import android.view.View; import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; import android.widget.CompoundButton; +import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.Toast; @@ -61,6 +68,7 @@ import ch.dissem.apps.abit.repository.AndroidMessageRepository; import ch.dissem.apps.abit.service.BitmessageService; import ch.dissem.apps.abit.service.Singleton; import ch.dissem.apps.abit.synchronization.SyncAdapter; +import ch.dissem.apps.abit.util.Drawables; import ch.dissem.apps.abit.util.Labels; import ch.dissem.apps.abit.util.Preferences; import ch.dissem.bitmessage.BitmessageContext; @@ -230,6 +238,50 @@ public class MainActivity extends AppCompatActivity .withActivity(this) .withHeaderBackground(R.drawable.header) .withProfiles(profiles) + .withOnAccountHeaderProfileImageListener(new AccountHeader.OnAccountHeaderProfileImageListener() { + @Override + public boolean onProfileImageClick(View view, IProfile profile, boolean current) { + if (current) { + // Show QR code in modal dialog + final Dialog dialog = new Dialog(MainActivity.this); + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); + + ImageView imageView = new ImageView(MainActivity.this); + imageView.setImageBitmap(Drawables.qrCode(Singleton.getIdentity(MainActivity.this))); + imageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dialog.dismiss(); + } + }); + dialog.addContentView(imageView, new RelativeLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + Window window = dialog.getWindow(); + if (window != null) { + Display display = window.getWindowManager().getDefaultDisplay(); + Point size = new Point(); + display.getSize(size); + int dim = size.x < size.y ? size.x : size.y; + + WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); + lp.copyFrom(window.getAttributes()); + lp.width = dim; + lp.height = dim; + + window.setAttributes(lp); + } + dialog.show(); + return true; + } + return false; + } + + @Override + public boolean onProfileImageLongClick(View view, IProfile iProfile, boolean b) { + return false; + } + }) .withOnAccountHeaderListener(new AccountHeader.OnAccountHeaderListener() { @Override public boolean onProfileChanged(View view, IProfile profile, boolean current) { diff --git a/app/src/main/java/ch/dissem/apps/abit/util/Drawables.java b/app/src/main/java/ch/dissem/apps/abit/util/Drawables.java index a35281a..d577515 100644 --- a/app/src/main/java/ch/dissem/apps/abit/util/Drawables.java +++ b/app/src/main/java/ch/dissem/apps/abit/util/Drawables.java @@ -19,19 +19,40 @@ package ch.dissem.apps.abit.util; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.util.Base64; import android.view.Menu; import android.view.MenuItem; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; import com.mikepenz.iconics.IconicsDrawable; import com.mikepenz.iconics.typeface.IIcon; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + import ch.dissem.apps.abit.Identicon; import ch.dissem.apps.abit.R; +import ch.dissem.bitmessage.entity.BitmessageAddress; +import ch.dissem.bitmessage.exception.ApplicationException; + +import static android.graphics.Color.BLACK; +import static android.graphics.Color.WHITE; +import static android.util.Base64.URL_SAFE; /** * Some helper methods to work with drawables. */ public class Drawables { + private static final Logger LOG = LoggerFactory.getLogger(Drawables.class); + + private static final int QR_CODE_SIZE = 350; + public static MenuItem addIcon(Context ctx, Menu menu, int menuItem, IIcon icon) { MenuItem item = menu.findItem(menuItem); item.setIcon(new IconicsDrawable(ctx, icon).colorRes(R.color.colorPrimaryDarkText).actionBar()); @@ -49,4 +70,42 @@ public class Drawables { identicon.draw(canvas); return bitmap; } + + public static Bitmap qrCode(BitmessageAddress address) { + StringBuilder link = new StringBuilder("bitmessage:"); + link.append(address.getAddress()); + if (address.getAlias() != null) { + link.append("?label=").append(address.getAlias()); + } + if (address.getPubkey() != null) { + link.append(address.getAlias() == null ? '?' : '&'); + ByteArrayOutputStream pubkey = new ByteArrayOutputStream(); + try { + address.getPubkey().writeUnencrypted(pubkey); + } catch (IOException e) { + throw new ApplicationException(e); + } + link.append("pubkey=").append(Base64.encodeToString(pubkey.toByteArray(), URL_SAFE)); + } + BitMatrix result; + try { + result = new MultiFormatWriter().encode(link.toString(), + BarcodeFormat.QR_CODE, QR_CODE_SIZE, QR_CODE_SIZE, null); + } catch (WriterException e) { + LOG.error(e.getMessage(), e); + return null; + } + int w = result.getWidth(); + int h = result.getHeight(); + int[] pixels = new int[w * h]; + for (int y = 0; y < h; y++) { + int offset = y * w; + for (int x = 0; x < w; x++) { + pixels[offset + x] = result.get(x, y) ? BLACK : WHITE; + } + } + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + bitmap.setPixels(pixels, 0, QR_CODE_SIZE, 0, 0, w, h); + return bitmap; + } }