Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
jamorham committed Aug 2, 2024
2 parents 984d772 + 233cd68 commit 0bd5d9b
Show file tree
Hide file tree
Showing 12 changed files with 383 additions and 35 deletions.
6 changes: 6 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,12 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".utilitymodels.SaveLogs"
android:configChanges="orientation|screenSize"
android:label="@string/title_activity_save_logs"
android:noHistory="true">
</activity>
<activity android:name=".deposit.DepositActivity" />
<activity android:name=".utils.AndroidBarcode" />
<activity
Expand Down
27 changes: 20 additions & 7 deletions app/src/main/java/com/eveningoutpost/dexdrip/EventLogActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.eveningoutpost.dexdrip.utilitymodels.Inevitable;
import com.eveningoutpost.dexdrip.utilitymodels.PersistentStore;
import com.eveningoutpost.dexdrip.utilitymodels.Pref;
import com.eveningoutpost.dexdrip.utilitymodels.SaveLogs;
import com.eveningoutpost.dexdrip.utilitymodels.SendFeedBack;
import com.eveningoutpost.dexdrip.databinding.ActivityEventLogBinding;
import com.eveningoutpost.dexdrip.ui.helpers.BitmapUtil;
Expand All @@ -50,6 +51,7 @@
import me.tatarka.bindingcollectionadapter2.collections.MergeObservableList;

import static com.eveningoutpost.dexdrip.Home.startWatchUpdaterService;
import static com.eveningoutpost.dexdrip.utils.DexCollectionType.getBestCollectorHardwareName;

