Request VPN permissions on activation
Signed-off-by: Eric Kuck <eric@bluelinelabs.com>
This commit is contained in:
parent
d50e0f5fb9
commit
d7ea078cdf
@ -25,7 +25,7 @@ import com.wireguard.android.util.ToolsInstaller;
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class Application extends android.app.Application {
|
||||
@ -37,7 +37,7 @@ public class Application extends android.app.Application {
|
||||
private ToolsInstaller toolsInstaller;
|
||||
private TunnelManager tunnelManager;
|
||||
private Handler handler;
|
||||
private List<BackendCallback> haveBackendCallbacks = new ArrayList<>();
|
||||
private Collection<BackendCallback> haveBackendCallbacks = new ArrayList<>();
|
||||
private final Object haveBackendCallbacksLock = new Object();
|
||||
|
||||
public Application() {
|
||||
|
@ -6,13 +6,11 @@
|
||||
|
||||
package com.wireguard.android.activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.databinding.CallbackRegistry;
|
||||
import android.databinding.CallbackRegistry.NotifierCallback;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.wireguard.android.Application;
|
||||
import com.wireguard.android.backend.GoBackend;
|
||||
import com.wireguard.android.model.Tunnel;
|
||||
import com.wireguard.android.model.TunnelManager;
|
||||
|
||||
@ -52,14 +50,6 @@ public abstract class BaseActivity extends ThemeChangeAwareActivity {
|
||||
|
||||
// The selected tunnel must be set before the superclass method recreates fragments.
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Application.onHaveBackend(backend -> {
|
||||
if (backend instanceof GoBackend) {
|
||||
final Intent intent = GoBackend.VpnService.prepare(this);
|
||||
if (intent != null)
|
||||
startActivityForResult(intent, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -14,7 +14,6 @@ import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.RecyclerView.Adapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.wireguard.android.BR;
|
||||
@ -78,7 +77,7 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>>
|
||||
holder.binding.executePendingBindings();
|
||||
|
||||
if (rowConfigurationHandler != null) {
|
||||
rowConfigurationHandler.onConfigureRow(holder.binding.getRoot(), getItem(position), position);
|
||||
rowConfigurationHandler.onConfigureRow(holder.binding, getItem(position), position);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,8 +148,8 @@ public class ObservableKeyedRecyclerViewAdapter<K, E extends Keyed<? extends K>>
|
||||
}
|
||||
}
|
||||
|
||||
public interface RowConfigurationHandler<T> {
|
||||
void onConfigureRow(View view, T item, int position);
|
||||
public interface RowConfigurationHandler<B extends ViewDataBinding, T> {
|
||||
void onConfigureRow(B binding, T item, int position);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,11 +7,25 @@
|
||||
package com.wireguard.android.fragment;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.databinding.DataBindingUtil;
|
||||
import android.databinding.ViewDataBinding;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.wireguard.android.Application;
|
||||
import com.wireguard.android.R;
|
||||
import com.wireguard.android.activity.BaseActivity;
|
||||
import com.wireguard.android.activity.BaseActivity.OnSelectedTunnelChangedListener;
|
||||
import com.wireguard.android.backend.GoBackend;
|
||||
import com.wireguard.android.databinding.TunnelDetailFragmentBinding;
|
||||
import com.wireguard.android.databinding.TunnelListItemBinding;
|
||||
import com.wireguard.android.model.Tunnel;
|
||||
import com.wireguard.android.model.Tunnel.State;
|
||||
import com.wireguard.android.util.ExceptionLoggers;
|
||||
|
||||
/**
|
||||
* Base class for fragments that need to know the currently-selected tunnel. Only does anything when
|
||||
@ -19,7 +33,12 @@ import com.wireguard.android.model.Tunnel;
|
||||
*/
|
||||
|
||||
public abstract class BaseFragment extends Fragment implements OnSelectedTunnelChangedListener {
|
||||
private static final String TAG = "WireGuard/" + BaseFragment.class.getSimpleName();
|
||||
private static final int REQUEST_CODE_VPN_PERMISSION = 23491;
|
||||
|
||||
private BaseActivity activity;
|
||||
private Tunnel pendingTunnel;
|
||||
private Boolean pendingTunnelUp;
|
||||
|
||||
protected Tunnel getSelectedTunnel() {
|
||||
return activity != null ? activity.getSelectedTunnel() : null;
|
||||
@ -44,8 +63,64 @@ public abstract class BaseFragment extends Fragment implements OnSelectedTunnelC
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (requestCode == REQUEST_CODE_VPN_PERMISSION) {
|
||||
if (pendingTunnel != null && pendingTunnelUp != null)
|
||||
setTunnelStateWithPermissionsResult(pendingTunnel, pendingTunnelUp);
|
||||
pendingTunnel = null;
|
||||
pendingTunnelUp = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void setSelectedTunnel(final Tunnel tunnel) {
|
||||
if (activity != null)
|
||||
activity.setSelectedTunnel(tunnel);
|
||||
}
|
||||
|
||||
public void setTunnelState(final View view, final boolean checked) {
|
||||
final ViewDataBinding binding = DataBindingUtil.findBinding(view);
|
||||
final Tunnel tunnel;
|
||||
if (binding instanceof TunnelDetailFragmentBinding)
|
||||
tunnel = ((TunnelDetailFragmentBinding) binding).getTunnel();
|
||||
else if (binding instanceof TunnelListItemBinding)
|
||||
tunnel = ((TunnelListItemBinding) binding).getItem();
|
||||
else
|
||||
return;
|
||||
|
||||
Application.onHaveBackend(backend -> {
|
||||
if (backend instanceof GoBackend) {
|
||||
final Intent intent = GoBackend.VpnService.prepare(view.getContext());
|
||||
if (intent != null) {
|
||||
pendingTunnel = tunnel;
|
||||
pendingTunnelUp = checked;
|
||||
startActivityForResult(intent, REQUEST_CODE_VPN_PERMISSION);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setTunnelStateWithPermissionsResult(tunnel, checked);
|
||||
});
|
||||
}
|
||||
|
||||
private void setTunnelStateWithPermissionsResult(@NonNull final Tunnel tunnel, final boolean checked) {
|
||||
tunnel.setState(State.of(checked)).whenComplete((state, throwable) -> {
|
||||
if (throwable == null)
|
||||
return;
|
||||
final View view = getView();
|
||||
if (view == null) {
|
||||
Log.e(TAG, "setTunnelStateWithPermissionsResult() with no view");
|
||||
return;
|
||||
}
|
||||
final Context context = view.getContext();
|
||||
final String error = ExceptionLoggers.unwrapMessage(throwable);
|
||||
final int messageResId = checked ? R.string.error_up : R.string.error_down;
|
||||
final String message = context.getString(messageResId, error);
|
||||
Snackbar.make(view, message, Snackbar.LENGTH_LONG).show();
|
||||
Log.e(TAG, message, throwable);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018 Samuel Holland <samuel@sholland.org>
|
||||
* Copyright © 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package com.wireguard.android.fragment;
|
||||
|
||||
import android.content.Context;
|
||||
import android.databinding.DataBindingUtil;
|
||||
import android.databinding.ViewDataBinding;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.wireguard.android.R;
|
||||
import com.wireguard.android.databinding.TunnelDetailFragmentBinding;
|
||||
import com.wireguard.android.databinding.TunnelListItemBinding;
|
||||
import com.wireguard.android.model.Tunnel;
|
||||
import com.wireguard.android.model.Tunnel.State;
|
||||
import com.wireguard.android.util.ExceptionLoggers;
|
||||
|
||||
/**
|
||||
* Helper method shared by TunnelListFragment and TunnelDetailFragment.
|
||||
*/
|
||||
|
||||
public final class TunnelController {
|
||||
private static final String TAG = "WireGuard/" + TunnelController.class.getSimpleName();
|
||||
|
||||
private TunnelController() {
|
||||
// Prevent instantiation.
|
||||
}
|
||||
|
||||
public static void setTunnelState(final View view, final boolean checked) {
|
||||
final ViewDataBinding binding = DataBindingUtil.findBinding(view);
|
||||
final Tunnel tunnel;
|
||||
if (binding instanceof TunnelDetailFragmentBinding)
|
||||
tunnel = ((TunnelDetailFragmentBinding) binding).getTunnel();
|
||||
else if (binding instanceof TunnelListItemBinding)
|
||||
tunnel = ((TunnelListItemBinding) binding).getItem();
|
||||
else
|
||||
tunnel = null;
|
||||
if (tunnel == null) {
|
||||
Log.e(TAG, "setChecked() from a null tunnel", new IllegalStateException("No tunnel"));
|
||||
return;
|
||||
}
|
||||
tunnel.setState(State.of(checked)).whenComplete((state, throwable) -> {
|
||||
if (throwable == null)
|
||||
return;
|
||||
final Context context = view.getContext();
|
||||
final String error = ExceptionLoggers.unwrapMessage(throwable);
|
||||
final int messageResId = checked ? R.string.error_up : R.string.error_down;
|
||||
final String message = context.getString(messageResId, error);
|
||||
Snackbar.make(view, message, Snackbar.LENGTH_LONG).show();
|
||||
Log.e(TAG, message, throwable);
|
||||
});
|
||||
}
|
||||
}
|
@ -69,7 +69,9 @@ public class TunnelDetailFragment extends BaseFragment {
|
||||
|
||||
@Override
|
||||
public void onViewStateRestored(final Bundle savedInstanceState) {
|
||||
binding.setFragment(this);
|
||||
onSelectedTunnelChanged(null, getSelectedTunnel());
|
||||
super.onViewStateRestored(savedInstanceState);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,8 +32,10 @@ import com.wireguard.android.R;
|
||||
import com.wireguard.android.activity.TunnelCreatorActivity;
|
||||
import com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter;
|
||||
import com.wireguard.android.databinding.TunnelListFragmentBinding;
|
||||
import com.wireguard.android.databinding.TunnelListItemBinding;
|
||||
import com.wireguard.android.model.Tunnel;
|
||||
import com.wireguard.android.util.ExceptionLoggers;
|
||||
import com.wireguard.android.widget.ToggleSwitch;
|
||||
import com.wireguard.config.Config;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@ -269,23 +271,21 @@ public class TunnelListFragment extends BaseFragment {
|
||||
super.onViewStateRestored(savedInstanceState);
|
||||
binding.setFragment(this);
|
||||
binding.setTunnels(Application.getTunnelManager().getTunnels());
|
||||
binding.setRowConfigurationHandler(new ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler<Tunnel>() {
|
||||
@Override
|
||||
public void onConfigureRow(View view, Tunnel tunnel, int position) {
|
||||
view.setOnClickListener(clicked -> {
|
||||
binding.setRowConfigurationHandler((ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler<TunnelListItemBinding, Tunnel>) (binding, tunnel, position) -> {
|
||||
binding.setFragment(this);
|
||||
binding.getRoot().setOnClickListener(clicked -> {
|
||||
if (actionMode == null) {
|
||||
setSelectedTunnel(tunnel);
|
||||
} else {
|
||||
actionModeListener.toggleItemChecked(position);
|
||||
}
|
||||
});
|
||||
view.setOnLongClickListener(clicked -> {
|
||||
binding.getRoot().setOnLongClickListener(clicked -> {
|
||||
actionModeListener.toggleItemChecked(position);
|
||||
return true;
|
||||
});
|
||||
|
||||
view.setActivated(actionModeListener.checkedItems.contains(position));
|
||||
}
|
||||
binding.getRoot().setActivated(actionModeListener.checkedItems.contains(position));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,14 @@
|
||||
|
||||
<data>
|
||||
|
||||
<import type="com.wireguard.android.fragment.TunnelController" />
|
||||
|
||||
<import type="com.wireguard.android.model.Tunnel.State" />
|
||||
|
||||
<import type="com.wireguard.android.util.ClipboardUtils" />
|
||||
|
||||
<variable
|
||||
name="fragment"
|
||||
type="com.wireguard.android.fragment.TunnelDetailFragment" />
|
||||
|
||||
<variable
|
||||
name="tunnel"
|
||||
type="com.wireguard.android.model.Tunnel" />
|
||||
@ -63,7 +65,7 @@
|
||||
android:layout_alignBaseline="@+id/interface_title"
|
||||
android:layout_alignParentEnd="true"
|
||||
app:checked="@{tunnel.state == State.UP}"
|
||||
app:onBeforeCheckedChanged="@{TunnelController::setTunnelState}" />
|
||||
app:onBeforeCheckedChanged="@{fragment::setTunnelState}" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/interface_name_label"
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
<data>
|
||||
|
||||
<import type="com.wireguard.android.fragment.TunnelController" />
|
||||
|
||||
<import type="com.wireguard.android.model.Tunnel" />
|
||||
|
||||
<import type="com.wireguard.android.model.Tunnel.State" />
|
||||
@ -21,6 +19,10 @@
|
||||
<variable
|
||||
name="item"
|
||||
type="com.wireguard.android.model.Tunnel" />
|
||||
|
||||
<variable
|
||||
name="fragment"
|
||||
type="com.wireguard.android.fragment.TunnelListFragment" />
|
||||
</data>
|
||||
|
||||
<RelativeLayout
|
||||
@ -49,6 +51,6 @@
|
||||
android:layout_alignBaseline="@+id/tunnel_name"
|
||||
android:layout_alignParentEnd="true"
|
||||
app:checked="@{item.state == State.UP}"
|
||||
app:onBeforeCheckedChanged="@{TunnelController::setTunnelState}" />
|
||||
app:onBeforeCheckedChanged="@{fragment::setTunnelState}" />
|
||||
</RelativeLayout>
|
||||
</layout>
|
||||
|
Loading…
Reference in New Issue
Block a user