From d71ee3f4d5af5b3f2ae3878aa246b1350b31ccb7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 5 Jun 2018 13:26:50 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../presentation/activity/MainActivity.java | 230 ++++-------------- .../dialog/NoExtendedLengthSupportDialog.java | 19 +- .../presentation/dialog/RootFoundDialog.java | 23 ++ .../presentation/fragment/MainFragment.java | 50 ++-- .../main/java/com/tangem/util/CommonUtil.java | 52 ++++ .../main/java/com/tangem/util/Compress.java | 51 ++++ app/src/main/res/layout/activity_main.xml | 2 +- app/src/main/res/values/strings.xml | 20 +- 8 files changed, 213 insertions(+), 234 deletions(-) create mode 100644 app/src/main/java/com/tangem/presentation/dialog/RootFoundDialog.java create mode 100644 app/src/main/java/com/tangem/util/CommonUtil.java create mode 100644 app/src/main/java/com/tangem/util/Compress.java diff --git a/app/src/main/java/com/tangem/presentation/activity/MainActivity.java b/app/src/main/java/com/tangem/presentation/activity/MainActivity.java index 6f55632e70..2b68bf3e56 100644 --- a/app/src/main/java/com/tangem/presentation/activity/MainActivity.java +++ b/app/src/main/java/com/tangem/presentation/activity/MainActivity.java @@ -1,14 +1,8 @@ package com.tangem.presentation.activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; -import android.content.pm.ResolveInfo; -import android.net.Uri; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.os.Bundle; @@ -34,110 +28,63 @@ import com.tangem.domain.wallet.DeviceNFCAntennaLocation; import com.tangem.domain.wallet.LastSignStorage; import com.tangem.domain.wallet.Logger; import com.tangem.domain.wallet.PINStorage; +import com.tangem.presentation.dialog.RootFoundDialog; import com.tangem.presentation.fragment.MainFragment; +import com.tangem.util.CommonUtil; import com.tangem.util.PhoneUtility; import com.tangem.wallet.BuildConfig; import com.tangem.wallet.R; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - public class MainActivity extends AppCompatActivity implements PopupMenu.OnMenuItemClickListener { + public static final String TAG = MainActivity.class.getSimpleName(); - public static final int DIALOG_ENABLE_INTERNET = 1; private static final int REQUEST_CODE_SEND_EMAIL = 2; - private String logTag = "MainActivity"; private File zipFile = null; private NfcAdapter.ReaderCallback onNFCReaderCallback; private OnCardsClean onCardsClean; private FloatingActionButton fab; + private LinearLayout llTapPrompt; public interface OnCardsClean { void doClean(); } -// public interface OnCreateNFCDialog { -// Dialog CreateNFCDialog(int id, AlertDialogWrapper.Builder builder, LayoutInflater li); -// } - - - // OnCreateNFCDialog onCreateNFCDialog; - - public void setOnCardsClean(OnCardsClean onCardsClean) { this.onCardsClean = onCardsClean; } -// public void setOnCreateNFCDialog(OnCreateNFCDialog onCreateNFCDialog) { -// this.onCreateNFCDialog = onCreateNFCDialog; -// } - public void setNfcAdapterReaderCallback(NfcAdapter.ReaderCallback callback) { this.onNFCReaderCallback = callback; } - public void showCleanButton() { - findViewById(R.id.tvTapPrompt).setVisibility(View.INVISIBLE); - } - - public void hideCleanButton() { - findViewById(R.id.tvTapPrompt).setVisibility(View.VISIBLE); - } - - public static class RootFoundDialog extends DialogFragment { - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - - return new AlertDialog.Builder(getActivity()) - .setIcon(R.drawable.tangem_logo_small_new) - .setTitle("Your Android device is rooted. Security at risk!") - .setCancelable(false) - .setPositiveButton("Got it", - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - } - } - ) - .create(); - } - - } - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tvNFCHint = findViewById(R.id.tvNFCHint); + llTapPrompt = findViewById(R.id.llTapPrompt); + LinearLayout hand = findViewById(R.id.llHand); + LinearLayout nfc = findViewById(R.id.llNFC); + RippleBackground rippleBackground = findViewById(R.id.imNFC); fab = findViewById(R.id.fab); - // check if device root - RootBeer rootBeer = new RootBeer(this); - if (rootBeer.isRootedWithoutBusyBoxCheck()) { - new RootFoundDialog().show(getFragmentManager(), "RootFoundDialog"); - } - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); commonInit(getApplicationContext()); - if (tvNFCHint != null) { -// tvNFCHint.setText("Scan a banknote with your\n" + PhoneUtility.GetPhoneName() + "\nas shown above"); - tvNFCHint.setText("Scan a banknote with your\n smartphone as shown above"); - } + rippleBackground.startRippleAnimation(); + +// tvNFCHint.setText("Scan a banknote with your\n" + PhoneUtility.GetPhoneName() + "\nas shown above"); + tvNFCHint.setText(R.string.scan_banknote); DeviceNFCAntennaLocation antenna = new DeviceNFCAntennaLocation(); antenna.getAntennaLocation(); - final LinearLayout hand = findViewById(R.id.llHand); - final LinearLayout nfc = findViewById(R.id.llNFC); + + // animate final RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) hand.getLayoutParams(); final RelativeLayout.LayoutParams lp2 = (RelativeLayout.LayoutParams) nfc.getLayoutParams(); final float dp = getResources().getDisplayMetrics().density; @@ -153,24 +100,21 @@ public class MainActivity extends AppCompatActivity implements PopupMenu.OnMenuI hand.setLayoutParams(lp); } }; - a.setDuration(2000); // in ms + a.setDuration(2000); a.setInterpolator(new DecelerateInterpolator()); hand.startAnimation(a); // set listeners fab.setOnClickListener(this::showMenu); + // add fragment MainFragment mainFragment = (MainFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentMain); - if (mainFragment.getCardListAdapter().getItemCount() > 0) { + if (mainFragment.getCardListAdapter().getItemCount() > 0) showCleanButton(); - } else { + else hideCleanButton(); - } - - final RippleBackground rippleBackground = findViewById(R.id.imNFC); - rippleBackground.startRippleAnimation(); - + // NFC Intent intent = getIntent(); if (intent != null && (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))) { Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); @@ -178,12 +122,11 @@ public class MainActivity extends AppCompatActivity implements PopupMenu.OnMenuI onNFCReaderCallback.onTagDiscovered(tag); } } - } - @Override - protected void onDestroy() { -// Logger.StopSaveToFile(getApplicationContext()); - super.onDestroy(); + // check if device root + RootBeer rootBeer = new RootBeer(this); + if (rootBeer.isRootedWithoutBusyBoxCheck()) + new RootFoundDialog().show(getFragmentManager(), RootFoundDialog.TAG); } @Override @@ -208,9 +151,13 @@ public class MainActivity extends AppCompatActivity implements PopupMenu.OnMenuI return super.onKeyDown(keycode, e); } + @Override + public boolean onMenuItemClick(MenuItem item) { + return onOptionsItemSelected(item); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); if (BuildConfig.DEBUG) { for (int i = 0; i < menu.size(); i++) menu.getItem(i).setVisible(true); @@ -218,78 +165,21 @@ public class MainActivity extends AppCompatActivity implements PopupMenu.OnMenuI return true; } - public class Compress { - private static final int BUFFER = 2048; - - private String[] _files; - private String _zipFile; - - Compress(String[] files, String zipFile) { - _files = files; - _zipFile = zipFile; - } - - void zip() { - try { - BufferedInputStream origin = null; - FileOutputStream dest = new FileOutputStream(_zipFile); - - ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); - - byte data[] = new byte[BUFFER]; - - for (String _file : _files) { - Log.v("Compress", "Adding: " + _file); - FileInputStream fi = new FileInputStream(_file); - origin = new BufferedInputStream(fi, BUFFER); - ZipEntry entry = new ZipEntry(_file.substring(_file.lastIndexOf("/") + 1)); - out.putNextEntry(entry); - int count; - while ((count = origin.read(data, 0, BUFFER)) != -1) { - out.write(data, 0, count); - } - origin.close(); - } - - out.close(); - } catch (Exception e) { - e.printStackTrace(); - } - - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == REQUEST_CODE_SEND_EMAIL) { - if (zipFile != null) { - zipFile.delete(); - zipFile = null; - } - } - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - public boolean onMenuItemClick(MenuItem item) { - return onOptionsItemSelected(item); - } - @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); - //noinspection SimplifiableIfStatement + // noinspection SimplifiableIfStatement switch (id) { case R.id.sendLogs: File f = null; try { f = Logger.collectLogs(this); if (f != null) { - Log.e(logTag, String.format("Collect %d log bytes", f.length())); - sendEmail("Logs", PhoneUtility.getDeviceInfo(), new File[]{f}); + Log.e(TAG, String.format("Collect %d log bytes", f.length())); + CommonUtil.sendEmail(this, zipFile, TAG, "Logs", PhoneUtility.getDeviceInfo(), new File[]{f}); } else { - Log.e(logTag, "Can't create temporaly log file"); + Log.e(TAG, "Can't create temporaly log file"); } } catch (Exception e) { e.printStackTrace(); @@ -320,6 +210,17 @@ public class MainActivity extends AppCompatActivity implements PopupMenu.OnMenuI return super.onOptionsItemSelected(item); } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == REQUEST_CODE_SEND_EMAIL) { + if (zipFile != null) { + zipFile.delete(); + zipFile = null; + } + } + super.onActivityResult(requestCode, resultCode, data); + } + public static void commonInit(Context context) { if (PINStorage.needInit()) { PINStorage.Init(context); @@ -329,6 +230,14 @@ public class MainActivity extends AppCompatActivity implements PopupMenu.OnMenuI } } + public void showCleanButton() { + llTapPrompt.setVisibility(View.INVISIBLE); + } + + public void hideCleanButton() { + llTapPrompt.setVisibility(View.VISIBLE); + } + private void showLogoActivity() { Intent intent = new Intent(getBaseContext(), LogoActivity.class); intent.putExtra(LogoActivity.TAG, true); @@ -363,41 +272,4 @@ public class MainActivity extends AppCompatActivity implements PopupMenu.OnMenuI popup.show(); } - private void sendEmail(String subject, String text, File[] fileLocations) { - if (zipFile != null) return; - try { - Intent intent = new Intent(Intent.ACTION_SEND) - //.setData(new Uri.Builder().scheme("mailto").build()) - .setType("text/plain") - .putExtra(Intent.EXTRA_EMAIL, new String[]{"android@tangem.com"}) - .putExtra(Intent.EXTRA_SUBJECT, subject) - .putExtra(Intent.EXTRA_TEXT, text); - - if (fileLocations != null && fileLocations.length > 0) { - String[] fileNames = new String[fileLocations.length]; - for (int i = 0; i < fileLocations.length; i++) - fileNames[i] = fileLocations[i].getAbsolutePath(); - zipFile = File.createTempFile("tangemLogs", ".zip", fileLocations[0].getParentFile()); - Compress compress = new Compress(fileNames, zipFile.getAbsolutePath()); - compress.zip(); - Log.e(logTag, String.format("Send %d bytes zip with logs", zipFile.length())); - Uri attachment = Uri.parse("content://" + getString(R.string.log_file_provider_authorities) + "/" + zipFile.getName()); - - intent.putExtra(Intent.EXTRA_STREAM, attachment); - zipFile.deleteOnExit(); - } - - List activities = getPackageManager().queryIntentActivities(intent, 0); - boolean isIntentSafe = activities.size() > 0; - - if (isIntentSafe) { - startActivity(intent); - } - - } catch (Exception e) { - e.printStackTrace(); - } - - } - } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/presentation/dialog/NoExtendedLengthSupportDialog.java b/app/src/main/java/com/tangem/presentation/dialog/NoExtendedLengthSupportDialog.java index 62a1552dcc..409333d558 100644 --- a/app/src/main/java/com/tangem/presentation/dialog/NoExtendedLengthSupportDialog.java +++ b/app/src/main/java/com/tangem/presentation/dialog/NoExtendedLengthSupportDialog.java @@ -9,23 +9,17 @@ import android.os.Bundle; import com.tangem.wallet.R; public class NoExtendedLengthSupportDialog extends DialogFragment { + public static final String TAG = NoExtendedLengthSupportDialog.class.getSimpleName(); - public static boolean allreadyShowed=false; + public static boolean allreadyShowed = false; @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()) .setIcon(R.drawable.tangem_logo_small_new) - .setTitle("Warning") - .setMessage("The NFC adapter of the device does not support extended length APDU, it's possible that some functions will not work!") - .setPositiveButton("Got it", - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - NoExtendedLengthSupportDialog.allreadyShowed=true; - } - } - ) + .setTitle(R.string.warning) + .setMessage(R.string.the_nfc_adapter_length_apdu) + .setPositiveButton(R.string.got_it, (dialog, whichButton) -> NoExtendedLengthSupportDialog.allreadyShowed = true) .create(); } @@ -33,4 +27,5 @@ public class NoExtendedLengthSupportDialog extends DialogFragment { public void onCancel(DialogInterface dialog) { super.onCancel(dialog); } -} + +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/presentation/dialog/RootFoundDialog.java b/app/src/main/java/com/tangem/presentation/dialog/RootFoundDialog.java new file mode 100644 index 0000000000..a100c2762f --- /dev/null +++ b/app/src/main/java/com/tangem/presentation/dialog/RootFoundDialog.java @@ -0,0 +1,23 @@ +package com.tangem.presentation.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.os.Bundle; + +import com.tangem.wallet.R; + +public class RootFoundDialog extends DialogFragment { + public static final String TAG = RootFoundDialog.class.getSimpleName(); + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()) + .setIcon(R.drawable.tangem_logo_small_new) + .setTitle(R.string.device_is_rooted) + .setCancelable(false) + .setPositiveButton(R.string.got_it, null) + .create(); + } + +} diff --git a/app/src/main/java/com/tangem/presentation/fragment/MainFragment.java b/app/src/main/java/com/tangem/presentation/fragment/MainFragment.java index 209bc14ef1..2273293b9b 100644 --- a/app/src/main/java/com/tangem/presentation/fragment/MainFragment.java +++ b/app/src/main/java/com/tangem/presentation/fragment/MainFragment.java @@ -63,6 +63,7 @@ import java.util.Objects; // NfcManager getNfcManager(Activity activity, NfcAdapter.ReaderCallback readerCallback); // //} + /** * A placeholder fragment containing a simple view. */ @@ -442,19 +443,13 @@ public class MainFragment extends Fragment implements NfcAdapter.ReaderCallback, if (card.getStatus() == TangemCard.Status.Empty) { intent = new Intent(getActivity(), EmptyWalletActivity.class); // Toast.makeText(getContext(), "1", Toast.LENGTH_SHORT).show(); - } - - else if (card.getStatus() == TangemCard.Status.Loaded) { + } else if (card.getStatus() == TangemCard.Status.Loaded) { intent = new Intent(getActivity(), LoadedWalletActivity.class); // Toast.makeText(getContext(), "2", Toast.LENGTH_SHORT).show(); - } - - else if (card.getStatus() == TangemCard.Status.NotPersonalized || card.getStatus() == TangemCard.Status.Purged) { + } else if (card.getStatus() == TangemCard.Status.NotPersonalized || card.getStatus() == TangemCard.Status.Purged) { // Toast.makeText(getContext(), "3", Toast.LENGTH_SHORT).show(); return; - } - - else { + } else { intent = new Intent(getActivity(), LoadedWalletActivity.class); // Toast.makeText(getContext(), "4", Toast.LENGTH_SHORT).show(); } @@ -676,20 +671,16 @@ public class MainFragment extends Fragment implements NfcAdapter.ReaderCallback, if (cardProtocol != null) { if (cardProtocol.getError() == null) { - progressBar.post(new Runnable() { - @Override - public void run() { - progressBar.setProgress(100); - progressBar.setProgressTintList(ColorStateList.valueOf(Color.GREEN)); - addCard(cardProtocol.getCard()); - } + progressBar.post(() -> { + progressBar.setProgress(100); + progressBar.setProgressTintList(ColorStateList.valueOf(Color.GREEN)); + addCard(cardProtocol.getCard()); }); } else { // remove last UIDs because of error and no card read - progressBar.post(new Runnable() { - @Override - public void run() { - Toast.makeText(getContext(), "Try to scan again", Toast.LENGTH_LONG).show(); + progressBar.post(() -> { + if (getContext() != null) { + Toast.makeText(getContext(), R.string.try_to_scan_again, Toast.LENGTH_LONG).show(); unsuccessReadCount++; progressBar.setProgress(100); progressBar.setProgressTintList(ColorStateList.valueOf(Color.RED)); @@ -698,7 +689,7 @@ public class MainFragment extends Fragment implements NfcAdapter.ReaderCallback, doEnterPIN(); } else if (cardProtocol.getError() instanceof CardProtocol.TangemException_ExtendedLengthNotSupported) { if (!NoExtendedLengthSupportDialog.allreadyShowed) { - new NoExtendedLengthSupportDialog().show(getActivity().getFragmentManager(), "NoExtendedLengthSupportDialog"); + new NoExtendedLengthSupportDialog().show(Objects.requireNonNull(getActivity()).getFragmentManager(), NoExtendedLengthSupportDialog.TAG); } } else { lastTag = null; @@ -708,16 +699,13 @@ public class MainFragment extends Fragment implements NfcAdapter.ReaderCallback, } } - progressBar.postDelayed(new Runnable() { - @Override - public void run() { - try { - progressBar.setProgress(0); - progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); - progressBar.setVisibility(View.INVISIBLE); - } catch (Exception e) { - e.printStackTrace(); - } + progressBar.postDelayed(() -> { + try { + progressBar.setProgress(0); + progressBar.setProgressTintList(ColorStateList.valueOf(Color.DKGRAY)); + progressBar.setVisibility(View.INVISIBLE); + } catch (Exception e) { + e.printStackTrace(); } }, 500); } diff --git a/app/src/main/java/com/tangem/util/CommonUtil.java b/app/src/main/java/com/tangem/util/CommonUtil.java new file mode 100644 index 0000000000..613fefd364 --- /dev/null +++ b/app/src/main/java/com/tangem/util/CommonUtil.java @@ -0,0 +1,52 @@ +package com.tangem.util; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.util.Log; + +import com.tangem.wallet.R; + +import java.io.File; +import java.util.List; + +public class CommonUtil { + + public static void sendEmail(Context context, File zipFile, String logTag, String subject, String text, File[] fileLocations) { + if (zipFile != null) return; + try { + Intent intent = new Intent(Intent.ACTION_SEND) + //.setData(new Uri.Builder().scheme("mailto").build()) + .setType("text/plain") + .putExtra(Intent.EXTRA_EMAIL, new String[]{"android@tangem.com"}) + .putExtra(Intent.EXTRA_SUBJECT, subject) + .putExtra(Intent.EXTRA_TEXT, text); + + if (fileLocations != null && fileLocations.length > 0) { + String[] fileNames = new String[fileLocations.length]; + for (int i = 0; i < fileLocations.length; i++) + fileNames[i] = fileLocations[i].getAbsolutePath(); + zipFile = File.createTempFile("tangemLogs", ".zip", fileLocations[0].getParentFile()); + Compress compress = new Compress(fileNames, zipFile.getAbsolutePath()); + compress.zip(); + Log.e(logTag, String.format("Send %d bytes zip with logs", zipFile.length())); + Uri attachment = Uri.parse("content://" + context.getString(R.string.log_file_provider_authorities) + "/" + zipFile.getName()); + + intent.putExtra(Intent.EXTRA_STREAM, attachment); + zipFile.deleteOnExit(); + } + + List activities = context.getPackageManager().queryIntentActivities(intent, 0); + boolean isIntentSafe = activities.size() > 0; + + if (isIntentSafe) { + context.startActivity(intent); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/app/src/main/java/com/tangem/util/Compress.java b/app/src/main/java/com/tangem/util/Compress.java new file mode 100644 index 0000000000..20deeefd86 --- /dev/null +++ b/app/src/main/java/com/tangem/util/Compress.java @@ -0,0 +1,51 @@ +package com.tangem.util; + +import android.util.Log; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class Compress { + private static final int BUFFER = 2048; + + private String[] _files; + private String _zipFile; + + public Compress(String[] files, String zipFile) { + _files = files; + _zipFile = zipFile; + } + + public void zip() { + try { + BufferedInputStream origin = null; + FileOutputStream dest = new FileOutputStream(_zipFile); + + ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); + + byte data[] = new byte[BUFFER]; + + for (String _file : _files) { + Log.v("Compress", "Adding: " + _file); + FileInputStream fi = new FileInputStream(_file); + origin = new BufferedInputStream(fi, BUFFER); + ZipEntry entry = new ZipEntry(_file.substring(_file.lastIndexOf("/") + 1)); + out.putNextEntry(entry); + int count; + while ((count = origin.read(data, 0, BUFFER)) != -1) { + out.write(data, 0, count); + } + origin.close(); + } + + out.close(); + } catch (Exception e) { + e.printStackTrace(); + } + + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 95c7fd348d..33216fe278 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -8,7 +8,7 @@ tools:context="com.tangem.presentation.activity.MainActivity"> LoadedWalletActivity Settings + + Your Android device is rooted. Security at risk! + Got it + Warning + The NFC adapter of the device does not support extended length APDU, it\'s possible that some functions will not work! + Clean up Manage user PIN1… @@ -59,6 +65,8 @@ Tap Tangem card with your smartphone + Scan a banknote with your \n smartphone as shown above + Try to scan again Send payment @@ -79,23 +87,13 @@ Please wait while the payment is sent… - - - - - - - - General Enable social recommendations - Recommendations for people to contact - based on your message history - + Recommendations for people to contact based on your message history Display name John Smith