/*
* New style event log viewer
Expand All @@ -65,6 +67,7 @@ public class EventLogActivity extends BaseAppCompatActivity {
private static final String TAG = EventLogActivity.class.getSimpleName();
private static final String PREF_SEVERITY_SELECTION = "event-log-severity-enabled-";
private static final String PREF_LAST_SEARCH = "event-log-last-search-";
private static int MAX_LOG_PACKAGE_SIZE = 200000;

static {
severitiesList.add(1);
Expand Down Expand Up @@ -291,20 +294,32 @@ private void updateToTopButtonVisibility(boolean force) {
}
}

// prepare current visible logs for upload
public synchronized void uploadEventLogs(View v) {
public synchronized void uploadEventLogs(View v) { // Send events log to JamOrHam
startActivity(new Intent(getApplicationContext(), SendFeedBack.class).putExtra("generic_text", packLogs()));
}

public synchronized void saveEventLog(View v) { // Save events log in mobile storage
startActivity(new Intent(getApplicationContext(), SaveLogs.class).putExtra("generic_text", packLogs()));
}

private String packLogs() { // Prepare current visible logs for upload or local save
final StringBuilder builder = new StringBuilder(50000);
builder.append("The following logs will be sent to the developers: \n\nPlease also include your email address or we will not know who they are from!\n\nFilter: "
builder.append("\n"
+ (model.allSeveritiesEnabled() ? "ALL" : model.whichSeveritiesEnabled()) + (model.getCurrentFilter() != "" ? " Search: " + model.getCurrentFilter() : "") + "\n\n");
for (UserError item : model.visible) {
builder.append(item.toString());
builder.append("\n");
if (builder.length() > 200000) {
if (builder.length() > MAX_LOG_PACKAGE_SIZE) {
JoH.static_toast_long(this, "Could not package up all logs, using most recent");
builder.append("\n\nOnly the most recent logs have been included to limit the file size.\n");
break;
}
}
startActivity(new Intent(getApplicationContext(), SendFeedBack.class).putExtra("generic_text", builder.toString()));

builder.insert(0, JoH.getDeviceDetails() + "\n" + JoH.getVersionDetails() + "\n" + getBestCollectorHardwareName() + "\n===\n" + "\nLog data:\n"); // Adds device, version and collector details before the log.
builder.append("\n\nCaptured: " + JoH.dateTimeText(JoH.tsl())); // Adds date and time of capture after the log.

return builder.toString();
}

// View model container - accessible binding methods must be declared public
Expand Down Expand Up @@ -636,5 +651,3 @@ public void onBindBinding(ViewDataBinding binding, int bindingVariable, @LayoutR
}
}



Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public class Constants {

static final int NIGHTSCOUT_ERROR_NOTIFICATION_ID = 2001;
public static final int HEALTH_CONNECT_RESPONSE_ID = 2002;
public static final int ZXING_CAM_REQ_CODE = 49374;
public static final int ZXING_FILE_REQ_CODE = 49375; // This is created by just incrementing the existing camera scan code from the zxing package
public static final int SENSORY_EXPIRY_NOTIFICATION_ID = 2003;


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package com.eveningoutpost.dexdrip.utilitymodels;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.TextView;

import com.eveningoutpost.dexdrip.BaseAppCompatActivity;
import com.eveningoutpost.dexdrip.R;
import com.eveningoutpost.dexdrip.models.JoH;
import com.eveningoutpost.dexdrip.models.UserError;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import static com.eveningoutpost.dexdrip.utils.FileUtils.makeSureDirectoryExists;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

// Saves xDrip logs to storage.
// SendFeedBack sends logs to the lead developer.
// This does the same thing for saving logs to storage.
// Navid200
// July 2024

public class SaveLogs extends BaseAppCompatActivity {

private static final String TAG = "save logs";
private String LOG_FILE_PATH = "/Download/xDrip-export"; // Path to where we save the log file
private String LOG_FILE_NAME = "xDrip-log.txt"; // Log file name
private final static int MY_PERMISSIONS_REQUEST_STORAGE = 104;
private String log_data = "";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_save_logs);

Intent intent = getIntent();
if (intent != null) {
final Bundle bundle = intent.getExtras();
if (bundle != null) {
final String str2 = bundle.getString("generic_text");
if (str2 != null) {
log_data = str2;
((TextView) findViewById(R.id.yourSaveText)).setText(log_data.length() > 300 ? "\n\nAttached " + log_data.length() + " characters of log data. (hidden)\n\n" : log_data);
}
}
}
}

public void closeActivity(View myview) {
finish();
}

public void saveLogs(View myview) {
if (saveLogsToStorage(log_data)) {
UserError.Log.e(TAG, "Saved log file to /Downloads/xDrip-export/xDrip-log.txt");
} else {
UserError.Log.e(TAG, "Could not write log file");
}
log_data = "";
closeActivity(null); // Let's close the menu
}

public boolean saveLogsToStorage(String contents) {
if (isStorageWritable(this, MY_PERMISSIONS_REQUEST_STORAGE)) {
try {
final StringBuilder sb = new StringBuilder();
sb.append(Environment.getExternalStorageDirectory().getAbsolutePath());
sb.append(LOG_FILE_PATH);
final String dir = sb.toString();
makeSureDirectoryExists(dir);
final String pathPlusFileName = dir + "/" + LOG_FILE_NAME;
final File myExternalFile = new File(pathPlusFileName);
FileOutputStream fos = new FileOutputStream(myExternalFile);
fos.write(contents.getBytes());
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
return true;
} else {
JoH.static_toast_long("getString(R.string.sdcard_not_writable_cannot_save)");
return false;
}
}

public static boolean isStorageWritable(Activity context, int request_code) { // Get write permission if not & return false. Return true if yes and not tied up.
if (ContextCompat.checkSelfPermission(context,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(context,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
request_code);
UserError.Log.e(TAG, "Did not have write permission, but should have it now");
return false;
}
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state);
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ protected void onCreate(Bundle savedInstanceState) {
final String str2 = bundle.getString("generic_text");
if (str2 != null) {
log_data = str2;
((EditText) findViewById(R.id.yourText)).setText(log_data.length() > 300 ? "\n\nPlease describe what you think these logs may show? Explain the problem if there is one.\n\nAttached " + log_data.length() + " characters of log data. (hidden)\n\n" : log_data);
((EditText) findViewById(R.id.yourText)).setText(log_data.length() > 300 ? "\n\nPlease describe what you think these logs may show. Explain the problem if there is one.\n\nAttached " + log_data.length() + " characters of log data. (hidden)\n\n" : log_data);
type_of_message = "Log Push";
myrating.setVisibility(View.GONE);
ratingtext.setVisibility(View.GONE);
Expand Down Expand Up @@ -177,7 +177,7 @@ public void sendFeedback(View myview) {
try {
final RequestBody formBody = new FormEncodingBuilder()
.add("contact", contact.getText().toString())
.add("body", JoH.getDeviceDetails() + "\n" + JoH.getVersionDetails() + "\n" + getBestCollectorHardwareName() + "\n===\n\n" + yourtext.getText().toString() + " \n\n===\nType: " + type_of_message + "\nLog data:\n\n" + log_data + "\n\n\nSent: " + JoH.dateTimeText(JoH.tsl()))
.add("body",yourtext.getText().toString() + " \n\n===\nType: " + type_of_message + "\nLog data:\n\n" + log_data) // Adding "Your text" and type to the log
.add("rating", String.valueOf(myrating.getRating()))
.add("type", type_of_message)
.build();
Expand Down
98 changes: 86 additions & 12 deletions app/src/main/java/com/eveningoutpost/dexdrip/utils/Preferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.media.Ringtone;
import android.media.RingtoneManager;
Expand Down Expand Up @@ -124,12 +126,20 @@
import com.eveningoutpost.dexdrip.webservices.XdripWebService;
import com.eveningoutpost.dexdrip.xDripWidget;
import com.eveningoutpost.dexdrip.xdrip;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import com.nightscout.core.barcode.NSBarcodeConfig;

import net.tribe7.common.base.Joiner;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URI;
import java.text.DecimalFormat;
Expand Down Expand Up @@ -170,6 +180,13 @@ public class Preferences extends BasePreferenceActivity implements SearchPrefere
private static AllPrefsFragment pFragment;
private BroadcastReceiver mibandStatusReceiver;

// The following three variables enable us to create a common state from the input,
// whether we scan from camera or a file, and continue with the same following
// set of commands to avoid code duplication.
private volatile String scanFormat = null; // The format of the scan
private volatile String scanContents = null; // Text content of the scan coming either from camera or file
private volatile byte[] scanRawBytes = null; // Raw bytes of the scan

private void refreshFragments() {
refreshFragments(null);
}
Expand Down Expand Up @@ -341,7 +358,11 @@ public static Boolean getBooleanPreferenceViaContextWithoutException(Context con


@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
protected synchronized void onActivityResult(int requestCode, int resultCode, Intent data) {
// Let's reset variables just to be sure
scanFormat = null;
scanContents = null;
scanRawBytes = null;
if (requestCode == Constants.HEALTH_CONNECT_RESPONSE_ID) {
if (HealthConnectEntry.enabled()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Expand All @@ -352,22 +373,64 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
}

if (requestCode == Constants.ZXING_FILE_REQ_CODE) { // If we are scanning an image file, not using the camera
// The core of the following section, selecting the file, converting it into a bitmap, and then to a bitstream, is from:
// https://stackoverflow.com/questions/55427308/scaning-qrcode-from-image-not-from-camera-using-zxing
if (data == null || data.getData() == null) {
Log.e("TAG", "No file was selected");
return;
}
Uri uri = data.getData();
try {
InputStream inputStream = getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
if (bitmap == null) {
Log.e("TAG", "uri is not a bitmap," + uri.toString());
return;
}
int width = bitmap.getWidth(), height = bitmap.getHeight();
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
bitmap.recycle();
bitmap = null;
RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);
BinaryBitmap bBitmap = new BinaryBitmap(new HybridBinarizer(source));
MultiFormatReader reader = new MultiFormatReader();
try {
Result result = reader.decode(bBitmap);
scanFormat = result.getBarcodeFormat().toString();
scanContents = result.getText(); // The text content of the scanned file
scanRawBytes = result.getRawBytes();
} catch (NotFoundException e) {
Log.e("TAG", "decode exception", e);
}
} catch (FileNotFoundException e) {
Log.e("TAG", "can not open file" + uri.toString(), e);
}
} else if (requestCode == Constants.ZXING_CAM_REQ_CODE) { // If we are scanning from camera
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
scanFormat = scanResult.getFormatName();
scanContents = scanResult.getContents(); // The text content of the scan from camera
scanRawBytes = scanResult.getRawBytes();
}
// We now have scan format, scan text content, and scan raw bytes in the corresponding variables.
// Everything after this is applied whether we scanned with camera or from a file.

IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (scanResult == null || scanResult.getContents() == null) {
if (scanContents == null) { // If we have no scan content
UserError.Log.d(TAG, "No scan results ");
return;
}
if (scanResult.getFormatName().equals("QR_CODE")) {

final String scanresults = scanResult.getContents();
if (QRcodeUtils.hasDecoderMarker(scanresults)) {
installxDripPlusPreferencesFromQRCode(prefs, scanresults);
if (scanFormat.equals("QR_CODE")) { // The scan is a QR code

if (QRcodeUtils.hasDecoderMarker(scanContents)) {
installxDripPlusPreferencesFromQRCode(prefs, scanContents);
return;
}

try {
if (BlueJay.processQRCode(scanResult.getRawBytes())) {
if (BlueJay.processQRCode(scanRawBytes)) {
refreshFragments();
return;
}
Expand All @@ -376,7 +439,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
}


final NSBarcodeConfig barcode = new NSBarcodeConfig(scanresults);
final NSBarcodeConfig barcode = new NSBarcodeConfig(scanContents);
if (barcode.hasMongoConfig()) {
if (barcode.getMongoUri().isPresent()) {
SharedPreferences.Editor editor = prefs.edit();
Expand Down Expand Up @@ -427,9 +490,9 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
editor.putBoolean("cloud_storage_mqtt_enable", false);
editor.apply();
}
} else if (scanResult.getFormatName().equals("CODE_128")) {
Log.d(TAG, "Setting serial number to: " + scanResult.getContents());
prefs.edit().putString("share_key", scanResult.getContents()).apply();
} else if (scanFormat.equals("CODE_128")) {
Log.d(TAG, "Setting serial number to: " + scanContents);
prefs.edit().putString("share_key", scanContents).apply();
}
refreshFragments();
}
Expand Down Expand Up @@ -1006,6 +1069,7 @@ public void onCreate(Bundle savedInstanceState) {
addPreferencesFromResource(R.xml.pref_data_sync);
setupBarcodeConfigScanner();
setupBarcodeShareScanner();
setupQrFromFile();
bindPreferenceSummaryToValue(findPreference("cloud_storage_mongodb_uri"));
bindPreferenceSummaryToValue(findPreference("cloud_storage_mongodb_collection"));
bindPreferenceSummaryToValue(findPreference("cloud_storage_mongodb_device_status_collection"));
Expand Down Expand Up @@ -2853,6 +2917,16 @@ public boolean onPreferenceClick(Preference preference) {
});
}

private void setupQrFromFile() {
findPreference("qr_code_from_file").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) { // Listener for scanning QR code from file
new QrCodeFromFile(getActivity()).scanFile();
return true;
}
});
}

private void refresh_extra_items() {
try {
if (this.prefs == null) return;
Expand Down
Loading

0 comments on commit 0bd5d9b

Please sign in to comment.