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),
 | 
				
			||||||
 | 
					                        object: SettingsActivity.PermissionRequestCallback {
 | 
				
			||||||
 | 
					                            override fun done(permissions: Array<String>, grantResults: IntArray) {
 | 
				
			||||||
 | 
					                                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
 | 
				
			||||||
                                    isEnabled = false
 | 
					                                    isEnabled = false
 | 
				
			||||||
                                    exportLog()
 | 
					                                    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),
 | 
				
			||||||
 | 
					                        object : SettingsActivity.PermissionRequestCallback {
 | 
				
			||||||
 | 
					                            override fun done(permissions: Array<String>, grantResults: IntArray) {
 | 
				
			||||||
 | 
					                                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
 | 
				
			||||||
                                    isEnabled = false
 | 
					                                    isEnabled = false
 | 
				
			||||||
                                    exportZip()
 | 
					                                    exportZip()
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					                        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user