generate aztec code
This commit is contained in:
parent
4fd4949813
commit
1bb906f660
|
@ -61,7 +61,10 @@
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Android API 20 Platform" jdkType="Android SDK" />
|
<orderEntry type="jdk" jdkName="Android API 20 Platform" jdkType="Android SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" exported="" name="appcompat-v7-20.0.0" level="project" />
|
||||||
<orderEntry type="library" exported="" name="core-3.1.0" level="project" />
|
<orderEntry type="library" exported="" name="core-3.1.0" level="project" />
|
||||||
|
<orderEntry type="library" exported="" name="support-annotations-20.0.0" level="project" />
|
||||||
|
<orderEntry type="library" exported="" name="support-v4-20.0.0" level="project" />
|
||||||
<orderEntry type="library" exported="" name="miglayout-3.7.4" level="project" />
|
<orderEntry type="library" exported="" name="miglayout-3.7.4" level="project" />
|
||||||
<orderEntry type="library" exported="" name="secretshare-1.4.1" level="project" />
|
<orderEntry type="library" exported="" name="secretshare-1.4.1" level="project" />
|
||||||
</component>
|
</component>
|
||||||
|
|
|
@ -5,6 +5,7 @@ apply plugin: 'maven'
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.tiemens:secretshare:1.4.1'
|
compile 'com.tiemens:secretshare:1.4.1'
|
||||||
compile 'com.google.zxing:core:3.1.0'
|
compile 'com.google.zxing:core:3.1.0'
|
||||||
|
compile 'com.android.support:appcompat-v7:20.+'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
|
|
|
@ -1,31 +1,27 @@
|
||||||
package org.surfsite.android.secretshare;
|
package org.surfsite.android.secretshare;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Color;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.print.PrintHelper;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
|
||||||
import com.google.zxing.EncodeHintType;
|
|
||||||
import com.google.zxing.WriterException;
|
|
||||||
import com.google.zxing.common.BitMatrix;
|
|
||||||
import com.google.zxing.qrcode.QRCodeWriter;
|
|
||||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
|
||||||
import com.tiemens.secretshare.engine.SecretShare;
|
import com.tiemens.secretshare.engine.SecretShare;
|
||||||
import com.tiemens.secretshare.engine.SecretShare.ShareInfo;
|
import com.tiemens.secretshare.engine.SecretShare.ShareInfo;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,7 +37,6 @@ public class GenerateFragment extends Fragment implements FragmentSupport {
|
||||||
private static final String ARG_N = "n";
|
private static final String ARG_N = "n";
|
||||||
private static final String ARG_K = "k";
|
private static final String ARG_K = "k";
|
||||||
private static final String ARG_CLEARTEXT = "cleartext";
|
private static final String ARG_CLEARTEXT = "cleartext";
|
||||||
private final static QRCodeWriter sQRCodeWriter = new QRCodeWriter();
|
|
||||||
private int n;
|
private int n;
|
||||||
private int k;
|
private int k;
|
||||||
private String cleartext;
|
private String cleartext;
|
||||||
|
@ -128,12 +123,11 @@ public class GenerateFragment extends Fragment implements FragmentSupport {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
if (generateSharesTask != null)
|
if (generateSharesTask != null)
|
||||||
generateSharesTask.cancel(true);
|
generateSharesTask.cancel(true);
|
||||||
|
else {
|
||||||
TextView tv = (TextView) getActivity().findViewById(R.id.generate_status);
|
generateSharesTask = new GenerateSharesTask(n, k, cleartext);
|
||||||
|
|
||||||
generateSharesTask = new GenerateSharesTask(tv, n, k, cleartext);
|
|
||||||
generateSharesTask.execute();
|
generateSharesTask.execute();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
|
@ -168,6 +162,7 @@ public class GenerateFragment extends Fragment implements FragmentSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class GenerateSharesTask extends AsyncTask<Void, Void, Void> {
|
private class GenerateSharesTask extends AsyncTask<Void, Void, Void> {
|
||||||
|
private final Activity activity;
|
||||||
private TextView tv;
|
private TextView tv;
|
||||||
private List<SecretShare.ShareInfo> pieces;
|
private List<SecretShare.ShareInfo> pieces;
|
||||||
private int n;
|
private int n;
|
||||||
|
@ -175,9 +170,12 @@ public class GenerateFragment extends Fragment implements FragmentSupport {
|
||||||
private String cleartext;
|
private String cleartext;
|
||||||
private SecretShare.PublicInfo publicInfo;
|
private SecretShare.PublicInfo publicInfo;
|
||||||
private boolean finished = false;
|
private boolean finished = false;
|
||||||
|
private Bitmap qrCodeBitmap;
|
||||||
|
private ImageView qrCodeView;
|
||||||
|
|
||||||
public GenerateSharesTask(TextView tv, int n, int k, String cleartext) {
|
public GenerateSharesTask(int n, int k, String cleartext) {
|
||||||
this.tv = tv;
|
activity = getActivity();
|
||||||
|
this.tv = (TextView) activity.findViewById(R.id.generate_status);
|
||||||
this.n = n;
|
this.n = n;
|
||||||
this.k = k;
|
this.k = k;
|
||||||
this.cleartext = cleartext;
|
this.cleartext = cleartext;
|
||||||
|
@ -185,50 +183,6 @@ public class GenerateFragment extends Fragment implements FragmentSupport {
|
||||||
+ " chars. Please Wait. This can take a long time.");
|
+ " chars. Please Wait. This can take a long time.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bitmap createBitmap(byte[] content, final int size) {
|
|
||||||
final Hashtable<EncodeHintType, Object> hints =
|
|
||||||
new Hashtable<EncodeHintType, Object>();
|
|
||||||
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
|
|
||||||
hints.put(EncodeHintType.CHARACTER_SET, "ISO-8859-1");
|
|
||||||
BitMatrix result;
|
|
||||||
|
|
||||||
String data;
|
|
||||||
try {
|
|
||||||
data = new String(content, "ISO-8859-1");
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
data = new String(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
result = sQRCodeWriter.encode(data,
|
|
||||||
BarcodeFormat.QR_CODE,
|
|
||||||
size,
|
|
||||||
size,
|
|
||||||
hints);
|
|
||||||
} catch (WriterException ex) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int width = result.getWidth();
|
|
||||||
final int height = result.getHeight();
|
|
||||||
final int[] pixels = new int[width * height];
|
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
final int offset = y * width;
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
pixels[offset + x] =
|
|
||||||
result.get(x, y) ? Color.BLACK : Color.TRANSPARENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final Bitmap bitmap =
|
|
||||||
Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
|
||||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
|
||||||
|
|
||||||
return bitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFinished() {
|
public boolean isFinished() {
|
||||||
return finished;
|
return finished;
|
||||||
}
|
}
|
||||||
|
@ -260,7 +214,7 @@ public class GenerateFragment extends Fragment implements FragmentSupport {
|
||||||
byte[] bmodulus = publicInfo.getPrimeModulus().toByteArray();
|
byte[] bmodulus = publicInfo.getPrimeModulus().toByteArray();
|
||||||
byte[] bshare = piece.getShare().toByteArray();
|
byte[] bshare = piece.getShare().toByteArray();
|
||||||
int blen = 4 + 4 + 4 + 4 + 4 + bmodulus.length + bshare.length;
|
int blen = 4 + 4 + 4 + 4 + 4 + bmodulus.length + bshare.length;
|
||||||
ByteBuffer bencoded = ByteBuffer.allocate(blen);
|
final ByteBuffer bencoded = ByteBuffer.allocate(blen);
|
||||||
bencoded.putInt(n).putInt(k).putInt(piece.getX());
|
bencoded.putInt(n).putInt(k).putInt(piece.getX());
|
||||||
bencoded.putInt(bmodulus.length).put(bmodulus);
|
bencoded.putInt(bmodulus.length).put(bmodulus);
|
||||||
bencoded.putInt(bshare.length).put(bshare);
|
bencoded.putInt(bshare.length).put(bshare);
|
||||||
|
@ -281,7 +235,32 @@ public class GenerateFragment extends Fragment implements FragmentSupport {
|
||||||
tv.append("B64Len: " + bencoded64.length() + "\n");
|
tv.append("B64Len: " + bencoded64.length() + "\n");
|
||||||
tv.append(bencoded64 + "\n");
|
tv.append(bencoded64 + "\n");
|
||||||
tv.append(bencoded + "\n\n");
|
tv.append(bencoded + "\n\n");
|
||||||
|
|
||||||
|
final String data = "ssss-android:" + bencoded64;
|
||||||
|
if (i == 0) {
|
||||||
|
View view = activity.getLayoutInflater().inflate(R.layout.address_qr, null);
|
||||||
|
final TextView tv = (TextView) view.findViewById(R.id.secret_text);
|
||||||
|
tv.setText(out[i]);
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
|
builder.setTitle("ssss-1");
|
||||||
|
builder.setView(view);
|
||||||
|
if (PrintHelper.systemSupportsPrint()) {
|
||||||
|
builder.setPositiveButton(R.string.print, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
Renderer.printCode(activity, "sss-1", data);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(android.R.string.cancel, null);
|
||||||
|
} else {
|
||||||
|
builder.setPositiveButton(android.R.string.ok, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.finished = true;
|
this.finished = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
183
app/src/main/java/org/surfsite/android/secretshare/Renderer.java
Normal file
183
app/src/main/java/org/surfsite/android/secretshare/Renderer.java
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
package org.surfsite.android.secretshare;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.support.v4.print.PrintHelper;
|
||||||
|
import android.text.TextPaint;
|
||||||
|
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.EncodeHintType;
|
||||||
|
import com.google.zxing.aztec.AztecWriter;
|
||||||
|
import com.google.zxing.common.BitMatrix;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
public class Renderer {
|
||||||
|
private final static AztecWriter sCodeWriter = new AztecWriter();
|
||||||
|
|
||||||
|
public static Bitmap createBitmap(String data) {
|
||||||
|
final Hashtable<EncodeHintType, Object> hints =
|
||||||
|
new Hashtable<EncodeHintType, Object>();
|
||||||
|
hints.put(EncodeHintType.CHARACTER_SET, "ISO-8859-1");
|
||||||
|
BitMatrix result;
|
||||||
|
|
||||||
|
final int size = (int) Math.sqrt(data.length() * 8) * 10;
|
||||||
|
|
||||||
|
result = sCodeWriter.encode(data,
|
||||||
|
BarcodeFormat.AZTEC,
|
||||||
|
size,
|
||||||
|
size,
|
||||||
|
hints);
|
||||||
|
|
||||||
|
final int width = result.getWidth();
|
||||||
|
final int height = result.getHeight();
|
||||||
|
final int[] pixels = new int[width * height];
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
final int offset = y * width;
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
pixels[offset + x] =
|
||||||
|
result.get(x, y) ? Color.BLACK : Color.TRANSPARENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final Bitmap bitmap =
|
||||||
|
Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
|
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void printCode(final Activity context, final String label, final String contents) {
|
||||||
|
new AsyncTask<Void, Void, Bitmap>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Bitmap doInBackground(Void... params) {
|
||||||
|
TextPaint textPaint = new TextPaint();
|
||||||
|
textPaint.setAntiAlias(true);
|
||||||
|
textPaint.setColor(0xFF000000);
|
||||||
|
final int bitmapMargin = 100;//big margin is to prevent possible clipping
|
||||||
|
final int textHeight = 28;
|
||||||
|
textPaint.setTextSize(textHeight);
|
||||||
|
textPaint.setTextAlign(Paint.Align.CENTER);
|
||||||
|
final int codePadding = (int) (textPaint.descent() * 2);
|
||||||
|
int textWidth = getTextWidth(label, textPaint);
|
||||||
|
|
||||||
|
Bitmap codeBitmap = createBitmap(contents);
|
||||||
|
final int width = Math.max(textWidth, codeBitmap.getWidth());
|
||||||
|
Bitmap bmp = Bitmap.createBitmap(width + bitmapMargin * 2,
|
||||||
|
textHeight + codeBitmap.getHeight() + codePadding * 2 + bitmapMargin * 2,
|
||||||
|
Bitmap.Config.RGB_565);
|
||||||
|
Canvas canvas = new Canvas(bmp);
|
||||||
|
Paint paint = new Paint();
|
||||||
|
paint.setStyle(Paint.Style.FILL);
|
||||||
|
paint.setARGB(0xFF, 0xFF, 0xFF, 0xFF);
|
||||||
|
paint.setAntiAlias(false);
|
||||||
|
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint);
|
||||||
|
|
||||||
|
int centerXForAddress = bitmapMargin + width / 2;
|
||||||
|
int y = bitmapMargin + codePadding;
|
||||||
|
Paint codePaint = new Paint();
|
||||||
|
codePaint.setAntiAlias(false);
|
||||||
|
codePaint.setDither(false);
|
||||||
|
canvas.drawBitmap(codeBitmap, centerXForAddress - codeBitmap.getWidth() / 2, y, codePaint);
|
||||||
|
y += codePadding - textPaint.ascent();
|
||||||
|
canvas.drawText(label, centerXForAddress, y + codeBitmap.getHeight(), textPaint);
|
||||||
|
return bmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(final Bitmap bitmap) {
|
||||||
|
if (bitmap != null) {
|
||||||
|
//DEBUG
|
||||||
|
// android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(context);
|
||||||
|
// android.widget.ImageView view = new android.widget.ImageView(context);
|
||||||
|
// view.setImageBitmap(bitmap);
|
||||||
|
// builder.setView(view);
|
||||||
|
// builder.setPositiveButton(android.R.string.ok, null);
|
||||||
|
// builder.show();
|
||||||
|
|
||||||
|
PrintHelper printHelper = new PrintHelper(context);
|
||||||
|
printHelper.setScaleMode(PrintHelper.SCALE_MODE_FIT);
|
||||||
|
printHelper.printBitmap(label, bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static int getTextWidth(String s, Paint paint) {
|
||||||
|
Rect bounds = new Rect();
|
||||||
|
paint.getTextBounds(s, 0, s.length(), bounds);
|
||||||
|
return bounds.right - bounds.left;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ArrayList<String> wrap(String txt, int maxWidth, boolean mustFit, Paint paint) {
|
||||||
|
int pos = 0;
|
||||||
|
int start = pos;
|
||||||
|
ArrayList<String> lines = new ArrayList<String>();
|
||||||
|
while (true) {
|
||||||
|
int i = pos;
|
||||||
|
if (txt == null) txt = "";
|
||||||
|
int len = txt.length();
|
||||||
|
if (pos >= len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int startForLineBreak = pos;
|
||||||
|
while (true) {
|
||||||
|
while (i < len && txt.charAt(i) != ' ' && txt.charAt(i) != '\n') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
int w = getTextWidth(txt.substring(startForLineBreak, i), paint);
|
||||||
|
if (pos == startForLineBreak) {
|
||||||
|
if (w > maxWidth) {
|
||||||
|
if (mustFit) {
|
||||||
|
do {
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
while (getTextWidth(txt.substring(startForLineBreak, i), paint) > maxWidth);
|
||||||
|
}
|
||||||
|
pos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (w <= maxWidth) {
|
||||||
|
pos = i;
|
||||||
|
if (pos >= len)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (w > maxWidth || i >= len || txt.charAt(i) == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
int nextBreak = pos >= len ? len : ++pos;
|
||||||
|
|
||||||
|
if (nextBreak >= txt.length()) {
|
||||||
|
lines.add(txt.substring(start, txt.length()));
|
||||||
|
} else {
|
||||||
|
char c = txt.charAt(nextBreak - 1);
|
||||||
|
if ((c == ' ') || (c == '\n')) {
|
||||||
|
if (nextBreak - 2 < start) {
|
||||||
|
lines.add("");
|
||||||
|
} else {
|
||||||
|
lines.add(txt.substring(start, nextBreak - 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lines.add(txt.substring(start, nextBreak));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start = pos;
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
app/src/main/res/layout/address_qr.xml
Normal file
14
app/src/main/res/layout/address_qr.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/secret_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:textSize="16sp"/>
|
||||||
|
|
||||||
|
</ScrollView>
|
|
@ -6,6 +6,13 @@
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
tools:context="org.surfsite.android.secretshare.GenerateFragment">
|
tools:context="org.surfsite.android.secretshare.GenerateFragment">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -19,5 +26,5 @@
|
||||||
android:text="@string/hello_blank_fragment"
|
android:text="@string/hello_blank_fragment"
|
||||||
/>
|
/>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
|
@ -8,5 +8,6 @@
|
||||||
<string name="string_generate_secrets">Generate Secrets</string>
|
<string name="string_generate_secrets">Generate Secrets</string>
|
||||||
<string name="string_encrypted_secrets">Encrypted secrets</string>
|
<string name="string_encrypted_secrets">Encrypted secrets</string>
|
||||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||||
|
<string name="print">Print</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue