Convert activity package to Kotlin
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
parent
85aa5fbd46
commit
04d0b819f6
@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.wireguard.android.activity;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
|
||||||
import com.wireguard.android.model.ObservableTunnel;
|
|
||||||
import com.wireguard.util.NonNullForAll;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.databinding.CallbackRegistry;
|
|
||||||
import androidx.databinding.CallbackRegistry.NotifierCallback;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for activities that need to remember the currently-selected tunnel.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@NonNullForAll
|
|
||||||
public abstract class BaseActivity extends ThemeChangeAwareActivity {
|
|
||||||
private static final String KEY_SELECTED_TUNNEL = "selected_tunnel";
|
|
||||||
|
|
||||||
private final SelectionChangeRegistry selectionChangeRegistry = new SelectionChangeRegistry();
|
|
||||||
@Nullable private ObservableTunnel selectedTunnel;
|
|
||||||
|
|
||||||
public void addOnSelectedTunnelChangedListener(final OnSelectedTunnelChangedListener listener) {
|
|
||||||
selectionChangeRegistry.add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public ObservableTunnel getSelectedTunnel() {
|
|
||||||
return selectedTunnel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
|
||||||
// Restore the saved tunnel if there is one; otherwise grab it from the arguments.
|
|
||||||
final String savedTunnelName;
|
|
||||||
if (savedInstanceState != null)
|
|
||||||
savedTunnelName = savedInstanceState.getString(KEY_SELECTED_TUNNEL);
|
|
||||||
else if (getIntent() != null)
|
|
||||||
savedTunnelName = getIntent().getStringExtra(KEY_SELECTED_TUNNEL);
|
|
||||||
else
|
|
||||||
savedTunnelName = null;
|
|
||||||
|
|
||||||
if (savedTunnelName != null)
|
|
||||||
Application.getTunnelManager().getTunnels()
|
|
||||||
.thenAccept(tunnels -> setSelectedTunnel(tunnels.get(savedTunnelName)));
|
|
||||||
|
|
||||||
// The selected tunnel must be set before the superclass method recreates fragments.
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSaveInstanceState(final Bundle outState) {
|
|
||||||
if (selectedTunnel != null)
|
|
||||||
outState.putString(KEY_SELECTED_TUNNEL, selectedTunnel.getName());
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void onSelectedTunnelChanged(@Nullable ObservableTunnel oldTunnel, @Nullable ObservableTunnel newTunnel);
|
|
||||||
|
|
||||||
public void removeOnSelectedTunnelChangedListener(
|
|
||||||
final OnSelectedTunnelChangedListener listener) {
|
|
||||||
selectionChangeRegistry.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSelectedTunnel(@Nullable final ObservableTunnel tunnel) {
|
|
||||||
final ObservableTunnel oldTunnel = selectedTunnel;
|
|
||||||
if (Objects.equals(oldTunnel, tunnel))
|
|
||||||
return;
|
|
||||||
selectedTunnel = tunnel;
|
|
||||||
onSelectedTunnelChanged(oldTunnel, tunnel);
|
|
||||||
selectionChangeRegistry.notifyCallbacks(oldTunnel, 0, tunnel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnSelectedTunnelChangedListener {
|
|
||||||
void onSelectedTunnelChanged(@Nullable ObservableTunnel oldTunnel, @Nullable ObservableTunnel newTunnel);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class SelectionChangeNotifier
|
|
||||||
extends NotifierCallback<OnSelectedTunnelChangedListener, ObservableTunnel, ObservableTunnel> {
|
|
||||||
@Override
|
|
||||||
public void onNotifyCallback(final OnSelectedTunnelChangedListener listener,
|
|
||||||
final ObservableTunnel oldTunnel, final int ignored,
|
|
||||||
final ObservableTunnel newTunnel) {
|
|
||||||
listener.onSelectedTunnelChanged(oldTunnel, newTunnel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class SelectionChangeRegistry
|
|
||||||
extends CallbackRegistry<OnSelectedTunnelChangedListener, ObservableTunnel, ObservableTunnel> {
|
|
||||||
private SelectionChangeRegistry() {
|
|
||||||
super(new SelectionChangeNotifier());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
package com.wireguard.android.activity
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.databinding.CallbackRegistry
|
||||||
|
import androidx.databinding.CallbackRegistry.NotifierCallback
|
||||||
|
import com.wireguard.android.Application
|
||||||
|
import com.wireguard.android.model.ObservableTunnel
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for activities that need to remember the currently-selected tunnel.
|
||||||
|
*/
|
||||||
|
abstract class BaseActivity : ThemeChangeAwareActivity() {
|
||||||
|
private val selectionChangeRegistry = SelectionChangeRegistry()
|
||||||
|
var selectedTunnel: ObservableTunnel? = null
|
||||||
|
set(value) {
|
||||||
|
val oldTunnel = field
|
||||||
|
if (oldTunnel == value) return
|
||||||
|
field = value
|
||||||
|
onSelectedTunnelChanged(oldTunnel, value)
|
||||||
|
selectionChangeRegistry.notifyCallbacks(oldTunnel, 0, value)
|
||||||
|
}
|
||||||
|
fun addOnSelectedTunnelChangedListener(listener: OnSelectedTunnelChangedListener) {
|
||||||
|
selectionChangeRegistry.add(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
// Restore the saved tunnel if there is one; otherwise grab it from the arguments.
|
||||||
|
val savedTunnelName = when {
|
||||||
|
savedInstanceState != null -> savedInstanceState.getString(KEY_SELECTED_TUNNEL)
|
||||||
|
intent != null -> intent.getStringExtra(KEY_SELECTED_TUNNEL)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
if (savedTunnelName != null) {
|
||||||
|
Application.getTunnelManager()
|
||||||
|
.tunnels
|
||||||
|
.thenAccept { selectedTunnel = it[savedTunnelName] }
|
||||||
|
}
|
||||||
|
|
||||||
|
// The selected tunnel must be set before the superclass method recreates fragments.
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
if (selectedTunnel != null) outState.putString(KEY_SELECTED_TUNNEL, selectedTunnel!!.name)
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?, newTunnel: ObservableTunnel?)
|
||||||
|
fun removeOnSelectedTunnelChangedListener(
|
||||||
|
listener: OnSelectedTunnelChangedListener) {
|
||||||
|
selectionChangeRegistry.remove(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnSelectedTunnelChangedListener {
|
||||||
|
fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?, newTunnel: ObservableTunnel?)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SelectionChangeNotifier : NotifierCallback<OnSelectedTunnelChangedListener, ObservableTunnel, ObservableTunnel>() {
|
||||||
|
override fun onNotifyCallback(
|
||||||
|
listener: OnSelectedTunnelChangedListener,
|
||||||
|
oldTunnel: ObservableTunnel?,
|
||||||
|
ignored: Int,
|
||||||
|
newTunnel: ObservableTunnel?
|
||||||
|
) {
|
||||||
|
listener.onSelectedTunnelChanged(oldTunnel, newTunnel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SelectionChangeRegistry :
|
||||||
|
CallbackRegistry<OnSelectedTunnelChangedListener, ObservableTunnel, ObservableTunnel>(SelectionChangeNotifier())
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val KEY_SELECTED_TUNNEL = "selected_tunnel"
|
||||||
|
}
|
||||||
|
}
|
@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.wireguard.android.activity;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
|
|
||||||
import com.wireguard.android.R;
|
|
||||||
import com.wireguard.android.fragment.TunnelDetailFragment;
|
|
||||||
import com.wireguard.android.fragment.TunnelEditorFragment;
|
|
||||||
import com.wireguard.android.model.ObservableTunnel;
|
|
||||||
import com.wireguard.util.NonNullForAll;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.app.ActionBar;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.fragment.app.FragmentManager;
|
|
||||||
import androidx.fragment.app.FragmentTransaction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CRUD interface for WireGuard tunnels. This activity serves as the main entry point to the
|
|
||||||
* WireGuard application, and contains several fragments for listing, viewing details of, and
|
|
||||||
* editing the configuration and interface state of WireGuard tunnels.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@NonNullForAll
|
|
||||||
public class MainActivity extends BaseActivity
|
|
||||||
implements FragmentManager.OnBackStackChangedListener {
|
|
||||||
@Nullable private ActionBar actionBar;
|
|
||||||
private boolean isTwoPaneLayout;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
final int backStackEntries = getSupportFragmentManager().getBackStackEntryCount();
|
|
||||||
// If the two-pane layout does not have an editor open, going back should exit the app.
|
|
||||||
if (isTwoPaneLayout && backStackEntries <= 1) {
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Deselect the current tunnel on navigating back from the detail pane to the one-pane list.
|
|
||||||
if (!isTwoPaneLayout && backStackEntries == 1) {
|
|
||||||
getSupportFragmentManager().popBackStack();
|
|
||||||
setSelectedTunnel(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.onBackPressed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void onBackStackChanged() {
|
|
||||||
if (actionBar == null)
|
|
||||||
return;
|
|
||||||
// Do not show the home menu when the two-pane layout is at the detail view (see above).
|
|
||||||
final int backStackEntries = getSupportFragmentManager().getBackStackEntryCount();
|
|
||||||
final int minBackStackEntries = isTwoPaneLayout ? 2 : 1;
|
|
||||||
actionBar.setDisplayHomeAsUpEnabled(backStackEntries >= minBackStackEntries);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use onTouchListener here to avoid the UI click sound, hence
|
|
||||||
// calling View#performClick defeats the purpose of it.
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
@Override
|
|
||||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.main_activity);
|
|
||||||
actionBar = getSupportActionBar();
|
|
||||||
isTwoPaneLayout = findViewById(R.id.master_detail_wrapper) instanceof LinearLayout;
|
|
||||||
getSupportFragmentManager().addOnBackStackChangedListener(this);
|
|
||||||
onBackStackChanged();
|
|
||||||
// Dispatch insets on back stack change
|
|
||||||
// This is required to ensure replaced fragments are also able to consume insets
|
|
||||||
findViewById(R.id.master_detail_wrapper).setOnApplyWindowInsetsListener((v, insets) -> {
|
|
||||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
|
||||||
fragmentManager.addOnBackStackChangedListener(() -> {
|
|
||||||
final List<Fragment> fragments = fragmentManager.getFragments();
|
|
||||||
for (int i = 0; i < fragments.size(); i++) {
|
|
||||||
fragments.get(i).requireView().dispatchApplyWindowInsets(insets);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return insets;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
|
||||||
getMenuInflater().inflate(R.menu.main_activity, menu);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("UnnecessaryFullyQualifiedName")
|
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
|
||||||
switch (item.getItemId()) {
|
|
||||||
case android.R.id.home:
|
|
||||||
// The back arrow in the action bar should act the same as the back button.
|
|
||||||
onBackPressed();
|
|
||||||
return true;
|
|
||||||
case R.id.menu_action_edit:
|
|
||||||
getSupportFragmentManager().beginTransaction()
|
|
||||||
.replace(R.id.detail_container, new TunnelEditorFragment())
|
|
||||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
|
||||||
.addToBackStack(null)
|
|
||||||
.commit();
|
|
||||||
return true;
|
|
||||||
case R.id.menu_action_save:
|
|
||||||
// This menu item is handled by the editor fragment.
|
|
||||||
return false;
|
|
||||||
case R.id.menu_settings:
|
|
||||||
startActivity(new Intent(this, SettingsActivity.class));
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSelectedTunnelChanged(@Nullable final ObservableTunnel oldTunnel,
|
|
||||||
@Nullable final ObservableTunnel newTunnel) {
|
|
||||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
|
||||||
final int backStackEntries = fragmentManager.getBackStackEntryCount();
|
|
||||||
if (newTunnel == null) {
|
|
||||||
// Clear everything off the back stack (all editors and detail fragments).
|
|
||||||
fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (backStackEntries == 2) {
|
|
||||||
// Pop the editor off the back stack to reveal the detail fragment. Use the immediate
|
|
||||||
// method to avoid the editor picking up the new tunnel while it is still visible.
|
|
||||||
fragmentManager.popBackStackImmediate();
|
|
||||||
} else if (backStackEntries == 0) {
|
|
||||||
// Create and show a new detail fragment.
|
|
||||||
fragmentManager.beginTransaction()
|
|
||||||
.add(R.id.detail_container, new TunnelDetailFragment())
|
|
||||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
|
||||||
.addToBackStack(null)
|
|
||||||
.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
126
ui/src/main/java/com/wireguard/android/activity/MainActivity.kt
Normal file
126
ui/src/main/java/com/wireguard/android/activity/MainActivity.kt
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
package com.wireguard.android.activity
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.appcompat.app.ActionBar
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.fragment.app.FragmentTransaction
|
||||||
|
import com.wireguard.android.R
|
||||||
|
import com.wireguard.android.fragment.TunnelDetailFragment
|
||||||
|
import com.wireguard.android.fragment.TunnelEditorFragment
|
||||||
|
import com.wireguard.android.model.ObservableTunnel
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CRUD interface for WireGuard tunnels. This activity serves as the main entry point to the
|
||||||
|
* WireGuard application, and contains several fragments for listing, viewing details of, and
|
||||||
|
* editing the configuration and interface state of WireGuard tunnels.
|
||||||
|
*/
|
||||||
|
class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener {
|
||||||
|
private var actionBar: ActionBar? = null
|
||||||
|
private var isTwoPaneLayout = false
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
val backStackEntries = supportFragmentManager.backStackEntryCount
|
||||||
|
// If the two-pane layout does not have an editor open, going back should exit the app.
|
||||||
|
if (isTwoPaneLayout && backStackEntries <= 1) {
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Deselect the current tunnel on navigating back from the detail pane to the one-pane list.
|
||||||
|
if (!isTwoPaneLayout && backStackEntries == 1) {
|
||||||
|
supportFragmentManager.popBackStack()
|
||||||
|
selectedTunnel = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
super.onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackStackChanged() {
|
||||||
|
if (actionBar == null) return
|
||||||
|
// Do not show the home menu when the two-pane layout is at the detail view (see above).
|
||||||
|
val backStackEntries = supportFragmentManager.backStackEntryCount
|
||||||
|
val minBackStackEntries = if (isTwoPaneLayout) 2 else 1
|
||||||
|
actionBar!!.setDisplayHomeAsUpEnabled(backStackEntries >= minBackStackEntries)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.main_activity)
|
||||||
|
actionBar = supportActionBar
|
||||||
|
isTwoPaneLayout = findViewById<View>(R.id.master_detail_wrapper) is LinearLayout
|
||||||
|
supportFragmentManager.addOnBackStackChangedListener(this)
|
||||||
|
onBackStackChanged()
|
||||||
|
// Dispatch insets on back stack change
|
||||||
|
// This is required to ensure replaced fragments are also able to consume insets
|
||||||
|
findViewById<View>(R.id.master_detail_wrapper).setOnApplyWindowInsetsListener { _, insets ->
|
||||||
|
val fragmentManager = supportFragmentManager
|
||||||
|
fragmentManager.addOnBackStackChangedListener {
|
||||||
|
fragmentManager.fragments.forEach {
|
||||||
|
it.requireView().dispatchApplyWindowInsets(insets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
insets
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
menuInflater.inflate(R.menu.main_activity, menu)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
return when (item.itemId) {
|
||||||
|
android.R.id.home -> {
|
||||||
|
// The back arrow in the action bar should act the same as the back button.
|
||||||
|
onBackPressed()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.menu_action_edit -> {
|
||||||
|
supportFragmentManager.beginTransaction()
|
||||||
|
.replace(R.id.detail_container, TunnelEditorFragment())
|
||||||
|
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||||
|
.addToBackStack(null)
|
||||||
|
.commit()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
// This menu item is handled by the editor fragment.
|
||||||
|
R.id.menu_action_save -> false
|
||||||
|
R.id.menu_settings -> {
|
||||||
|
startActivity(Intent(this, SettingsActivity::class.java))
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?,
|
||||||
|
newTunnel: ObservableTunnel?) {
|
||||||
|
val fragmentManager = supportFragmentManager
|
||||||
|
val backStackEntries = fragmentManager.backStackEntryCount
|
||||||
|
if (newTunnel == null) {
|
||||||
|
// Clear everything off the back stack (all editors and detail fragments).
|
||||||
|
fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (backStackEntries == 2) {
|
||||||
|
// Pop the editor off the back stack to reveal the detail fragment. Use the immediate
|
||||||
|
// method to avoid the editor picking up the new tunnel while it is still visible.
|
||||||
|
fragmentManager.popBackStackImmediate()
|
||||||
|
} else if (backStackEntries == 0) {
|
||||||
|
// Create and show a new detail fragment.
|
||||||
|
fragmentManager.beginTransaction()
|
||||||
|
.add(R.id.detail_container, TunnelDetailFragment())
|
||||||
|
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||||
|
.addToBackStack(null)
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.wireguard.android.activity;
|
|
||||||
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.SparseArray;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
|
||||||
import com.wireguard.android.R;
|
|
||||||
import com.wireguard.android.backend.WgQuickBackend;
|
|
||||||
import com.wireguard.android.util.ModuleLoader;
|
|
||||||
import com.wireguard.util.NonNullForAll;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.core.app.ActivityCompat;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.preference.Preference;
|
|
||||||
import androidx.preference.PreferenceFragmentCompat;
|
|
||||||
import androidx.preference.PreferenceScreen;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for changing application-global persistent settings.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@NonNullForAll
|
|
||||||
public class SettingsActivity extends ThemeChangeAwareActivity {
|
|
||||||
private final SparseArray<PermissionRequestCallback> permissionRequestCallbacks = new SparseArray<>();
|
|
||||||
private int permissionRequestCounter;
|
|
||||||
|
|
||||||
public void ensurePermissions(final String[] permissions, final PermissionRequestCallback cb) {
|
|
||||||
final List<String> needPermissions = new ArrayList<>(permissions.length);
|
|
||||||
for (final String permission : permissions) {
|
|
||||||
if (ContextCompat.checkSelfPermission(this, permission)
|
|
||||||
!= PackageManager.PERMISSION_GRANTED)
|
|
||||||
needPermissions.add(permission);
|
|
||||||
}
|
|
||||||
if (needPermissions.isEmpty()) {
|
|
||||||
final int[] granted = new int[permissions.length];
|
|
||||||
Arrays.fill(granted, PackageManager.PERMISSION_GRANTED);
|
|
||||||
cb.done(permissions, granted);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final int idx = permissionRequestCounter++;
|
|
||||||
permissionRequestCallbacks.put(idx, cb);
|
|
||||||
ActivityCompat.requestPermissions(this,
|
|
||||||
needPermissions.toArray(new String[needPermissions.size()]), idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
|
|
||||||
getSupportFragmentManager().beginTransaction()
|
|
||||||
.add(android.R.id.content, new SettingsFragment())
|
|
||||||
.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("UnnecessaryFullyQualifiedName")
|
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
|
||||||
if (item.getItemId() == android.R.id.home) {
|
|
||||||
finish();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(final int requestCode,
|
|
||||||
final String[] permissions,
|
|
||||||
final int[] grantResults) {
|
|
||||||
final PermissionRequestCallback f = permissionRequestCallbacks.get(requestCode);
|
|
||||||
if (f != null) {
|
|
||||||
permissionRequestCallbacks.remove(requestCode);
|
|
||||||
f.done(permissions, grantResults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface PermissionRequestCallback {
|
|
||||||
void done(String[] permissions, int[] grantResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SettingsFragment extends PreferenceFragmentCompat {
|
|
||||||
@Override
|
|
||||||
public void onCreatePreferences(final Bundle savedInstanceState, final String key) {
|
|
||||||
addPreferencesFromResource(R.xml.preferences);
|
|
||||||
final PreferenceScreen screen = getPreferenceScreen();
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
|
||||||
screen.removePreference(getPreferenceManager().findPreference("dark_theme"));
|
|
||||||
|
|
||||||
final Preference[] wgQuickOnlyPrefs = {
|
|
||||||
getPreferenceManager().findPreference("tools_installer"),
|
|
||||||
getPreferenceManager().findPreference("restore_on_boot"),
|
|
||||||
getPreferenceManager().findPreference("multiple_tunnels")
|
|
||||||
};
|
|
||||||
for (final Preference pref : wgQuickOnlyPrefs)
|
|
||||||
pref.setVisible(false);
|
|
||||||
Application.getBackendAsync().thenAccept(backend -> {
|
|
||||||
for (final Preference pref : wgQuickOnlyPrefs) {
|
|
||||||
if (backend instanceof WgQuickBackend)
|
|
||||||
pref.setVisible(true);
|
|
||||||
else
|
|
||||||
screen.removePreference(pref);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final Preference moduleInstaller = getPreferenceManager().findPreference("module_downloader");
|
|
||||||
final Preference kernelModuleDisabler = getPreferenceManager().findPreference("kernel_module_disabler");
|
|
||||||
moduleInstaller.setVisible(false);
|
|
||||||
if (ModuleLoader.isModuleLoaded()) {
|
|
||||||
screen.removePreference(moduleInstaller);
|
|
||||||
} else {
|
|
||||||
screen.removePreference(kernelModuleDisabler);
|
|
||||||
Application.getAsyncWorker().runAsync(Application.getRootShell()::start).whenComplete((v, e) -> {
|
|
||||||
if (e == null)
|
|
||||||
moduleInstaller.setVisible(true);
|
|
||||||
else
|
|
||||||
screen.removePreference(moduleInstaller);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
package com.wireguard.android.activity
|
||||||
|
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.SparseArray
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import com.wireguard.android.Application
|
||||||
|
import com.wireguard.android.R
|
||||||
|
import com.wireguard.android.backend.Backend
|
||||||
|
import com.wireguard.android.backend.WgQuickBackend
|
||||||
|
import com.wireguard.android.util.ModuleLoader
|
||||||
|
import java.util.ArrayList
|
||||||
|
import java.util.Arrays
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for changing application-global persistent settings.
|
||||||
|
*/
|
||||||
|
class SettingsActivity : ThemeChangeAwareActivity() {
|
||||||
|
private val permissionRequestCallbacks = SparseArray<PermissionRequestCallback>()
|
||||||
|
private var permissionRequestCounter = 0
|
||||||
|
|
||||||
|
fun ensurePermissions(permissions: Array<String>, cb: PermissionRequestCallback) {
|
||||||
|
val needPermissions: MutableList<String> = ArrayList(permissions.size)
|
||||||
|
permissions.forEach {
|
||||||
|
if (ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
needPermissions.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needPermissions.isEmpty()) {
|
||||||
|
val granted = IntArray(permissions.size)
|
||||||
|
Arrays.fill(granted, PackageManager.PERMISSION_GRANTED)
|
||||||
|
cb.done(permissions, granted)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val idx = permissionRequestCounter++
|
||||||
|
permissionRequestCallbacks.put(idx, cb)
|
||||||
|
ActivityCompat.requestPermissions(this,
|
||||||
|
needPermissions.toTypedArray(), idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
if (supportFragmentManager.findFragmentById(android.R.id.content) == null) {
|
||||||
|
supportFragmentManager.beginTransaction()
|
||||||
|
.add(android.R.id.content, SettingsFragment())
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (item.itemId == android.R.id.home) {
|
||||||
|
finish()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(requestCode: Int,
|
||||||
|
permissions: Array<String>,
|
||||||
|
grantResults: IntArray) {
|
||||||
|
val f = permissionRequestCallbacks[requestCode]
|
||||||
|
if (f != null) {
|
||||||
|
permissionRequestCallbacks.remove(requestCode)
|
||||||
|
f.done(permissions, grantResults)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PermissionRequestCallback {
|
||||||
|
fun done(permissions: Array<String>, grantResults: IntArray)
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, key: String?) {
|
||||||
|
addPreferencesFromResource(R.xml.preferences)
|
||||||
|
val screen = preferenceScreen
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) screen.removePreference(preferenceManager.findPreference("dark_theme"))
|
||||||
|
val wgQuickOnlyPrefs = arrayOf(
|
||||||
|
preferenceManager.findPreference("tools_installer"),
|
||||||
|
preferenceManager.findPreference("restore_on_boot"),
|
||||||
|
preferenceManager.findPreference<Preference>("multiple_tunnels")
|
||||||
|
).filterNotNull()
|
||||||
|
wgQuickOnlyPrefs.forEach { it.isVisible = false }
|
||||||
|
Application.getBackendAsync().thenAccept { backend ->
|
||||||
|
if (backend is WgQuickBackend) {
|
||||||
|
wgQuickOnlyPrefs.forEach { it.isVisible = true }
|
||||||
|
} else {
|
||||||
|
wgQuickOnlyPrefs.forEach { screen.removePreference(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val moduleInstaller = preferenceManager.findPreference<Preference>("module_downloader")
|
||||||
|
val kernelModuleDisabler = preferenceManager.findPreference<Preference>("kernel_module_disabler")
|
||||||
|
moduleInstaller?.isVisible = false
|
||||||
|
if (ModuleLoader.isModuleLoaded()) {
|
||||||
|
screen.removePreference(moduleInstaller)
|
||||||
|
} else {
|
||||||
|
screen.removePreference(kernelModuleDisabler)
|
||||||
|
Application.getAsyncWorker().runAsync(Application.getRootShell()::start).whenComplete { _, e ->
|
||||||
|
if (e == null)
|
||||||
|
moduleInstaller?.isVisible = true
|
||||||
|
else
|
||||||
|
screen.removePreference(moduleInstaller)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.wireguard.android.activity;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
|
||||||
import com.wireguard.util.NonNullForAll;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate;
|
|
||||||
|
|
||||||
@NonNullForAll
|
|
||||||
public abstract class ThemeChangeAwareActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
|
|
||||||
private static final String TAG = "WireGuard/" + ThemeChangeAwareActivity.class.getSimpleName();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
|
|
||||||
Application.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDestroy() {
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
|
|
||||||
Application.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
|
|
||||||
if ("dark_theme".equals(key)) {
|
|
||||||
AppCompatDelegate.setDefaultNightMode(
|
|
||||||
sharedPreferences.getBoolean(key, false) ?
|
|
||||||
AppCompatDelegate.MODE_NIGHT_YES :
|
|
||||||
AppCompatDelegate.MODE_NIGHT_NO);
|
|
||||||
recreate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
package com.wireguard.android.activity
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import com.wireguard.android.Application
|
||||||
|
|
||||||
|
abstract class ThemeChangeAwareActivity : AppCompatActivity(), OnSharedPreferenceChangeListener {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||||
|
Application.getSharedPreferences().registerOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||||
|
Application.getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this)
|
||||||
|
}
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||||
|
when (key) {
|
||||||
|
"dark_theme" -> {
|
||||||
|
AppCompatDelegate.setDefaultNightMode(if (sharedPreferences.getBoolean(key, false)) {
|
||||||
|
AppCompatDelegate.MODE_NIGHT_YES
|
||||||
|
} else {
|
||||||
|
AppCompatDelegate.MODE_NIGHT_NO
|
||||||
|
})
|
||||||
|
recreate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.wireguard.android.activity;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import com.wireguard.android.fragment.TunnelEditorFragment;
|
|
||||||
import com.wireguard.android.model.ObservableTunnel;
|
|
||||||
import com.wireguard.util.NonNullForAll;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Standalone activity for creating tunnels.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@NonNullForAll
|
|
||||||
public class TunnelCreatorActivity extends BaseActivity {
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("UnnecessaryFullyQualifiedName")
|
|
||||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
|
|
||||||
getSupportFragmentManager().beginTransaction()
|
|
||||||
.add(android.R.id.content, new TunnelEditorFragment())
|
|
||||||
.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSelectedTunnelChanged(@Nullable final ObservableTunnel oldTunnel, @Nullable final ObservableTunnel newTunnel) {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
package com.wireguard.android.activity
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.wireguard.android.fragment.TunnelEditorFragment
|
||||||
|
import com.wireguard.android.model.ObservableTunnel
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standalone activity for creating tunnels.
|
||||||
|
*/
|
||||||
|
class TunnelCreatorActivity : BaseActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
if (supportFragmentManager.findFragmentById(android.R.id.content) == null) {
|
||||||
|
supportFragmentManager.beginTransaction()
|
||||||
|
.add(android.R.id.content, TunnelEditorFragment())
|
||||||
|
.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?, newTunnel: ObservableTunnel?) {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.wireguard.android.activity;
|
|
||||||
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.service.quicksettings.TileService;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.wireguard.android.Application;
|
|
||||||
import com.wireguard.android.QuickTileService;
|
|
||||||
import com.wireguard.android.R;
|
|
||||||
import com.wireguard.android.backend.Tunnel.State;
|
|
||||||
import com.wireguard.android.model.ObservableTunnel;
|
|
||||||
import com.wireguard.android.util.ErrorMessages;
|
|
||||||
import com.wireguard.util.NonNullForAll;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.N)
|
|
||||||
@NonNullForAll
|
|
||||||
public class TunnelToggleActivity extends AppCompatActivity {
|
|
||||||
private static final String TAG = "WireGuard/" + TunnelToggleActivity.class.getSimpleName();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
final ObservableTunnel tunnel = Application.getTunnelManager().getLastUsedTunnel();
|
|
||||||
if (tunnel == null)
|
|
||||||
return;
|
|
||||||
tunnel.setState(State.TOGGLE).whenComplete((v, t) -> {
|
|
||||||
TileService.requestListeningState(this, new ComponentName(this, QuickTileService.class));
|
|
||||||
onToggleFinished(t);
|
|
||||||
finishAffinity();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onToggleFinished(@Nullable final Throwable throwable) {
|
|
||||||
if (throwable == null)
|
|
||||||
return;
|
|
||||||
final String error = ErrorMessages.get(throwable);
|
|
||||||
final String message = getString(R.string.toggle_error, error);
|
|
||||||
Log.e(TAG, message, throwable);
|
|
||||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
package com.wireguard.android.activity
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.service.quicksettings.TileService
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.wireguard.android.Application
|
||||||
|
import com.wireguard.android.QuickTileService
|
||||||
|
import com.wireguard.android.R
|
||||||
|
import com.wireguard.android.backend.Tunnel
|
||||||
|
import com.wireguard.android.util.ErrorMessages
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
|
class TunnelToggleActivity : AppCompatActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
val tunnel = Application.getTunnelManager().lastUsedTunnel ?: return
|
||||||
|
tunnel.setState(Tunnel.State.TOGGLE).whenComplete { _, t ->
|
||||||
|
TileService.requestListeningState(this, ComponentName(this, QuickTileService::class.java))
|
||||||
|
onToggleFinished(t)
|
||||||
|
finishAffinity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onToggleFinished(throwable: Throwable?) {
|
||||||
|
if (throwable == null) return
|
||||||
|
val error = ErrorMessages.get(throwable)
|
||||||
|
val message = getString(R.string.toggle_error, error)
|
||||||
|
Log.e(TAG, message, throwable)
|
||||||
|
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = "WireGuard/" + TunnelToggleActivity::class.java.simpleName
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ import androidx.preference.Preference
|
|||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.wireguard.android.Application
|
import com.wireguard.android.Application
|
||||||
import com.wireguard.android.R
|
import com.wireguard.android.R
|
||||||
|
import com.wireguard.android.activity.SettingsActivity
|
||||||
import com.wireguard.android.util.DownloadsFileSaver
|
import com.wireguard.android.util.DownloadsFileSaver
|
||||||
import com.wireguard.android.util.ErrorMessages
|
import com.wireguard.android.util.ErrorMessages
|
||||||
import com.wireguard.android.util.FragmentUtils
|
import com.wireguard.android.util.FragmentUtils
|
||||||
@ -80,12 +81,16 @@ class LogExporterPreference(context: Context, attrs: AttributeSet?) : Preference
|
|||||||
override fun getTitle() = context.getString(R.string.log_export_title)
|
override fun getTitle() = context.getString(R.string.log_export_title)
|
||||||
|
|
||||||
override fun onClick() {
|
override fun onClick() {
|
||||||
FragmentUtils.getPrefActivity(this).ensurePermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { _, granted ->
|
FragmentUtils.getPrefActivity(this)
|
||||||
if (granted.isNotEmpty() && granted[0] == PackageManager.PERMISSION_GRANTED) {
|
.ensurePermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
|
||||||
isEnabled = false
|
object: SettingsActivity.PermissionRequestCallback {
|
||||||
exportLog()
|
override fun done(permissions: Array<String>, grantResults: IntArray) {
|
||||||
}
|
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
}
|
isEnabled = false
|
||||||
|
exportLog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -13,6 +13,7 @@ import androidx.preference.Preference
|
|||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.wireguard.android.Application
|
import com.wireguard.android.Application
|
||||||
import com.wireguard.android.R
|
import com.wireguard.android.R
|
||||||
|
import com.wireguard.android.activity.SettingsActivity
|
||||||
import com.wireguard.android.model.ObservableTunnel
|
import com.wireguard.android.model.ObservableTunnel
|
||||||
import com.wireguard.android.util.DownloadsFileSaver
|
import com.wireguard.android.util.DownloadsFileSaver
|
||||||
import com.wireguard.android.util.ErrorMessages
|
import com.wireguard.android.util.ErrorMessages
|
||||||
@ -84,12 +85,16 @@ class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference
|
|||||||
override fun getTitle() = context.getString(R.string.zip_export_title)
|
override fun getTitle() = context.getString(R.string.zip_export_title)
|
||||||
|
|
||||||
override fun onClick() {
|
override fun onClick() {
|
||||||
FragmentUtils.getPrefActivity(this).ensurePermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { _, granted ->
|
FragmentUtils.getPrefActivity(this)
|
||||||
if (granted.isNotEmpty() && granted[0] == PackageManager.PERMISSION_GRANTED) {
|
.ensurePermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
|
||||||
isEnabled = false
|
object : SettingsActivity.PermissionRequestCallback {
|
||||||
exportZip()
|
override fun done(permissions: Array<String>, grantResults: IntArray) {
|
||||||
}
|
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
}
|
isEnabled = false
|
||||||
|
exportZip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
Loading…
Reference in New Issue
Block a user