diff --git a/app/src/main/java/com/nynja/mobile/communicator/data/DataManager.java b/app/src/main/java/com/nynja/mobile/communicator/data/DataManager.java index 7c33f4df828f5c05892a65efb3fb3f10629176d8..45c7de320b2897282e88917ee168d93584391173 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/data/DataManager.java +++ b/app/src/main/java/com/nynja/mobile/communicator/data/DataManager.java @@ -10,6 +10,7 @@ import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import com.google.firebase.iid.FirebaseInstanceId; +import com.google.zxing.WriterException; import com.nynja.mobile.communicator.data.db.DbHelper; import com.nynja.mobile.communicator.data.db.PreferenceHelper; import com.nynja.mobile.communicator.data.models.LocalContact; @@ -53,6 +54,7 @@ import com.nynja.mobile.communicator.utils.ContactsUtil; import com.nynja.mobile.communicator.utils.ImageUtils; import com.nynja.mobile.communicator.utils.NetworkUtil; import com.nynja.mobile.communicator.utils.StringUtils; +import com.nynja.mobile.communicator.utils.ZxingEncoder; import java.io.File; import java.util.ArrayList; @@ -100,10 +102,11 @@ public class DataManager { private Room mActiveRoom = null; - @Inject public DataManager(@ApplicationContext Context context, RxBus bus, - PreferenceHelper preferenceHelper, - IFileUploadModule fileUploadModule, - DbHelper dbHelper) { + @Inject + public DataManager(@ApplicationContext Context context, RxBus bus, + PreferenceHelper preferenceHelper, + IFileUploadModule fileUploadModule, + DbHelper dbHelper) { mContext = context; mBus = bus; mPreferenceHelper = preferenceHelper; @@ -139,7 +142,8 @@ public class DataManager { return telesignModule.getInputSubject(); } - @WorkerThread private void subscribeToBus() { + @WorkerThread + private void subscribeToBus() { getInputSubject() .subscribeOn(Schedulers.io()) .subscribe(this::handleRequest); @@ -181,7 +185,8 @@ public class DataManager { Timber.d(".l. END DECODE TIME:%d", System.currentTimeMillis() - time); } - @WorkerThread private void handleRequest(Data data) { + @WorkerThread + private void handleRequest(Data data) { if (data instanceof ServerData) { ServerData serverData = (ServerData) data; Response response = new Response(serverData.getData().getPayload()); @@ -230,7 +235,10 @@ public class DataManager { } else if (serverObj instanceof Profile) {//============================================Profile Profile profile = (Profile) serverObj; if (profile.getVox() != null) mVoxClientManager.loginVox(profile.getVox()); - if (!BaseMQQT.Statuses.REMOVE.equals(profile.status)) saveProfile(profile); + if (!BaseMQQT.Statuses.REMOVE.equals(profile.status)) { + saveProfile(profile); + saveMyQrCode(); + } } else if (serverObj instanceof Message) {//============================================Message final Message message = (Message) serverObj; if (getProfile() == null) return; @@ -294,6 +302,19 @@ public class DataManager { mDbHelper.saveProfile(profile); } + public void saveMyQrCode() { + try { + if (ImageUtils.getQrCodeBitmap(mContext) == null || + ImageUtils.compareBitmaps(ImageUtils.getQrCodeBitmap(mContext), + ZxingEncoder.getInstance().generate_QR_CODE(getProfile().phone))) { + Bitmap bitmap = ZxingEncoder.getInstance().generate_QR_CODE(getProfile().phone); + ImageUtils.saveBitmapQrCodeToFile(bitmap, mContext); + } + } catch (WriterException e) { + Timber.e(e); + } + } + public Profile getProfile() { return mProfile == null ? mProfile = mDbHelper.getProfile() : mProfile; } @@ -753,33 +774,39 @@ public class DataManager { Bitmap videoThumbnail = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.MINI_KIND); File thumb = ImageUtils.saveBitmapToFile(videoThumbnail, file, mContext); uploadFile(file, new UploadProgressInterface() { - @Override public void onComplete(String url) { + @Override + public void onComplete(String url) { Desc descVideo = new Desc(); descVideo.mime = BaseMQQT.MimeTypes.Video; descVideo.payload = url; uploadFile(thumb, new UploadProgressInterface() { - @Override public void onComplete(String url) { + @Override + public void onComplete(String url) { Desc descThumb = new Desc(); descThumb.mime = BaseMQQT.MimeTypes.Thumb; descThumb.payload = url; sendMessageInChat(room, descThumb, descVideo); } - @Override public void onDataLoaded(int percent) { + @Override + public void onDataLoaded(int percent) { } - @Override public void onError(Exception e) { + @Override + public void onError(Exception e) { } }); } - @Override public void onDataLoaded(int percent) { + @Override + public void onDataLoaded(int percent) { } - @Override public void onError(Exception e) { + @Override + public void onError(Exception e) { } }); @@ -799,7 +826,8 @@ public class DataManager { mAudioModule.startRecord(mContext, listener); } - @NonNull public String stopRecord() { + @NonNull + public String stopRecord() { return mAudioModule.stopRecord(); } diff --git a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/QrCodePresenter.java b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/QrCodePresenter.java index 87c2c8231416e7f9cf88b0c2db1ecae2e979a836..1576f41430433bc2c9d96bfbc635f163d90e8d89 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/QrCodePresenter.java +++ b/app/src/main/java/com/nynja/mobile/communicator/mvp/presenters/QrCodePresenter.java @@ -1,5 +1,7 @@ package com.nynja.mobile.communicator.mvp.presenters; +import android.content.Context; + import com.arellomobile.mvp.InjectViewState; import com.nynja.mobile.communicator.data.FragmentTransferObject; import com.nynja.mobile.communicator.data.models.mqtt.Contact; @@ -21,11 +23,13 @@ import java.util.ArrayList; public class QrCodePresenter extends BasePresenter { - @Override protected Class[] getFilter() { + @Override + protected Class[] getFilter() { return new Class[]{Io.class}; } - @Override protected void handleResponse(Response response) { + @Override + protected void handleResponse(Response response) { if (response.data instanceof Io) { Io io = (Io) response.data; if (io.code instanceof Ok && ((Ok) io.code).msg instanceof String && @@ -61,10 +65,14 @@ public class QrCodePresenter extends BasePresenter { } public void navigateTo(boolean showQrCode) { - if (showQrCode){ + if (showQrCode) { getViewState().setProfile(mDataManager.getProfile()); - }else { + } else { getViewState().navigateToQRReader(); } } + + public void saveQrCodeImage() { + mDataManager.saveMyQrCode(); + } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/ui/activities/QRCodeActivity.java b/app/src/main/java/com/nynja/mobile/communicator/ui/activities/QRCodeActivity.java index 1ddf7c54b9bd97fcccc5bfdd1277fcc0a88f8398..0c944e2f47e75c66cd1b0d15c03ce90fd89c3d87 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/ui/activities/QRCodeActivity.java +++ b/app/src/main/java/com/nynja/mobile/communicator/ui/activities/QRCodeActivity.java @@ -19,6 +19,7 @@ import com.nynja.mobile.communicator.mvp.presenters.QrCodePresenter; import com.nynja.mobile.communicator.mvp.view.QrCodeView; import com.nynja.mobile.communicator.ui.base.BaseActivity; import com.nynja.mobile.communicator.utils.DialogFactory; +import com.nynja.mobile.communicator.utils.ImageUtils; import com.nynja.mobile.communicator.utils.ZXingScannerView; import com.nynja.mobile.communicator.utils.ZxingEncoder; @@ -51,7 +52,8 @@ public class QRCodeActivity extends BaseActivity implements QrCodeView, return intent; } - @Override protected void onCreate(Bundle savedInstanceState) { + @Override + protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_qr_code_generator); if (getIntent() != null && getIntent().getExtras() != null) { @@ -60,15 +62,16 @@ public class QRCodeActivity extends BaseActivity implements QrCodeView, } } - @Override public void onResume() { + @Override + public void onResume() { super.onResume(); if (mScannerLayout.getVisibility() == View.VISIBLE) { mScannerView.setResultHandler(this); - mScannerView.startCamera(); } } - @Override public void onPause() { + @Override + public void onPause() { super.onPause(); if (mScannerLayout.getVisibility() == View.VISIBLE) mScannerView.stopCamera(); } @@ -86,32 +89,33 @@ public class QRCodeActivity extends BaseActivity implements QrCodeView, @OnClick(R.id.a_qr_code_tv_button_title) public void onScanClick() { - if (mScannerLayout.getVisibility() == View.GONE){ + if (mScannerLayout.getVisibility() == View.GONE) { mRxPermissions.request(Manifest.permission.CAMERA) .filter(granted -> granted) .subscribe(granted -> mPresenter.navigateTo(false)); - }else { + } else { mPresenter.navigateTo(true); } } - @Override public void setProfile(Profile profile) { - try { - String data = profile.phone; - Bitmap qrCodeBitmap = ZxingEncoder.getInstance().generate_QR_CODE(data); - qrCode.setVisibility(View.VISIBLE); - mScannerLayout.setVisibility(View.GONE); - title.setText(R.string.my_qr_code_inline); - btnTitle.setText(R.string.scan_qr_code); - qrCode.setImageBitmap(qrCodeBitmap); - } catch (WriterException e) { - Timber.e(e); + @Override + public void setProfile(Profile profile) { + if (ImageUtils.getQrCodeBitmap(this) == null) { + mPresenter.saveQrCodeImage(); } + Bitmap qrCodeBitmap = ImageUtils.getQrCodeBitmap(this); + qrCode.setVisibility(View.VISIBLE); + mScannerView.stopCamera(); + mScannerLayout.setVisibility(View.GONE); + title.setText(R.string.my_qr_code_inline); + btnTitle.setText(R.string.scan_qr_code); + qrCode.setImageBitmap(qrCodeBitmap); } @Override public void navigateToQRReader() { qrCode.setVisibility(View.GONE); + mScannerView.startCamera(); mScannerLayout.setVisibility(View.VISIBLE); title.setText(R.string.scan_qr_code); btnTitle.setText(R.string.my_qr_code_inline); @@ -119,20 +123,23 @@ public class QRCodeActivity extends BaseActivity implements QrCodeView, mScannerView.startCamera(); } - @Override public void handleResult(Result rawResult) { + @Override + public void handleResult(Result rawResult) { isFlashTurnedOn = false; mScannerView.setFlash(false); mPresenter.getContactByPhoneNumber(rawResult.getText()); } - @Override public void userNotFound() { + @Override + public void userNotFound() { DialogFactory.createDialog(this, getString(R.string.error_user_not_found), (dialog, which) -> { }, null).show(); mScannerView.resumeCameraPreview(this); } - @Override public void finishActivity() { + @Override + public void finishActivity() { finish(); } } diff --git a/app/src/main/java/com/nynja/mobile/communicator/utils/FileUtils.java b/app/src/main/java/com/nynja/mobile/communicator/utils/FileUtils.java index 6592b63e1a54d7146d1681935ba5c10b2ecdcd99..c720efa185bc71313fa5bedd5d82d98e97f7cb49 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/utils/FileUtils.java +++ b/app/src/main/java/com/nynja/mobile/communicator/utils/FileUtils.java @@ -119,6 +119,10 @@ public class FileUtils { return null; } + public static boolean isFileExists(File file) { + return (file.exists() && !file.isDirectory()); + } + /** * Get the value of the data column for this Uri. This is useful for * MediaStore Uris, and other file-based ContentProviders. diff --git a/app/src/main/java/com/nynja/mobile/communicator/utils/ImageUtils.java b/app/src/main/java/com/nynja/mobile/communicator/utils/ImageUtils.java index 2f86a8f1651f98e70748988528c68657105f885f..638dbc92dd224e949473cdc84a2a058eb3879df7 100644 --- a/app/src/main/java/com/nynja/mobile/communicator/utils/ImageUtils.java +++ b/app/src/main/java/com/nynja/mobile/communicator/utils/ImageUtils.java @@ -8,12 +8,14 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.ThumbnailUtils; +import android.os.Build; import android.support.annotation.NonNull; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Date; import timber.log.Timber; @@ -62,6 +64,103 @@ public class ImageUtils { return file; } + public static File saveBitmapQrCodeToFile(Bitmap bitmap, Context context) { + File storageDir = context.getExternalFilesDir("Thumbs"); + File file = new File(storageDir, "qr_code_thumb.png"); + FileOutputStream fos; + try { + fos = new FileOutputStream(file); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); + fos.close(); + } catch (Exception e) { + Timber.e("SAVE_IMAGE %s", e); + } + return file; + } + + public static Bitmap getQrCodeBitmap(Context context) { + File storageDir = context.getExternalFilesDir("Thumbs"); + File file = new File(storageDir, "qr_code_thumb.png"); + if (file.exists()) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + return BitmapFactory.decodeFile(file.getPath(), options); + } + + return null; + } + + public static boolean compareBitmaps(Bitmap bitmap1, Bitmap bitmap2) { + int chunkNumbers = 10; + int rows, cols; + int chunkHeight, chunkWidth; + rows = cols = (int) Math.sqrt(chunkNumbers); + chunkHeight = bitmap1.getHeight() / rows; + chunkWidth = bitmap1.getWidth() / cols; + + int yCoord = 0; + for (int x = 0; x < rows; x++) { + int xCoord = 0; + for (int y = 0; y < cols; y++) { + try { + Bitmap bitmapChunk1 = Bitmap.createBitmap(bitmap1, xCoord, yCoord, chunkWidth, chunkHeight); + Bitmap bitmapChunk2 = Bitmap.createBitmap(bitmap2, xCoord, yCoord, chunkWidth, chunkHeight); + + if (!sameAs(bitmapChunk1, bitmapChunk2)) { + recycleBitmaps(bitmapChunk1, bitmapChunk2); + return false; + } + + recycleBitmaps(bitmapChunk1, bitmapChunk2); + + xCoord += chunkWidth; + } catch (Exception e) { + return false; + } + } + yCoord += chunkHeight; + } + + return true; + } + + private static boolean sameAs(Bitmap bitmap1, Bitmap bitmap2) { + if (bitmap1.getConfig() != bitmap2.getConfig()) + return false; + + if (bitmap1.getWidth() != bitmap2.getWidth()) + return false; + + if (bitmap1.getHeight() != bitmap2.getHeight()) + return false; + + int w = bitmap1.getWidth(); + int h = bitmap1.getHeight(); + + int[] argbA = new int[w * h]; + int[] argbB = new int[w * h]; + + bitmap1.getPixels(argbA, 0, w, 0, 0, w, h); + bitmap2.getPixels(argbB, 0, w, 0, 0, w, h); + + if (bitmap1.getConfig() == Bitmap.Config.ALPHA_8) { + final int length = w * h; + for (int i = 0; i < length; i++) { + if ((argbA[i] & 0xFF000000) != (argbB[i] & 0xFF000000)) { + return false; + } + } + return true; + } + + return Arrays.equals(argbA, argbB); + } + + private static void recycleBitmaps(Bitmap bitmap1, Bitmap bitmap2) { + bitmap1.recycle(); + bitmap2.recycle(); + } + public static File saveThumbnail(File fileName, Context context) { Bitmap thumbnail = ThumbnailUtils.extractThumbnail( BitmapFactory.decodeFile(fileName.getAbsolutePath()),