/*
- * Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
*
package com.stoutner.privacybrowser.fragments;
import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.ActivityManager;
import android.content.Context;
-import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
+import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
-import android.preference.PreferenceManager;
+import android.os.Handler;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
+import androidx.webkit.WebViewCompat;
import com.stoutner.privacybrowser.BuildConfig;
import com.stoutner.privacybrowser.R;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
+import java.text.NumberFormat;
import java.util.Date;
public class AboutTabFragment extends Fragment {
+ // Declare the class constants.
+ final static String TAB_NUMBER = "tab_number";
+ final static String BLOCKLIST_VERSIONS = "blocklist_versions";
+ final long MEBIBYTE = 1048576;
+
// Declare the class variables.
+ private boolean updateMemoryUsageBoolean = true;
private int tabNumber;
private String[] blocklistVersions;
+ private View tabLayout;
+ private String appConsumedMemoryLabel;
+ private String appAvailableMemoryLabel;
+ private String appTotalMemoryLabel;
+ private String appMaximumMemoryLabel;
+ private String systemConsumedMemoryLabel;
+ private String systemAvailableMemoryLabel;
+ private String systemTotalMemoryLabel;
+ private Runtime runtime;
+ private ActivityManager activityManager;
+ private ActivityManager.MemoryInfo memoryInfo;
+ private NumberFormat numberFormat;
+ private ForegroundColorSpan blueColorSpan;
+
+ // Declare the class views.
+ private TextView appConsumedMemoryTextView;
+ private TextView appAvailableMemoryTextView;
+ private TextView appTotalMemoryTextView;
+ private TextView appMaximumMemoryTextView;
+ private TextView systemConsumedMemoryTextView;
+ private TextView systemAvailableMemoryTextView;
+ private TextView systemTotalMemoryTextView;
public static AboutTabFragment createTab(int tabNumber, String[] blocklistVersions) {
// Create a bundle.
Bundle argumentsBundle = new Bundle();
// Store the tab number in the bundle.
- argumentsBundle.putInt("tab_number", tabNumber);
- argumentsBundle.putStringArray("blocklist_versions", blocklistVersions);
+ argumentsBundle.putInt(TAB_NUMBER, tabNumber);
+ argumentsBundle.putStringArray(BLOCKLIST_VERSIONS, blocklistVersions);
// Create a new instance of the tab fragment.
AboutTabFragment aboutTabFragment = new AboutTabFragment();
assert arguments != null;
// Store the arguments in class variables.
- tabNumber = getArguments().getInt("tab_number");
- blocklistVersions = getArguments().getStringArray("blocklist_versions");
+ tabNumber = getArguments().getInt(TAB_NUMBER);
+ blocklistVersions = getArguments().getStringArray(BLOCKLIST_VERSIONS);
}
@Override
public View onCreateView(@NonNull LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) {
- // Create a tab layout view.
- View tabLayout;
-
// Get a handle for the context and assert that it isn't null.
Context context = getContext();
assert context != null;
- // Get a handle for the shared preferences.
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
-
- // Get the theme preference.
- boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
+ // Get the current theme status.
+ int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
// Load the tabs. Tab numbers start at 0.
if (tabNumber == 0) { // Load the about tab.
TextView webViewProviderTextView = tabLayout.findViewById(R.id.webview_provider);
TextView webViewVersionTextView = tabLayout.findViewById(R.id.webview_version);
TextView orbotTextView = tabLayout.findViewById(R.id.orbot);
+ TextView i2pTextView = tabLayout.findViewById(R.id.i2p);
TextView openKeychainTextView = tabLayout.findViewById(R.id.open_keychain);
+ appConsumedMemoryTextView = tabLayout.findViewById(R.id.app_consumed_memory);
+ appAvailableMemoryTextView = tabLayout.findViewById(R.id.app_available_memory);
+ appTotalMemoryTextView = tabLayout.findViewById(R.id.app_total_memory);
+ appMaximumMemoryTextView = tabLayout.findViewById(R.id.app_maximum_memory);
+ systemConsumedMemoryTextView = tabLayout.findViewById(R.id.system_consumed_memory);
+ systemAvailableMemoryTextView = tabLayout.findViewById(R.id.system_available_memory);
+ systemTotalMemoryTextView = tabLayout.findViewById(R.id.system_total_memory);
TextView easyListTextView = tabLayout.findViewById(R.id.easylist);
TextView easyPrivacyTextView = tabLayout.findViewById(R.id.easyprivacy);
TextView fanboyAnnoyanceTextView = tabLayout.findViewById(R.id.fanboy_annoyance);
String androidLabel = getString(R.string.android) + " ";
String buildLabel = getString(R.string.build) + " ";
String webViewVersionLabel = getString(R.string.webview_version) + " ";
+ appConsumedMemoryLabel = getString(R.string.app_consumed_memory) + " ";
+ appAvailableMemoryLabel = getString(R.string.app_available_memory) + " ";
+ appTotalMemoryLabel = getString(R.string.app_total_memory) + " ";
+ appMaximumMemoryLabel = getString(R.string.app_maximum_memory) + " ";
+ systemConsumedMemoryLabel = getString(R.string.system_consumed_memory) + " ";
+ systemAvailableMemoryLabel = getString(R.string.system_available_memory) + " ";
+ systemTotalMemoryLabel = getString(R.string.system_total_memory) + " ";
String easyListLabel = getString(R.string.easylist_label) + " ";
String easyPrivacyLabel = getString(R.string.easyprivacy_label) + " ";
String fanboyAnnoyanceLabel = getString(R.string.fanboy_annoyance_label) + " ";
orbot = "";
}
+ // Get the I2P version name if I2P is installed.
+ String i2p;
+ try {
+ // Store the version name.
+ i2p = context.getPackageManager().getPackageInfo("net.i2p.android.router", 0).versionName;
+ } catch (PackageManager.NameNotFoundException exception) { // I2P is not installed.
+ i2p = "";
+ }
+
// Get the OpenKeychain version name if it is installed.
String openKeychain;
try {
openKeychain = "";
}
- // Create a `SpannableStringBuilder` for the hardware and software `TextViews` that needs multiple colors of text.
+ // Create a spannable string builder for the hardware and software text views that needs multiple colors of text.
SpannableStringBuilder brandStringBuilder = new SpannableStringBuilder(brandLabel + brand);
SpannableStringBuilder manufacturerStringBuilder = new SpannableStringBuilder(manufacturerLabel + manufacturer);
SpannableStringBuilder modelStringBuilder = new SpannableStringBuilder(modelLabel + model);
SpannableStringBuilder ultraListStringBuilder = new SpannableStringBuilder(ultraListLabel + blocklistVersions[4]);
SpannableStringBuilder ultraPrivacyStringBuilder = new SpannableStringBuilder(ultraPrivacyLabel + blocklistVersions[5]);
- // Create the `blueColorSpan` variable.
- ForegroundColorSpan blueColorSpan;
-
- // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
- if (darkTheme) {
- blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
- } else {
+ // Set the blue color span according to the theme. The deprecated `getResources()` must be used until the minimum API >= 23.
+ if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
+ } else {
+ blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.violet_500));
}
// Setup the spans to display the device information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
securityPatchTextView.setVisibility(View.GONE);
}
- // Only populate the WebView provider if the SDK >= 26.
- if (Build.VERSION.SDK_INT >= 26) {
+ // Only populate the WebView provider if the SDK >= 21.
+ if (Build.VERSION.SDK_INT >= 21) {
// Create the WebView provider label.
String webViewProviderLabel = getString(R.string.webview_provider) + " ";
// Get the current WebView package info.
- PackageInfo webViewPackageInfo = WebView.getCurrentWebViewPackage();
+ PackageInfo webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(context);
// Remove the warning below that the package info might be null.
assert webViewPackageInfo != null;
// Display the WebView provider.
webViewProviderTextView.setText(webViewProviderStringBuilder);
- } else { // The API < 26.
+ } else { // The API < 21.
// Hide the WebView provider text view.
webViewProviderTextView.setVisibility(View.GONE);
}
orbotTextView.setVisibility(View.GONE);
}
+ // Only populate the I2P text view if it is installed.
+ if (!i2p.isEmpty()) {
+ String i2pLabel = getString(R.string.i2p) + " ";
+ SpannableStringBuilder i2pStringBuilder = new SpannableStringBuilder(i2pLabel + i2p);
+ i2pStringBuilder.setSpan(blueColorSpan, i2pLabel.length(), i2pStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ i2pTextView.setText(i2pStringBuilder);
+ } else { // I2P is not installed.
+ i2pTextView.setVisibility(View.GONE);
+ }
+
// Only populate the OpenKeychain text view if it is installed.
if (!openKeychain.isEmpty()) {
String openKeychainLabel = getString(R.string.openkeychain) + " ";
} catch (CertificateException e) {
// Do nothing if there is a certificate error.
}
+
+ // Get a handle for the runtime.
+ runtime = Runtime.getRuntime();
+
+ // Get a handle for the activity.
+ Activity activity = getActivity();
+
+ // Remove the incorrect lint warning below that the activity might be null.
+ assert activity != null;
+
+ // Get a handle for the activity manager.
+ activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
+
+ // Remove the incorrect lint warning below that the activity manager might be null.
+ assert activityManager != null;
+
+ // Instantiate a memory info variable.
+ memoryInfo = new ActivityManager.MemoryInfo();
+
+ // Define a number format.
+ numberFormat = NumberFormat.getInstance();
+
+ // Set the minimum and maximum number of fraction digits.
+ numberFormat.setMinimumFractionDigits(2);
+ numberFormat.setMaximumFractionDigits(2);
+
+ // Update the memory usage.
+ updateMemoryUsage(getActivity());
} catch (PackageManager.NameNotFoundException e) {
// Do nothing if `PackageManager` says Privacy Browser isn't installed.
}
WebView tabWebView = (WebView) tabLayout;
// Load the tabs according to the theme.
- if (darkTheme) { // The dark theme is applied.
+ if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) { // The dark theme is applied.
// Set the background color. The deprecated `.getColor()` must be used until the minimum API >= 23.
tabWebView.setBackgroundColor(getResources().getColor(R.color.gray_850));
}
}
+ // Scroll the tab if the saved instance state is not null.
+ if (savedInstanceState != null) {
+ tabLayout.post(() -> {
+ tabLayout.setScrollX(savedInstanceState.getInt("scroll_x"));
+ tabLayout.setScrollY(savedInstanceState.getInt("scroll_y"));
+ });
+ }
+
// Return the formatted `tabLayout`.
return tabLayout;
}
+
+ @Override
+ public void onPause() {
+ // Run the default commands.
+ super.onPause();
+
+ // Pause the updating of the memory usage.
+ updateMemoryUsageBoolean = false;
+ }
+
+ @Override
+ public void onResume() {
+ // Run the default commands.
+ super.onResume();
+
+ // Resume the updating of the memory usage.
+ updateMemoryUsageBoolean = true;
+ }
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
+ // Run the default commands.
+ super.onSaveInstanceState(savedInstanceState);
+
+ // Save the scroll positions if the tab layout is not null, which can happen if a tab is not currently selected.
+ if (tabLayout != null) {
+ savedInstanceState.putInt("scroll_x", tabLayout.getScrollX());
+ savedInstanceState.putInt("scroll_y", tabLayout.getScrollY());
+ }
+ }
+
+ public void updateMemoryUsage(Activity activity) {
+ try {
+ // Update the memory usage if enabled.
+ if (updateMemoryUsageBoolean) {
+ // Populate the memory info variable.
+ activityManager.getMemoryInfo(memoryInfo);
+
+ // Get the app memory information.
+ long appAvailableMemoryLong = runtime.freeMemory();
+ long appTotalMemoryLong = runtime.totalMemory();
+ long appMaximumMemoryLong = runtime.maxMemory();
+
+ // Calculate the app consumed memory.
+ long appConsumedMemoryLong = appTotalMemoryLong - appAvailableMemoryLong;
+
+ // Get the system memory information.
+ long systemTotalMemoryLong = memoryInfo.totalMem;
+ long systemAvailableMemoryLong = memoryInfo.availMem;
+
+ // Calculate the system consumed memory.
+ long systemConsumedMemoryLong = systemTotalMemoryLong - systemAvailableMemoryLong;
+
+ // Convert the memory information into mebibytes.
+ float appConsumedMemoryFloat = (float) appConsumedMemoryLong / MEBIBYTE;
+ float appAvailableMemoryFloat = (float) appAvailableMemoryLong / MEBIBYTE;
+ float appTotalMemoryFloat = (float) appTotalMemoryLong / MEBIBYTE;
+ float appMaximumMemoryFloat = (float) appMaximumMemoryLong / MEBIBYTE;
+ float systemConsumedMemoryFloat = (float) systemConsumedMemoryLong / MEBIBYTE;
+ float systemAvailableMemoryFloat = (float) systemAvailableMemoryLong / MEBIBYTE;
+ float systemTotalMemoryFloat = (float) systemTotalMemoryLong / MEBIBYTE;
+
+ // Get the mebibyte string.
+ String mebibyte = getString(R.string.mebibyte);
+
+ // Calculate the mebibyte length.
+ int mebibyteLength = mebibyte.length();
+
+ // Create spannable string builders.
+ SpannableStringBuilder appConsumedMemoryStringBuilder = new SpannableStringBuilder(appConsumedMemoryLabel + numberFormat.format(appConsumedMemoryFloat) + " " + mebibyte);
+ SpannableStringBuilder appAvailableMemoryStringBuilder = new SpannableStringBuilder(appAvailableMemoryLabel + numberFormat.format(appAvailableMemoryFloat) + " " + mebibyte);
+ SpannableStringBuilder appTotalMemoryStringBuilder = new SpannableStringBuilder(appTotalMemoryLabel + numberFormat.format(appTotalMemoryFloat) + " " + mebibyte);
+ SpannableStringBuilder appMaximumMemoryStringBuilder = new SpannableStringBuilder(appMaximumMemoryLabel + numberFormat.format(appMaximumMemoryFloat) + " " + mebibyte);
+ SpannableStringBuilder systemConsumedMemoryStringBuilder = new SpannableStringBuilder(systemConsumedMemoryLabel + numberFormat.format(systemConsumedMemoryFloat) + " " + mebibyte);
+ SpannableStringBuilder systemAvailableMemoryStringBuilder = new SpannableStringBuilder(systemAvailableMemoryLabel + numberFormat.format(systemAvailableMemoryFloat) + " " + mebibyte);
+ SpannableStringBuilder systemTotalMemoryStringBuilder = new SpannableStringBuilder(systemTotalMemoryLabel + numberFormat.format(systemTotalMemoryFloat) + " " + mebibyte);
+
+ // Setup the spans to display the memory information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ appConsumedMemoryStringBuilder.setSpan(blueColorSpan, appConsumedMemoryLabel.length(), appConsumedMemoryStringBuilder.length() - mebibyteLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ appAvailableMemoryStringBuilder.setSpan(blueColorSpan, appAvailableMemoryLabel.length(), appAvailableMemoryStringBuilder.length() - mebibyteLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ appTotalMemoryStringBuilder.setSpan(blueColorSpan, appTotalMemoryLabel.length(), appTotalMemoryStringBuilder.length() - mebibyteLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ appMaximumMemoryStringBuilder.setSpan(blueColorSpan, appMaximumMemoryLabel.length(), appMaximumMemoryStringBuilder.length() - mebibyteLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ systemConsumedMemoryStringBuilder.setSpan(blueColorSpan, systemConsumedMemoryLabel.length(), systemConsumedMemoryStringBuilder.length() - mebibyteLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ systemAvailableMemoryStringBuilder.setSpan(blueColorSpan, systemAvailableMemoryLabel.length(), systemAvailableMemoryStringBuilder.length() - mebibyteLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ systemTotalMemoryStringBuilder.setSpan(blueColorSpan, systemTotalMemoryLabel.length(), systemTotalMemoryStringBuilder.length() - mebibyteLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+
+ // Display the string in the text boxes.
+ appConsumedMemoryTextView.setText(appConsumedMemoryStringBuilder);
+ appAvailableMemoryTextView.setText(appAvailableMemoryStringBuilder);
+ appTotalMemoryTextView.setText(appTotalMemoryStringBuilder);
+ appMaximumMemoryTextView.setText(appMaximumMemoryStringBuilder);
+ systemConsumedMemoryTextView.setText(systemConsumedMemoryStringBuilder);
+ systemAvailableMemoryTextView.setText(systemAvailableMemoryStringBuilder);
+ systemTotalMemoryTextView.setText(systemTotalMemoryStringBuilder);
+ }
+
+ // Schedule another memory update if the activity has not been destroyed.
+ if (!activity.isDestroyed()) {
+ // Create a handler to update the memory usage.
+ Handler updateMemoryUsageHandler = new Handler();
+
+ // Create a runnable to update the memory usage.
+ Runnable updateMemoryUsageRunnable = () -> updateMemoryUsage(activity);
+
+ // Update the memory usage after 1000 milliseconds
+ updateMemoryUsageHandler.postDelayed(updateMemoryUsageRunnable, 1000);
+ }
+ } catch (Exception exception) {
+ // Do nothing.
+ }
+ }
}
\ No newline at end of file