X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserAndroid.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Factivities%2FLogcatActivity.java;h=7878f985ab5609841867b0554e966a2df869d132;hp=32d1bf47d1e831ddc97f2e0d35322821c4937ba9;hb=b82022327701273b1b56419e8d6042895c0bc7b9;hpb=33bd447a83bd3d763ee26bbb3a3f4adb074776ed diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.java index 32d1bf47..7878f985 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.java @@ -1,5 +1,5 @@ /* - * Copyright © 2019 Soren Stoutner . + * Copyright © 2019-2020 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -25,31 +25,38 @@ import android.app.Dialog; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.media.MediaScannerConnection; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; -import android.os.Environment; -import android.support.annotation.NonNull; -import android.support.design.widget.Snackbar; -import android.support.v4.app.ActivityCompat; -import android.support.v4.app.DialogFragment; -import android.support.v4.content.ContextCompat; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.app.AppCompatDialogFragment; -import android.support.v7.widget.Toolbar; +import android.preference.PreferenceManager; +import android.util.TypedValue; import android.view.Menu; import android.view.MenuItem; +import android.view.View; import android.view.WindowManager; import android.widget.EditText; +import android.widget.ScrollView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.DialogFragment; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; + +import com.google.android.material.snackbar.Snackbar; + import com.stoutner.privacybrowser.R; +import com.stoutner.privacybrowser.asynctasks.GetLogcat; import com.stoutner.privacybrowser.dialogs.StoragePermissionDialog; import com.stoutner.privacybrowser.dialogs.SaveLogcatDialog; +import com.stoutner.privacybrowser.helpers.FileNameHelper; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -60,25 +67,33 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; -import java.lang.ref.WeakReference; import java.nio.charset.StandardCharsets; public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialog.SaveLogcatListener, StoragePermissionDialog.StoragePermissionDialogListener { + // Initialize the saved instance state constants. + private final String SCROLLVIEW_POSITION = "scrollview_position"; + + // Define the class variables. private String filePathString; + // Define the class views. + private TextView logcatTextView; + @Override public void onCreate(Bundle savedInstanceState) { + // Get a handle for the shared preferences. + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + + // Get the screenshot preference. + boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false); + // Disable screenshots if not allowed. - if (!MainWebViewActivity.allowScreenshots) { + if (!allowScreenshots) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); } - // Set the activity theme. - if (MainWebViewActivity.darkTheme) { - setTheme(R.style.PrivacyBrowserDark_SecondaryActivity); - } else { - setTheme(R.style.PrivacyBrowserLight_SecondaryActivity); - } + // Set the theme. + setTheme(R.style.PrivacyBrowser); // Run the default commands. super.onCreate(savedInstanceState); @@ -86,36 +101,62 @@ public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialo // Set the content view. setContentView(R.layout.logcat_coordinatorlayout); - // Use the `SupportActionBar` from `android.support.v7.app.ActionBar` until the minimum API is >= 21. - Toolbar logcatAppBar = findViewById(R.id.logcat_toolbar); - setSupportActionBar(logcatAppBar); + // Set the toolbar as the action bar. + Toolbar toolbar = findViewById(R.id.logcat_toolbar); + setSupportActionBar(toolbar); - // Get a handle for the app bar. - ActionBar appBar = getSupportActionBar(); + // Get a handle for the action bar. + ActionBar actionBar = getSupportActionBar(); - // Remove the incorrect lint warning that `appBar` might be null. - assert appBar != null; + // Remove the incorrect lint warning that the action bar might be null. + assert actionBar != null; - // Display the the back arrow in the app bar. - appBar.setDisplayHomeAsUpEnabled(true); + // Display the the back arrow in the action bar. + actionBar.setDisplayHomeAsUpEnabled(true); + + // Populate the class views. + logcatTextView = findViewById(R.id.logcat_textview); // Implement swipe to refresh. SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.logcat_swiperefreshlayout); swipeRefreshLayout.setOnRefreshListener(() -> { // Get the current logcat. - new GetLogcat(this).execute(); + new GetLogcat(this, 0).execute(); }); - // Set the swipe to refresh color according to the theme. - if (MainWebViewActivity.darkTheme) { - swipeRefreshLayout.setColorSchemeResources(R.color.blue_600); - swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.gray_800); + // Get the current theme status. + int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + + // Set the refresh color scheme according to the theme. + if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { + swipeRefreshLayout.setColorSchemeResources(R.color.blue_500); } else { swipeRefreshLayout.setColorSchemeResources(R.color.blue_700); } + // Initialize a color background typed value. + TypedValue colorBackgroundTypedValue = new TypedValue(); + + // Get the color background from the theme. + getTheme().resolveAttribute(android.R.attr.colorBackground, colorBackgroundTypedValue, true); + + // Get the color background int from the typed value. + int colorBackgroundInt = colorBackgroundTypedValue.data; + + // Set the swipe refresh background color. + swipeRefreshLayout.setProgressBackgroundColorSchemeColor(colorBackgroundInt); + + // Initialize the scrollview Y position int. + int scrollViewYPositionInt = 0; + + // Check to see if the activity has been restarted. + if (savedInstanceState != null) { + // Get the saved scrollview position. + scrollViewYPositionInt = savedInstanceState.getInt(SCROLLVIEW_POSITION); + } + // Get the logcat. - new GetLogcat(this).execute(); + new GetLogcat(this, scrollViewYPositionInt).execute(); } @Override @@ -138,9 +179,6 @@ public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialo // Get a handle for the clipboard manager. ClipboardManager clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); - // Get a handle for the logcat text view. - TextView logcatTextView = findViewById(R.id.logcat_textview); - // Save the logcat in a ClipData. ClipData logcatClipData = ClipData.newPlainText(getString(R.string.logcat), logcatTextView.getText()); @@ -157,7 +195,7 @@ public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialo return true; case R.id.save: - // Get a handle for the save alert dialog. + // Instantiate the save alert dialog. DialogFragment saveDialogFragment = new SaveLogcatDialog(); // Show the save alert dialog. @@ -175,7 +213,7 @@ public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialo process.waitFor(); // Reload the logcat. - new GetLogcat(this).execute(); + new GetLogcat(this, 0).execute(); } catch (IOException|InterruptedException exception) { // Do nothing. } @@ -190,9 +228,30 @@ public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialo } @Override - public void onSaveLogcat(AppCompatDialogFragment dialogFragment) { + public void onSaveInstanceState(@NonNull Bundle savedInstanceState) { + // Run the default commands. + super.onSaveInstanceState(savedInstanceState); + + // Get a handle for the logcat scrollview. + ScrollView logcatScrollView = findViewById(R.id.logcat_scrollview); + + // Get the scrollview Y position. + int scrollViewYPositionInt = logcatScrollView.getScrollY(); + + // Store the scrollview Y position in the bundle. + savedInstanceState.putInt(SCROLLVIEW_POSITION, scrollViewYPositionInt); + } + + @Override + public void onSaveLogcat(DialogFragment dialogFragment) { + // Get a handle for the dialog fragment. + Dialog dialog = dialogFragment.getDialog(); + + // Remove the lint warning below that the dialog fragment might be null. + assert dialog != null; + // Get a handle for the file name edit text. - EditText fileNameEditText = dialogFragment.getDialog().findViewById(R.id.file_name_edittext); + EditText fileNameEditText = dialog.findViewById(R.id.file_name_edittext); // Get the file path string. filePathString = fileNameEditText.getText().toString(); @@ -219,12 +278,12 @@ public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialo // Check if the user has previously denied the storage permission. if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first. // Instantiate the storage permission alert dialog. - DialogFragment storagePermissionDialogFragment = new StoragePermissionDialog(); + DialogFragment storagePermissionDialogFragment = StoragePermissionDialog.displayDialog(0); // Show the storage permission alert dialog. The permission will be requested when the dialog is closed. storagePermissionDialogFragment.show(getSupportFragmentManager(), getString(R.string.storage_permission)); } else { // Show the permission request directly. - // Request the storage permission. The logcat will be saved when it finishes. + // Request the write external storage permission. The logcat will be saved when it finishes. ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); } @@ -233,7 +292,7 @@ public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialo } @Override - public void onCloseStoragePermissionDialog() { + public void onCloseStoragePermissionDialog(int type) { // Request the write external storage permission. The logcat will be saved when it finishes. ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); } @@ -245,18 +304,12 @@ public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialo // Save the logcat. saveLogcat(filePathString); } else { // The storage permission was not granted. - // Get a handle for the logcat text view. - TextView logcatTextView = findViewById(R.id.logcat_textview); - // Display an error snackbar. Snackbar.make(logcatTextView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show(); } } private void saveLogcat(String fileNameString) { - // Get a handle for the logcat text view. - TextView logcatTextView = findViewById(R.id.logcat_textview); - try { // Get the logcat as a string. String logcatString = logcatTextView.getText().toString(); @@ -303,146 +356,47 @@ public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialo // The activity result is called after browsing for a file in the save alert dialog. @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { + // Run the default commands. + super.onActivityResult(requestCode, resultCode, data); + // Don't do anything if the user pressed back from the file picker. if (resultCode == Activity.RESULT_OK) { // Get a handle for the save dialog fragment. DialogFragment saveDialogFragment = (DialogFragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.save_logcat)); - // Remove the incorrect lint error that the save dialog fragment might be null. - assert saveDialogFragment != null; + // Only update the file name if the dialog still exists. + if (saveDialogFragment != null) { + // Get a handle for the save dialog. + Dialog saveDialog = saveDialogFragment.getDialog(); - // Get a handle for the save dialog. - Dialog saveDialog = saveDialogFragment.getDialog(); + // Remove the lint warning below that the save dialog might be null. + assert saveDialog != null; - // Get a handle for the file name edit text. - EditText fileNameEditText = saveDialog.findViewById(R.id.file_name_edittext); + // Get a handle for the dialog views. + EditText fileNameEditText = saveDialog.findViewById(R.id.file_name_edittext); + TextView fileExistsWarningTextView = saveDialog.findViewById(R.id.file_exists_warning_textview); - // Get the file name URI. - Uri fileNameUri = data.getData(); + // Instantiate the file name helper. + FileNameHelper fileNameHelper = new FileNameHelper(); - // Remove the incorrect lint warning that the file name URI might be null. - assert fileNameUri != null; + // Get the file name URI from the intent. + Uri fileNameUri= data.getData(); - // Get the raw file name path. - String rawFileNamePath = fileNameUri.getPath(); + // Process the file name URI if it is not null. + if (fileNameUri != null) { + // Convert the file name URI to a file name path. + String fileNamePath = fileNameHelper.convertUriToFileNamePath(fileNameUri); - // Remove the incorrect lint warning that the file name path might be null. - assert rawFileNamePath != null; + // Set the file name path as the text of the file name edit text. + fileNameEditText.setText(fileNamePath); - // Check to see if the file name Path includes a valid storage location. - if (rawFileNamePath.contains(":")) { // The path is valid. - // Split the path into the initial content uri and the final path information. - String fileNameContentPath = rawFileNamePath.substring(0, rawFileNamePath.indexOf(":")); - String fileNameFinalPath = rawFileNamePath.substring(rawFileNamePath.indexOf(":") + 1); + // Move the cursor to the end of the file name edit text. + fileNameEditText.setSelection(fileNamePath.length()); - // Create the file name path string. - String fileNamePath; - - // Construct the file name path. - switch (fileNameContentPath) { - // The documents home has a special content path. - case "/document/home": - fileNamePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/" + fileNameFinalPath; - break; - - // Everything else for the primary user should be in `/document/primary`. - case "/document/primary": - fileNamePath = Environment.getExternalStorageDirectory() + "/" + fileNameFinalPath; - break; - - // Just in case, catch everything else and place it in the external storage directory. - default: - fileNamePath = Environment.getExternalStorageDirectory() + "/" + fileNameFinalPath; - break; + // Hide the file exists warning. + fileExistsWarningTextView.setVisibility(View.GONE); } - - // Set the file name path as the text of the file name edit text. - fileNameEditText.setText(fileNamePath); - } else { // The path is invalid. - // Close the alert dialog. - saveDialog.dismiss(); - - // Get a handle for the logcat text view. - TextView logcatTextView = findViewById(R.id.logcat_textview); - - // Display a snackbar with the error message. - Snackbar.make(logcatTextView, rawFileNamePath + " " + getString(R.string.invalid_location), Snackbar.LENGTH_INDEFINITE).show(); - } - } - } - - // `Void` does not declare any parameters. `Void` does not declare progress units. `String` contains the results. - private static class GetLogcat extends AsyncTask { - // Create a weak reference to the calling activity. - private final WeakReference activityWeakReference; - - // Populate the weak reference to the calling activity. - GetLogcat(Activity activity) { - activityWeakReference = new WeakReference<>(activity); - } - - @Override - protected String doInBackground(Void... parameters) { - // Get a handle for the activity. - Activity activity = activityWeakReference.get(); - - // Abort if the activity is gone. - if ((activity == null) || activity.isFinishing()) { - return ""; } - - // Create a log string builder. - StringBuilder logStringBuilder = new StringBuilder(); - - try { - // Get the logcat. `-b all` gets all the buffers (instead of just crash, main, and system). `-v long` produces more complete information. `-d` dumps the logcat and exits. - Process process = Runtime.getRuntime().exec("logcat -b all -v long -d"); - - // Wrap the logcat in a buffered reader. - BufferedReader logBufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); - - // Create a log transfer string. - String logTransferString; - - // Use the log transfer string to copy the logcat from the buffered reader to the string builder. - while ((logTransferString = logBufferedReader.readLine()) != null) { - // Append a line. - logStringBuilder.append(logTransferString); - - // Append a line break. - logStringBuilder.append("\n"); - } - - // Close the buffered reader. - logBufferedReader.close(); - } catch (IOException exception) { - // Do nothing. - } - - // Return the logcat. - return logStringBuilder.toString(); - } - - // `onPostExecute()` operates on the UI thread. - @Override - protected void onPostExecute(String logcatString) { - // Get a handle for the activity. - Activity activity = activityWeakReference.get(); - - // Abort if the activity is gone. - if ((activity == null) || activity.isFinishing()) { - return; - } - - // Get handles for the views. - TextView logcatTextView = activity.findViewById(R.id.logcat_textview); - SwipeRefreshLayout swipeRefreshLayout = activity.findViewById(R.id.logcat_swiperefreshlayout); - - // Display the logcat. - logcatTextView.setText(logcatString); - - // Stop the swipe to refresh animation if it is displayed. - swipeRefreshLayout.setRefreshing(false); } } } \ No newline at end of file