aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java
diff options
context:
space:
mode:
Diffstat (limited to 'ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java')
-rw-r--r--ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java162
1 files changed, 162 insertions, 0 deletions
diff --git a/ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java b/ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java
new file mode 100644
index 00000000..8d90fa7e
--- /dev/null
+++ b/ui/src/main/java/com/wireguard/android/fragment/TunnelDetailFragment.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.wireguard.android.fragment;
+
+import android.os.Bundle;
+import androidx.annotation.Nullable;
+import androidx.databinding.DataBindingUtil;
+
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.wireguard.android.R;
+import com.wireguard.android.databinding.TunnelDetailFragmentBinding;
+import com.wireguard.android.databinding.TunnelDetailPeerBinding;
+import com.wireguard.android.model.ObservableTunnel;
+import com.wireguard.android.backend.Tunnel.State;
+import com.wireguard.android.ui.EdgeToEdge;
+import com.wireguard.crypto.Key;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Fragment that shows details about a specific tunnel.
+ */
+
+public class TunnelDetailFragment extends BaseFragment {
+ @Nullable private TunnelDetailFragmentBinding binding;
+ @Nullable private Timer timer;
+ @Nullable private State lastState = State.TOGGLE;
+
+ @Override
+ public void onCreate(@Nullable final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
+ inflater.inflate(R.menu.tunnel_detail, menu);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (timer != null) {
+ timer.cancel();
+ timer = null;
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ timer = new Timer();
+ timer.scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ updateStats();
+ }
+ }, 0, 1000);
+ }
+
+ @Override
+ public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
+ @Nullable final Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ binding = TunnelDetailFragmentBinding.inflate(inflater, container, false);
+ binding.executePendingBindings();
+ EdgeToEdge.setUpRoot((ViewGroup) binding.getRoot());
+ EdgeToEdge.setUpScrollingContent((ViewGroup) binding.getRoot(), null);
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onDestroyView() {
+ binding = null;
+ super.onDestroyView();
+ }
+
+ @Override
+ public void onSelectedTunnelChanged(@Nullable final ObservableTunnel oldTunnel, @Nullable final ObservableTunnel newTunnel) {
+ if (binding == null)
+ return;
+ binding.setTunnel(newTunnel);
+ if (newTunnel == null)
+ binding.setConfig(null);
+ else
+ newTunnel.getConfigAsync().thenAccept(binding::setConfig);
+ lastState = State.TOGGLE;
+ updateStats();
+ }
+
+ @Override
+ public void onViewStateRestored(@Nullable final Bundle savedInstanceState) {
+ if (binding == null) {
+ return;
+ }
+
+ binding.setFragment(this);
+ onSelectedTunnelChanged(null, getSelectedTunnel());
+ super.onViewStateRestored(savedInstanceState);
+ }
+
+ private String formatBytes(final long bytes) {
+ if (bytes < 1024)
+ return requireContext().getString(R.string.transfer_bytes, bytes);
+ else if (bytes < 1024*1024)
+ return requireContext().getString(R.string.transfer_kibibytes, bytes/1024.0);
+ else if (bytes < 1024*1024*1024)
+ return requireContext().getString(R.string.transfer_mibibytes, bytes/(1024.0*1024.0));
+ else if (bytes < 1024*1024*1024*1024)
+ return requireContext().getString(R.string.transfer_gibibytes, bytes/(1024.0*1024.0*1024.0));
+ return requireContext().getString(R.string.transfer_tibibytes, bytes/(1024.0*1024.0*1024.0)/1024.0);
+ }
+
+ private void updateStats() {
+ if (binding == null || !isResumed())
+ return;
+ final ObservableTunnel tunnel = binding.getTunnel();
+ if (tunnel == null)
+ return;
+ final State state = tunnel.getState();
+ if (state != State.UP && lastState == state)
+ return;
+ lastState = state;
+ tunnel.getStatisticsAsync().whenComplete((statistics, throwable) -> {
+ if (throwable != null) {
+ for (int i = 0; i < binding.peersLayout.getChildCount(); ++i) {
+ final TunnelDetailPeerBinding peer = DataBindingUtil.getBinding(binding.peersLayout.getChildAt(i));
+ if (peer == null)
+ continue;
+ peer.transferLabel.setVisibility(View.GONE);
+ peer.transferText.setVisibility(View.GONE);
+ }
+ return;
+ }
+ for (int i = 0; i < binding.peersLayout.getChildCount(); ++i) {
+ final TunnelDetailPeerBinding peer = DataBindingUtil.getBinding(binding.peersLayout.getChildAt(i));
+ if (peer == null)
+ continue;
+ final Key publicKey = peer.getItem().getPublicKey();
+ final long rx = statistics.peerRx(publicKey);
+ final long tx = statistics.peerTx(publicKey);
+ if (rx == 0 && tx == 0) {
+ peer.transferLabel.setVisibility(View.GONE);
+ peer.transferText.setVisibility(View.GONE);
+ continue;
+ }
+ peer.transferText.setText(requireContext().getString(R.string.transfer_rx_tx, formatBytes(rx), formatBytes(tx)));
+ peer.transferLabel.setVisibility(View.VISIBLE);
+ peer.transferText.setVisibility(View.VISIBLE);
+ }
+ });
+ }
+}