diff options
Diffstat (limited to 'main/src/ui')
38 files changed, 776 insertions, 604 deletions
diff --git a/main/src/ui/java/de/blinkt/openvpn/OpenVPNTileService.java b/main/src/ui/java/de/blinkt/openvpn/OpenVPNTileService.java index 94c1f1db..09593047 100644 --- a/main/src/ui/java/de/blinkt/openvpn/OpenVPNTileService.java +++ b/main/src/ui/java/de/blinkt/openvpn/OpenVPNTileService.java @@ -85,7 +85,7 @@ public class OpenVPNTileService extends TileService implements VpnStatus.StateLi @SuppressLint("Override") @TargetApi(Build.VERSION_CODES.N) void launchVPN(VpnProfile profile, Context context) { - VPNLaunchHelper.startOpenVpn(profile, getBaseContext(), "QuickTile"); + VPNLaunchHelper.startOpenVpn(profile, getBaseContext(), "QuickTile", true); } @TargetApi(Build.VERSION_CODES.N) diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.java b/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.java deleted file mode 100644 index cca8b155..00000000 --- a/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2012-2015 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.activities; - -import android.app.UiModeManager; -import android.content.Context; -import android.content.res.Configuration; -import android.os.Bundle; -import android.view.Window; - -import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; - -import de.blinkt.openvpn.core.LocaleHelper; - -public abstract class BaseActivity extends AppCompatActivity { - boolean isAndroidTV() { - final UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE); - if (uiModeManager == null) - return false; - return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - if (isAndroidTV()) { - requestWindowFeature(Window.FEATURE_OPTIONS_PANEL); - } - super.onCreate(savedInstanceState); - } - - @Override - protected void attachBaseContext(Context base) { - super.attachBaseContext(LocaleHelper.updateResources(base)); - } - - @Override - public void onConfigurationChanged(@NonNull Configuration newConfig) { - super.onConfigurationChanged(newConfig); - LocaleHelper.onConfigurationChange(this); - } -} diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.kt b/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.kt new file mode 100644 index 00000000..9e6dd462 --- /dev/null +++ b/main/src/ui/java/de/blinkt/openvpn/activities/BaseActivity.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012-2015 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ +package de.blinkt.openvpn.activities + +import android.app.UiModeManager +import android.content.Context +import android.content.res.Configuration +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.view.Window +import androidx.activity.SystemBarStyle +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updateLayoutParams +import androidx.core.view.updatePadding +import de.blinkt.openvpn.R +import de.blinkt.openvpn.core.LocaleHelper + +abstract class BaseActivity : AppCompatActivity() { + val isAndroidTV: Boolean + get() { + val uiModeManager = getSystemService(UI_MODE_SERVICE) as UiModeManager + return uiModeManager.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION + } + + override fun onCreate(savedInstanceState: Bundle?) { + if (isAndroidTV) { + requestWindowFeature(Window.FEATURE_OPTIONS_PANEL) + } + this.enableEdgeToEdge(SystemBarStyle.dark(R.color.primary_dark)) + super.onCreate(savedInstanceState) + } + + fun setUpEdgeEdgeInsetsListener( + rootView: View, + contentViewId: Int = R.id.root_linear_layout, + setupBottom: Boolean = true + ) { + val contentView = rootView.findViewById<View>(contentViewId) + + ViewCompat.setOnApplyWindowInsetsListener(contentView) { v, windowInsets -> + val insets = + windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()) + val statusbarbg = findViewById<View>(R.id.statusbar_background); + + val statusBarInsets = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars()) + + statusbarbg.layoutParams.height = statusBarInsets.top + + + v.updateLayoutParams<ViewGroup.MarginLayoutParams> { + topMargin = insets.top + } + + v.updatePadding( + left = insets.left, + right = insets.right, + ) + if (setupBottom) { + v.updatePadding(bottom = insets.bottom) + WindowInsetsCompat.CONSUMED + } else { + windowInsets + } + } + } + + override fun attachBaseContext(base: Context) { + super.attachBaseContext(LocaleHelper.updateResources(base)) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + LocaleHelper.onConfigurationChange(this) + } +} diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/ConfigConverter.kt b/main/src/ui/java/de/blinkt/openvpn/activities/ConfigConverter.kt index b85eaa26..a80afcab 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/ConfigConverter.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/ConfigConverter.kt @@ -618,7 +618,9 @@ class ConfigConverter : BaseActivity(), FileSelectCallback, View.OnClickListener override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.config_converter) + val v = layoutInflater.inflate(R.layout.config_converter, null) + setUpEdgeEdgeInsetsListener(v, R.id.root_layout_config_converter) + setContentView(v) val fab_button = findViewById<ImageButton?>(R.id.fab_save) if (fab_button != null) { diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/CreateShortcuts.java b/main/src/ui/java/de/blinkt/openvpn/activities/CreateShortcuts.java index 82455895..3b9312e5 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/CreateShortcuts.java +++ b/main/src/ui/java/de/blinkt/openvpn/activities/CreateShortcuts.java @@ -5,6 +5,8 @@ package de.blinkt.openvpn.activities; +import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_START_REASON; + import android.app.ListActivity; import android.content.Intent; import android.os.Bundle; @@ -126,7 +128,7 @@ public class CreateShortcuts extends ListActivity implements OnItemClickListener Intent shortcutIntent = new Intent(Intent.ACTION_MAIN); shortcutIntent.setClass(this, LaunchVPN.class); shortcutIntent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString()); - shortcutIntent.putExtra(LaunchVPN.EXTRA_START_REASON, "shortcut"); + shortcutIntent.putExtra(EXTRA_START_REASON, "shortcut"); // Then, set up the container intent (the response to the caller) diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt b/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt index 1a16829e..fec69768 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/InternalWebView.kt @@ -22,7 +22,7 @@ import de.blinkt.openvpn.R import de.blinkt.openvpn.VpnProfile import org.json.JSONObject -class InternalWebView : AppCompatActivity() { +class InternalWebView : BaseActivity() { lateinit var webView: WebView lateinit var urlTextView: TextView @@ -32,6 +32,8 @@ class InternalWebView : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.webview_internal) + setUpEdgeEdgeInsetsListener(getWindow().getDecorView().getRootView(), R.id.container) + webView = findViewById(R.id.internal_webview) urlTextView = findViewById(R.id.url_textview) @@ -94,7 +96,7 @@ class InternalWebView : AppCompatActivity() { } - override fun onNewIntent(intent: Intent?) { + override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) } diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.java b/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.java deleted file mode 100644 index 5277a25d..00000000 --- a/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2012-2016 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.activities; - -import android.app.Activity; -import android.os.Bundle; -import android.view.MenuItem; - -import de.blinkt.openvpn.R; -import de.blinkt.openvpn.fragments.LogFragment; - -/** - * Created by arne on 13.10.13. - */ -public class LogWindow extends BaseActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.log_window); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - if (savedInstanceState == null) { - getSupportFragmentManager().beginTransaction() - .add(R.id.container, new LogFragment()) - .commit(); - } - - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - return super.onOptionsItemSelected(item); - } -} diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.kt b/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.kt new file mode 100644 index 00000000..afc18a03 --- /dev/null +++ b/main/src/ui/java/de/blinkt/openvpn/activities/LogWindow.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012-2016 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ +package de.blinkt.openvpn.activities + +import android.os.Bundle +import android.view.MenuItem +import de.blinkt.openvpn.R +import de.blinkt.openvpn.fragments.LogFragment + +/** + * Created by arne on 13.10.13.setUpEdgeEdgeStuff + */ +class LogWindow : BaseActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.log_window) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + + if (savedInstanceState == null) { + supportFragmentManager.beginTransaction() + .add(R.id.container, LogFragment()) + .commit() + } + + setUpEdgeEdgeInsetsListener(getWindow().getDecorView().getRootView(), R.id.container) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return super.onOptionsItemSelected(item) + } +} diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt b/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt index 68117b52..a15de114 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/MainActivity.kt @@ -10,24 +10,27 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.widget.Toast -import androidx.viewpager.widget.ViewPager +import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator import de.blinkt.openvpn.R import de.blinkt.openvpn.fragments.* import de.blinkt.openvpn.fragments.ImportRemoteConfig.Companion.newInstance import de.blinkt.openvpn.views.ScreenSlidePagerAdapter class MainActivity : BaseActivity() { - private lateinit var mPager: ViewPager + private lateinit var mPager: ViewPager2 private lateinit var mPagerAdapter: ScreenSlidePagerAdapter + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.main_activity) - + val view = layoutInflater.inflate(R.layout.main_activity, null) // Instantiate a ViewPager and a PagerAdapter. - mPager = findViewById(R.id.pager) - mPagerAdapter = ScreenSlidePagerAdapter(supportFragmentManager, this) + mPager = view.findViewById(R.id.pager) + val tablayout: TabLayout = view.findViewById(R.id.tab_layout) + + mPagerAdapter = ScreenSlidePagerAdapter(supportFragmentManager, lifecycle, this) /* Toolbar and slider should have the same elevation */disableToolbarElevation() mPagerAdapter.addTab(R.string.vpn_list_title, VPNProfileList::class.java) @@ -41,8 +44,16 @@ class MainActivity : BaseActivity() { mPagerAdapter.addTab(R.string.openvpn_log, LogFragment::class.java) mPagerAdapter.addTab(R.string.about, AboutFragment::class.java) mPager.setAdapter(mPagerAdapter) + + TabLayoutMediator(tablayout, mPager) { tab, position -> + tab.text = mPagerAdapter.getPageTitle(position) + }.attach() + + setUpEdgeEdgeInsetsListener(view, R.id.root_linear_layout) + setContentView(view) } + private fun disableToolbarElevation() { supportActionBar?.elevation = 0f } diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/OpenSSLSpeed.kt b/main/src/ui/java/de/blinkt/openvpn/activities/OpenSSLSpeed.kt index 324cd881..e7c6c2db 100644 --- a/main/src/ui/java/de/blinkt/openvpn/activities/OpenSSLSpeed.kt +++ b/main/src/ui/java/de/blinkt/openvpn/activities/OpenSSLSpeed.kt @@ -105,6 +105,7 @@ class OpenSSLSpeed : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.openssl_speed) + setUpEdgeEdgeInsetsListener(getWindow().getDecorView().getRootView(), R.id.speed_root) supportActionBar!!.setDisplayHomeAsUpEnabled(true) findViewById<View>(R.id.testSpecific).setOnClickListener { _ -> runAlgorithms(mCipher.text.toString()) } diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.java b/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.java deleted file mode 100644 index 2c9eb761..00000000 --- a/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2012-2016 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.activities; - -import android.annotation.TargetApi; -import android.app.AlertDialog; -import android.content.Intent; -import android.os.Build; -import android.os.Bundle; -import android.preference.PreferenceActivity; -import android.view.Menu; -import android.view.MenuItem; -import android.widget.Toast; - -import androidx.appcompat.app.ActionBar; -import androidx.viewpager.widget.ViewPager; - -import de.blinkt.openvpn.R; -import de.blinkt.openvpn.VpnProfile; -import de.blinkt.openvpn.core.ProfileManager; -import de.blinkt.openvpn.fragments.Settings_Allowed_Apps; -import de.blinkt.openvpn.fragments.Settings_Authentication; -import de.blinkt.openvpn.fragments.Settings_Basic; -import de.blinkt.openvpn.fragments.Settings_Connections; -import de.blinkt.openvpn.fragments.Settings_IP; -import de.blinkt.openvpn.fragments.Settings_Obscure; -import de.blinkt.openvpn.fragments.Settings_Routing; -import de.blinkt.openvpn.fragments.Settings_UserEditable; -import de.blinkt.openvpn.fragments.ShowConfigFragment; -import de.blinkt.openvpn.fragments.VPNProfileList; -import de.blinkt.openvpn.views.ScreenSlidePagerAdapter; - - -public class VPNPreferences extends BaseActivity { - - static final Class[] validFragments = new Class[]{ - Settings_Authentication.class, Settings_Basic.class, Settings_IP.class, - Settings_Obscure.class, Settings_Routing.class, ShowConfigFragment.class, - Settings_Connections.class, Settings_Allowed_Apps.class, - }; - - private String mProfileUUID; - private VpnProfile mProfile; - private ViewPager mPager; - private ScreenSlidePagerAdapter mPagerAdapter; - - public VPNPreferences() { - super(); - } - - - @TargetApi(Build.VERSION_CODES.KITKAT) - protected boolean isValidFragment(String fragmentName) { - for (Class c: validFragments) - if (c.getName().equals(fragmentName)) - return true; - return false; - - } - - @Override - protected void onStop() { - super.onStop(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - outState.putString(getIntent().getStringExtra(getPackageName() + ".profileUUID"),mProfileUUID); - super.onSaveInstanceState(outState); - } - - @Override - protected void onResume() { - super.onResume(); - getProfile(); - // When a profile is deleted from a category fragment in hadset mod we need to finish - // this activity as well when returning - if (mProfile==null || mProfile.profileDeleted) { - setResult(VPNProfileList.RESULT_VPN_DELETED); - finish(); - } - if (mProfile.mTemporaryProfile) - { - Toast.makeText(this, "Temporary profiles cannot be edited", Toast.LENGTH_LONG).show(); - finish(); - } - } - - private void getProfile() { - Intent intent = getIntent(); - - if(intent!=null) { - String profileUUID = intent.getStringExtra(getPackageName() + ".profileUUID"); - if(profileUUID==null) { - Bundle initialArguments = getIntent().getBundleExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS); - profileUUID = initialArguments.getString(getPackageName() + ".profileUUID"); - } - if(profileUUID!=null){ - - mProfileUUID = profileUUID; - mProfile = ProfileManager.get(this, mProfileUUID); - - } - } - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - mProfileUUID = getIntent().getStringExtra(getPackageName() + ".profileUUID"); - if(savedInstanceState!=null){ - String savedUUID = savedInstanceState.getString(getPackageName() + ".profileUUID"); - if(savedUUID!=null) - mProfileUUID=savedUUID; - } - super.onCreate(savedInstanceState); - - mProfile = ProfileManager.get(this,mProfileUUID); - if(mProfile==null) { - Toast.makeText(this, "Profile to edit cannot be found.", Toast.LENGTH_LONG).show(); - finish(); - return; - } - - setTitle(getString(R.string.edit_profile_title, mProfile.getName())); - - - setContentView(R.layout.main_activity); - - disableToolbarElevation(); - - // Instantiate a ViewPager and a PagerAdapter. - mPager = findViewById(R.id.pager); - mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager(), this); - - - Bundle fragmentArguments = new Bundle(); - fragmentArguments.putString(getPackageName() + ".profileUUID",mProfileUUID); - mPagerAdapter.setFragmentArgs(fragmentArguments); - - if (mProfile.mUserEditable) { - mPagerAdapter.addTab(R.string.basic, Settings_Basic.class); - mPagerAdapter.addTab(R.string.server_list, Settings_Connections.class); - mPagerAdapter.addTab(R.string.ipdns, Settings_IP.class); - mPagerAdapter.addTab(R.string.routing, Settings_Routing.class); - mPagerAdapter.addTab(R.string.settings_auth, Settings_Authentication.class); - - mPagerAdapter.addTab(R.string.advanced, Settings_Obscure.class); - } else { - mPagerAdapter.addTab(R.string.basic, Settings_UserEditable.class); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - mPagerAdapter.addTab(R.string.vpn_allowed_apps, Settings_Allowed_Apps.class); - } - mPagerAdapter.addTab(R.string.generated_config, ShowConfigFragment.class); - - - mPager.setAdapter(mPagerAdapter); - - //TabBarView tabs = (TabBarView) findViewById(R.id.sliding_tabs); - //tabs.setViewPager(mPager); - - } - - - @Override - public void onBackPressed() { - setResult(RESULT_OK, getIntent()); - super.onBackPressed(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.remove_vpn) - askProfileRemoval(); - if (item.getItemId() == R.id.duplicate_vpn) { - Intent data = new Intent(); - data.putExtra(VpnProfile.EXTRA_PROFILEUUID, mProfileUUID); - setResult(VPNProfileList.RESULT_VPN_DUPLICATE, data); - finish(); - } - - return super.onOptionsItemSelected(item); - } - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - - getMenuInflater().inflate(R.menu.vpnpreferences_menu, menu); - - return super.onCreateOptionsMenu(menu); - } - - private void askProfileRemoval() { - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setTitle("Confirm deletion"); - dialog.setMessage(getString(R.string.remove_vpn_query, mProfile.mName)); - - dialog.setPositiveButton(android.R.string.yes, - (dialog1, which) -> removeProfile(mProfile)); - dialog.setNegativeButton(android.R.string.no,null); - dialog.create().show(); - } - - protected void removeProfile(VpnProfile profile) { - ProfileManager.getInstance(this).removeProfile(this,profile); - setResult(VPNProfileList.RESULT_VPN_DELETED); - finish(); - - } - - private void disableToolbarElevation() { - ActionBar toolbar = getSupportActionBar(); - toolbar.setElevation(0); - } - -} diff --git a/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.kt b/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.kt new file mode 100644 index 00000000..0dd61748 --- /dev/null +++ b/main/src/ui/java/de/blinkt/openvpn/activities/VPNPreferences.kt @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2012-2016 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ +package de.blinkt.openvpn.activities + +import android.annotation.TargetApi +import android.app.AlertDialog +import android.content.DialogInterface +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.preference.PreferenceActivity +import android.view.Menu +import android.view.MenuItem +import android.widget.Toast +import androidx.viewpager2.widget.ViewPager2 +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator +import de.blinkt.openvpn.R +import de.blinkt.openvpn.VpnProfile +import de.blinkt.openvpn.core.ProfileManager +import de.blinkt.openvpn.fragments.Settings_Allowed_Apps +import de.blinkt.openvpn.fragments.Settings_Authentication +import de.blinkt.openvpn.fragments.Settings_Basic +import de.blinkt.openvpn.fragments.Settings_Connections +import de.blinkt.openvpn.fragments.Settings_IP +import de.blinkt.openvpn.fragments.Settings_Obscure +import de.blinkt.openvpn.fragments.Settings_Routing +import de.blinkt.openvpn.fragments.Settings_UserEditable +import de.blinkt.openvpn.fragments.ShowConfigFragment +import de.blinkt.openvpn.fragments.VPNProfileList +import de.blinkt.openvpn.views.ScreenSlidePagerAdapter + +class VPNPreferences : BaseActivity() { + private var mProfileUUID: String? = null + private var mProfile: VpnProfile? = null + private lateinit var mPager: ViewPager2 + private lateinit var mPagerAdapter: ScreenSlidePagerAdapter + + @TargetApi(Build.VERSION_CODES.KITKAT) + protected fun isValidFragment(fragmentName: String): Boolean { + for (c in validFragments) if (c.name == fragmentName) return true + return false + } + + override fun onStop() { + super.onStop() + } + + override fun onSaveInstanceState(outState: Bundle) { + outState.putString(intent.getStringExtra("$packageName.profileUUID"), mProfileUUID) + super.onSaveInstanceState(outState) + } + + override fun onResume() { + super.onResume() + profile + // When a profile is deleted from a category fragment in hadset mod we need to finish + // this activity as well when returning + if (mProfile == null || mProfile!!.profileDeleted) { + setResult(VPNProfileList.RESULT_VPN_DELETED) + finish() + } + if (mProfile!!.mTemporaryProfile) { + Toast.makeText(this, "Temporary profiles cannot be edited", Toast.LENGTH_LONG).show() + finish() + } + } + + private val profile: Unit + get() { + val intent = intent + + if (intent != null) { + var profileUUID = intent.getStringExtra("$packageName.profileUUID") + if (profileUUID == null) { + val initialArguments = + getIntent().getBundleExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS) + profileUUID = initialArguments!!.getString("$packageName.profileUUID") + } + if (profileUUID != null) { + mProfileUUID = profileUUID + mProfile = ProfileManager.get(this, mProfileUUID) + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + mProfileUUID = intent.getStringExtra("$packageName.profileUUID") + if (savedInstanceState != null) { + val savedUUID = savedInstanceState.getString("$packageName.profileUUID") + if (savedUUID != null) mProfileUUID = savedUUID + } + super.onCreate(savedInstanceState) + + mProfile = ProfileManager.get(this, mProfileUUID) + if (mProfile == null) { + Toast.makeText(this, "Profile to edit cannot be found.", Toast.LENGTH_LONG).show() + finish() + return + } + + title = getString(R.string.edit_profile_title, mProfile!!.name) + + + val rootview = layoutInflater.inflate(R.layout.main_activity, null) + setUpEdgeEdgeInsetsListener(rootview, R.id.root_linear_layout) + + disableToolbarElevation() + + // Instantiate a ViewPager and a PagerAdapter. + mPager = rootview.findViewById(R.id.pager) + val tablayout: TabLayout = rootview.findViewById(R.id.tab_layout) + mPagerAdapter = ScreenSlidePagerAdapter(supportFragmentManager, lifecycle, this) + + + val fragmentArguments = Bundle() + fragmentArguments.putString("$packageName.profileUUID", mProfileUUID) + mPagerAdapter.setFragmentArgs(fragmentArguments) + + if (mProfile!!.mUserEditable) { + mPagerAdapter.addTab(R.string.basic, Settings_Basic::class.java) + mPagerAdapter.addTab(R.string.server_list, Settings_Connections::class.java) + mPagerAdapter.addTab(R.string.ipdns, Settings_IP::class.java) + mPagerAdapter.addTab(R.string.routing, Settings_Routing::class.java) + mPagerAdapter.addTab(R.string.settings_auth, Settings_Authentication::class.java) + + mPagerAdapter.addTab(R.string.advanced, Settings_Obscure::class.java) + } else { + mPagerAdapter.addTab(R.string.basic, Settings_UserEditable::class.java) + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + mPagerAdapter.addTab(R.string.vpn_allowed_apps, Settings_Allowed_Apps::class.java) + } + mPagerAdapter.addTab(R.string.generated_config, ShowConfigFragment::class.java) + + + mPager.setAdapter(mPagerAdapter) + + //TabBarView tabs = (TabBarView) findViewById(R.id.sliding_tabs); + //tabs.setViewPager(mPager); + + TabLayoutMediator(tablayout, mPager) { tab, position -> + tab.text = mPagerAdapter.getPageTitle(position) + }.attach() + + setContentView(rootview) + } + + + override fun onBackPressed() { + setResult(RESULT_OK, intent) + super.onBackPressed() + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (item.itemId == R.id.remove_vpn) askProfileRemoval() + if (item.itemId == R.id.duplicate_vpn) { + val data = Intent() + data.putExtra(VpnProfile.EXTRA_PROFILEUUID, mProfileUUID) + setResult(VPNProfileList.RESULT_VPN_DUPLICATE, data) + finish() + } + + return super.onOptionsItemSelected(item) + } + + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.vpnpreferences_menu, menu) + + return super.onCreateOptionsMenu(menu) + } + + private fun askProfileRemoval() { + val dialog = AlertDialog.Builder(this) + dialog.setTitle("Confirm deletion") + dialog.setMessage(getString(R.string.remove_vpn_query, mProfile!!.mName)) + + dialog.setPositiveButton( + android.R.string.yes + ) { dialog1: DialogInterface?, which: Int -> removeProfile(mProfile) } + dialog.setNegativeButton(android.R.string.no, null) + dialog.create().show() + } + + protected fun removeProfile(profile: VpnProfile?) { + ProfileManager.getInstance(this).removeProfile(this, profile) + setResult(VPNProfileList.RESULT_VPN_DELETED) + finish() + } + + private fun disableToolbarElevation() { + val toolbar = supportActionBar + toolbar!!.elevation = 0f + } + + companion object { + val validFragments: Array<Class<*>> = arrayOf( + Settings_Authentication::class.java, + Settings_Basic::class.java, + Settings_IP::class.java, + Settings_Obscure::class.java, + Settings_Routing::class.java, + ShowConfigFragment::class.java, + Settings_Connections::class.java, + Settings_Allowed_Apps::class.java, + ) + } +} diff --git a/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java b/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java index ad7a7c28..e4d6b32f 100644 --- a/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java +++ b/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java @@ -262,7 +262,6 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable void setUserPW() { if (mVp.isUserPWAuth()) { ClientAPI_ProvideCreds creds = new ClientAPI_ProvideCreds(); - creds.setCachePassword(true); creds.setPassword(mVp.getPasswordAuth()); creds.setUsername(mVp.mUsername); provide_creds(creds); @@ -294,7 +293,7 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable @Override public void sendCRResponse(String response) { mHandler.post(() -> { - post_cc_msg("CR_RESPONSE," + response + "\n"); + post_cc_msg("CR_RESPONSE," + response); }); } @@ -312,25 +311,30 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable public void event(ClientAPI_Event event) { String name = event.getName(); String info = event.getInfo(); - if (name.equals("INFO")) { - if (info.startsWith("OPEN_URL:") || info.startsWith("CR_TEXT:") - || info.startsWith("WEB_AUTH:")) { - mService.trigger_sso(info); - } else { - VpnStatus.logInfo(R.string.info_from_server, info); + switch (name) { + case "INFO" -> { + if (info.startsWith("OPEN_URL:") || info.startsWith("CR_TEXT:") + || info.startsWith("WEB_AUTH:")) { + mService.trigger_sso(info); + } else { + VpnStatus.logInfo(R.string.info_from_server, info); + } + } + case "COMPRESSION_ENABLED", "WARN" -> + VpnStatus.logInfo(String.format(Locale.US, "%s: %s", name, info)); + case "PAUSE" -> + VpnStatus.updateStateString(name, "VPN connection paused", R.string.state_userpause, ConnectionStatus.LEVEL_VPNPAUSED); + case "RESUME" -> + VpnStatus.updateStateString(name, "VPN connection resumed", R.string.state_reconnecting, ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET); + default -> + { + VpnStatus.updateStateString(name, info); + VpnStatus.logInfo(String.format("EVENT: %s: %s", name, info)); } - } else if (name.equals("COMPRESSION_ENABLED") || name.equals(("WARN"))) { - VpnStatus.logInfo(String.format(Locale.US, "%s: %s", name, info)); - } else { - VpnStatus.updateStateString(name, info); } - /* if (event.name.equals("DYNAMIC_CHALLENGE")) { - ClientAPI_DynamicChallenge challenge = new ClientAPI_DynamicChallenge(); - final boolean status = ClientAPI_OpenVPNClient.parse_dynamic_challenge(event.info, challenge); - - } else */ if (event.getError()) VpnStatus.logError(String.format("EVENT(Error): %s: %s", name, info)); + } @Override diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/AboutFragment.java b/main/src/ui/java/de/blinkt/openvpn/fragments/AboutFragment.java index de6c83d8..15375a3f 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/AboutFragment.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/AboutFragment.java @@ -27,6 +27,9 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import com.android.vending.billing.IInAppBillingService; @@ -108,6 +111,16 @@ public class AboutFragment extends Fragment implements View.OnClickListener { TextView wv = (TextView) v.findViewById(R.id.full_licenses); wv.setText(Html.fromHtml(readHtmlFromAssets())); + + + + ViewCompat.setOnApplyWindowInsetsListener(v, (view, windowInsets) -> + { + Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), insets.bottom); + return WindowInsetsCompat.CONSUMED; + } + ); return v; } diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/FaqFragment.java b/main/src/ui/java/de/blinkt/openvpn/fragments/FaqFragment.java index dcdfd5e3..2863b242 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/FaqFragment.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/FaqFragment.java @@ -9,6 +9,9 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.StaggeredGridLayoutManager; @@ -196,9 +199,13 @@ public class FaqFragment extends Fragment { mRecyclerView.setAdapter(new FaqViewAdapter(getActivity(), getFAQEntries())); + Utils.applyInsetListener(v); + return v; } + + private FAQEntry[] getFAQEntries() { Vector<FAQEntry> faqItems = new Vector<>(); diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java b/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java index c5c48b0e..4a7cf735 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/LogFragment.java @@ -9,11 +9,9 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.app.Activity; -import android.app.PendingIntent; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.database.DataSetObserver; @@ -38,8 +36,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemLongClickListener; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.LinearLayout; @@ -538,7 +534,7 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. (dialog1, which) -> { Intent intent = new Intent(getActivity(), LaunchVPN.class); intent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUIDString()); - intent.putExtra(LaunchVPN.EXTRA_START_REASON, "restart from logwindow"); + intent.putExtra(OpenVPNService.EXTRA_START_REASON, "restart from logwindow"); intent.setAction(Intent.ACTION_MAIN); startActivity(intent); }); @@ -631,16 +627,26 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar. }); if (mShowOptionsLayout) mOptionsLayout.setVisibility(View.VISIBLE); + +// ViewCompat.setOnApplyWindowInsetsListener(v, (view, windowInsets) -> +// { +// Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); +// view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), insets.bottom); +// return WindowInsetsCompat.CONSUMED; +// } +// ); + Utils.applyInsetListener(v); + return v; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - // Scroll to the end of the list end - //getListView().setSelection(getListView().getAdapter().getCount()-1); } + + @Override public void onAttach(@NonNull Context activity) { super.onAttach(activity); diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/OpenVpnPreferencesFragment.java b/main/src/ui/java/de/blinkt/openvpn/fragments/OpenVpnPreferencesFragment.java index 802e0b49..0b2ebde2 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/OpenVpnPreferencesFragment.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/OpenVpnPreferencesFragment.java @@ -52,7 +52,10 @@ public abstract class OpenVpnPreferencesFragment extends PreferenceFragmentCompa @Override public void onSaveInstanceState (Bundle outState) { super.onSaveInstanceState(outState); - saveSettings(); + if (getView() != null) { + //if we have no view, there is no point in trying to save anything. + saveSettings(); + } outState.putString(VpnProfile.EXTRA_PROFILEUUID, mProfile.getUUIDString()); } } diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Authentication.kt b/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Authentication.kt index 51a4e2e3..944aa41a 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Authentication.kt +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Authentication.kt @@ -69,6 +69,9 @@ class Settings_Authentication : OpenVpnPreferencesFragment(), Preference.OnPrefe } override fun loadSettings() { + if (!this::mExpectTLSCert.isInitialized) { + return; + } mExpectTLSCert.isChecked = mProfile.mExpectTLSCert mCheckRemoteCN.isChecked = mProfile.mCheckRemoteCN mRemoteCN.setDN(mProfile.mRemoteCN) diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Connections.kt b/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Connections.kt index 8ed9d9ef..b06c3368 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Connections.kt +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_Connections.kt @@ -40,12 +40,8 @@ class Settings_Connections : Settings_Fragment(), View.OnClickListener { val v = inflater.inflate(R.layout.connections, container, false) mWarning = v.findViewById<View>(R.id.noserver_active_warning) as TextView mRecyclerView = v.findViewById<View>(R.id.connection_recycler_view) as RecyclerView - val dpwidth = (container!!.width / resources.displayMetrics.density).toInt() - var columns = dpwidth / 290 - columns = 1.coerceAtLeast(columns) mConnectionsAdapter = ConnectionsAdapter(activity, this, mProfile) - //mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(columns, StaggeredGridLayoutManager.VERTICAL)); mRecyclerView.setHasFixedSize(true) mRecyclerView.layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false) diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_IP.kt b/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_IP.kt index ef69f3f4..fef4861b 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_IP.kt +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/Settings_IP.kt @@ -66,6 +66,10 @@ class Settings_IP : OpenVpnPreferencesFragment(), Preference.OnPreferenceChangeL override fun loadSettings() { + // Since we maybe not have preferences bound yet, check if we actually have them bound. + if (!this::mUsePull.isInitialized) { + return; + } if (mProfile.mAuthenticationType == VpnProfile.TYPE_STATICKEYS) mUsePull.isEnabled = false else mUsePull.isChecked = mProfile.mUsePull mIPv4.text = mProfile.mIPv4Address diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/Utils.kt b/main/src/ui/java/de/blinkt/openvpn/fragments/Utils.kt index 55056424..e41dc337 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/Utils.kt +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/Utils.kt @@ -13,12 +13,14 @@ import android.os.Build import android.provider.OpenableColumns import android.text.SpannableString import android.text.SpannableStringBuilder -import android.text.TextUtils import android.text.style.ForegroundColorSpan import android.util.Base64 +import android.view.View import android.webkit.MimeTypeMap +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding import de.blinkt.openvpn.R -import kotlin.Throws import de.blinkt.openvpn.VpnProfile import de.blinkt.openvpn.core.Preferences import java.io.ByteArrayOutputStream @@ -319,4 +321,37 @@ object Utils { } } + @JvmStatic + fun applyInsetListener(v:View) + { + ViewCompat.setOnApplyWindowInsetsListener( + v + ) { view: View, windowInsets: WindowInsetsCompat -> + val insets = + windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()) + view.updatePadding( + bottom = insets.bottom + ) + WindowInsetsCompat.CONSUMED + } + v.requestApplyInsetsWhenAttached() + } +} + +fun View.requestApplyInsetsWhenAttached() { + if (isAttachedToWindow) { + // We're already attached, just request as normal + requestApplyInsets() + } else { + // We're not attached to the hierarchy, add a listener to + // request when we are + addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(v: View) { + v.removeOnAttachStateChangeListener(this) + v.requestApplyInsets() + } + + override fun onViewDetachedFromWindow(v: View) = Unit + }) + } }
\ No newline at end of file diff --git a/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java b/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java index fa9438cb..28504268 100644 --- a/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java +++ b/main/src/ui/java/de/blinkt/openvpn/fragments/VPNProfileList.java @@ -68,6 +68,7 @@ import de.blinkt.openvpn.core.VpnStatus; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; import static de.blinkt.openvpn.core.OpenVPNService.DISCONNECT_VPN; import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_CHALLENGE_TXT; +import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_START_REASON; public class VPNProfileList extends ListFragment implements OnClickListener, VpnStatus.StateListener { @@ -242,7 +243,7 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn shortcutIntent.setClass(requireContext(), LaunchVPN.class); shortcutIntent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString()); shortcutIntent.setAction(Intent.ACTION_MAIN); - shortcutIntent.putExtra(LaunchVPN.EXTRA_START_REASON, "shortcut"); + shortcutIntent.putExtra(EXTRA_START_REASON, "shortcut"); shortcutIntent.putExtra("EXTRA_HIDELOG", true); PersistableBundle versionExtras = new PersistableBundle(); @@ -450,6 +451,7 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn if (context != null) { final EditText entry = new EditText(context); entry.setSingleLine(); + entry.setContentDescription(getString(R.string.name_of_the_vpn_profile)); AlertDialog.Builder dialog = new AlertDialog.Builder(context); if (mCopyProfile == null) @@ -563,7 +565,7 @@ public class VPNProfileList extends ListFragment implements OnClickListener, Vpn Intent intent = new Intent(getActivity(), LaunchVPN.class); intent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString()); - intent.putExtra(LaunchVPN.EXTRA_START_REASON, "main profile list"); + intent.putExtra(EXTRA_START_REASON, "main profile list"); intent.setAction(Intent.ACTION_MAIN); startActivity(intent); } diff --git a/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.java b/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.java deleted file mode 100644 index 4f1150a2..00000000 --- a/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2012-2016 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.views; - -import android.content.Context; -import android.content.res.Resources; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; - -import java.util.Vector; - -/** -* Created by arne on 18.11.14. -*/ -public class ScreenSlidePagerAdapter extends FragmentPagerAdapter { - - private final Resources res; - private Bundle mFragmentArguments; - - public void setFragmentArgs(Bundle fragmentArguments) { - mFragmentArguments = fragmentArguments; - } - - static class Tab { - public Class<? extends Fragment> fragmentClass; - String mName; - - public Tab(Class<? extends Fragment> fClass, String name){ - mName = name; - fragmentClass = fClass; - } - - } - - - private Vector<Tab> mTabs = new Vector<Tab>(); - - public ScreenSlidePagerAdapter(FragmentManager fm, Context c) { - super(fm); - res = c.getResources(); - } - - @NonNull - @Override - public Fragment getItem(int position) { - try { - Fragment fragment = mTabs.get(position).fragmentClass.newInstance(); - if (mFragmentArguments!=null) - fragment.setArguments(mFragmentArguments); - return fragment; - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public CharSequence getPageTitle(int position) { - return mTabs.get(position).mName; - } - - @Override - public int getCount() { - return mTabs.size(); - } - - public void addTab(@StringRes int name, Class<? extends Fragment> fragmentClass) { - mTabs.add(new Tab(fragmentClass, res.getString(name))); - } -} diff --git a/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.kt b/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.kt new file mode 100644 index 00000000..98036953 --- /dev/null +++ b/main/src/ui/java/de/blinkt/openvpn/views/ScreenSlidePagerAdapter.kt @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012-2016 Arne Schwabe + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt + */ +package de.blinkt.openvpn.views + +import android.content.Context +import android.content.res.Resources +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import androidx.annotation.StringRes +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updateLayoutParams +import androidx.core.view.updatePadding +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.lifecycle.Lifecycle +import androidx.viewpager2.adapter.FragmentStateAdapter +import de.blinkt.openvpn.R +import java.util.Vector + +/** + * Created by arne on 18.11.14. + */ +class ScreenSlidePagerAdapter(fm: FragmentManager, lc: Lifecycle, c: Context) : + FragmentStateAdapter( + fm, lc + ) { + private val res: Resources = c.resources + private var mFragmentArguments: Bundle? = null + + fun setFragmentArgs(fragmentArguments: Bundle?) { + mFragmentArguments = fragmentArguments + } + + internal class Tab(var fragmentClass: Class<out Fragment>, var mName: String) + + private val mTabs = Vector<Tab>() + private var mBottomPadding= 0 + + override fun createFragment(position: Int): Fragment { + try { + val fragment = mTabs[position].fragmentClass.newInstance() + if (mFragmentArguments != null) fragment.arguments = mFragmentArguments + + return fragment + } catch (e: InstantiationException) { + e.printStackTrace() + } catch (e: IllegalAccessException) { + e.printStackTrace() + } + throw IndexOutOfBoundsException("index wrong") + } + + fun getPageTitle(position: Int): CharSequence { + return mTabs[position].mName + } + + override fun getItemCount(): Int { + return mTabs.size + } + + fun addTab(@StringRes name: Int, fragmentClass: Class<out Fragment>) { + mTabs.add(Tab(fragmentClass, res.getString(name))) + } + + fun setBottomPadding(bottom: Int) { + mBottomPadding = bottom; + } +} diff --git a/main/src/ui/res/layout/about.xml b/main/src/ui/res/layout/about.xml index cd482996..f73768c7 100644 --- a/main/src/ui/res/layout/about.xml +++ b/main/src/ui/res/layout/about.xml @@ -9,6 +9,7 @@ android:layout_height="match_parent" android:paddingLeft="@dimen/stdpadding" android:paddingRight="@dimen/stdpadding" + android:clipToPadding="false" android:scrollbarStyle="outsideOverlay"> <LinearLayout diff --git a/main/src/ui/res/layout/basic_settings.xml b/main/src/ui/res/layout/basic_settings.xml index 8aa4c811..47f84e5f 100644 --- a/main/src/ui/res/layout/basic_settings.xml +++ b/main/src/ui/res/layout/basic_settings.xml @@ -21,6 +21,7 @@ style="@style/item" android:text="@string/profilename" android:textAppearance="?android:attr/textAppearanceSmall" + android:labelFor="@id/profilename" /> <EditText diff --git a/main/src/ui/res/layout/config_converter.xml b/main/src/ui/res/layout/config_converter.xml index 591de858..311e7557 100644 --- a/main/src/ui/res/layout/config_converter.xml +++ b/main/src/ui/res/layout/config_converter.xml @@ -2,114 +2,124 @@ ~ Copyright (c) 2012-2016 Arne Schwabe ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt --> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> - <ScrollView + <RelativeLayout xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/root_layout_config_converter" android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_margin="@dimen/stdpadding" - android:orientation="vertical"> + android:layout_height="match_parent"> - - <LinearLayout - android:id="@+id/config_convert_root" + <ScrollView android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="match_parent" + android:layout_margin="@dimen/stdpadding" android:orientation="vertical"> - <TextView - android:id="@+id/profilename_label" - style="@style/item" - android:labelFor="@id/profilename" - android:text="@string/profilename" - android:textAppearance="?android:attr/textAppearanceSmall" - android:visibility="gone" /> - - <EditText - android:id="@+id/profilename" - style="@style/item" - android:inputType="text" - android:visibility="gone" /> - - <TextView - android:layout_marginTop="@dimen/stdpadding" - android:id="@+id/compatmode_label" - style="@style/item" - android:text="@string/compat_mode_label" - android:textAppearance="?android:attr/textAppearanceSmall" - android:visibility="gone" - tools:visibility="visible" /> - - <Spinner - android:id="@+id/compatmode" - style="@style/item" - android:entries="@array/compat_mode" - android:prompt="@string/compatmode" - android:visibility="gone" - tools:visibility="visible" /> - - <TextView - android:layout_marginTop="@dimen/stdpadding" - android:id="@+id/tls_profile_label" - style="@style/item" - android:text="@string/tls_profile" - android:textAppearance="?android:attr/textAppearanceSmall" - android:visibility="gone" - tools:visibility="visible" /> - <Spinner - android:id="@+id/tls_profile" - style="@style/item" - android:entries="@array/tls_profile_entries" - android:prompt="@string/compatmode" - android:visibility="gone" - tools:visibility="visible" /> - <TextView - android:id="@+id/files_missing_hint" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/files_missing_hint" - android:visibility="gone" - tools:visibilty="visible" /> - <TextView - android:id="@+id/permssion_hint" + <LinearLayout + android:id="@+id/config_convert_root" android:layout_width="match_parent" android:layout_height="wrap_content" - android:padding="5dp" - android:text="@string/query_permissions_sdcard" - android:textStyle="bold" - android:visibility="gone" - tools:visibility="visible" /> - - <CheckBox - android:layout_marginTop="@dimen/stdpadding" - android:id="@+id/importpkcs12" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:checked="true" - android:text="@string/importpkcs12fromconfig" - android:visibility="gone" - tools:visibilty="visible" /> - - <TextView - android:id="@+id/textView" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_margin="10dp" - android:text="@string/import_log" - android:textAppearance="?android:attr/textAppearanceMedium" /> + android:orientation="vertical"> + + <TextView + android:id="@+id/profilename_label" + style="@style/item" + android:labelFor="@id/profilename" + android:text="@string/profilename" + android:textAppearance="?android:attr/textAppearanceSmall" + android:visibility="gone" /> + + <EditText + android:id="@+id/profilename" + style="@style/item" + android:inputType="text" + android:visibility="gone" /> + + <TextView + android:id="@+id/compatmode_label" + style="@style/item" + android:layout_marginTop="@dimen/stdpadding" + android:text="@string/compat_mode_label" + android:textAppearance="?android:attr/textAppearanceSmall" + android:visibility="gone" + tools:visibility="visible" /> + + <Spinner + android:id="@+id/compatmode" + style="@style/item" + android:entries="@array/compat_mode" + android:prompt="@string/compatmode" + android:visibility="gone" + tools:visibility="visible" /> + + <TextView + android:id="@+id/tls_profile_label" + style="@style/item" + android:layout_marginTop="@dimen/stdpadding" + android:text="@string/tls_profile" + android:textAppearance="?android:attr/textAppearanceSmall" + android:visibility="gone" + tools:visibility="visible" /> + + <Spinner + android:id="@+id/tls_profile" + style="@style/item" + android:entries="@array/tls_profile_entries" + android:prompt="@string/compatmode" + android:visibility="gone" + tools:visibility="visible" /> + + <TextView + android:id="@+id/files_missing_hint" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/files_missing_hint" + android:visibility="gone" + tools:visibilty="visible" /> + + <TextView + android:id="@+id/permssion_hint" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="5dp" + android:text="@string/query_permissions_sdcard" + android:textStyle="bold" + android:visibility="gone" + tools:visibility="visible" /> + + <CheckBox + android:id="@+id/importpkcs12" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/stdpadding" + android:checked="true" + android:text="@string/importpkcs12fromconfig" + android:visibility="gone" + tools:visibilty="visible" /> + + <TextView + android:id="@+id/textView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="10dp" + android:text="@string/import_log" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <Space + android:id="@+id/fab_footerspace" + android:layout_width="40dp" + android:layout_height="@dimen/round_button_diameter" + android:visibility="gone" /> + </LinearLayout> + + </ScrollView> - <Space - android:id="@+id/fab_footerspace" - android:layout_width="40dp" - android:layout_height="@dimen/round_button_diameter" - android:visibility="gone" /> - </LinearLayout> + <include layout="@layout/save_fab" /> - </ScrollView> + </RelativeLayout> - <include layout="@layout/save_fab" /> -</RelativeLayout> + <include layout="@layout/status_bg" /> +</FrameLayout> diff --git a/main/src/ui/res/layout/faq.xml b/main/src/ui/res/layout/faq.xml index 8cb79649..46b56e58 100644 --- a/main/src/ui/res/layout/faq.xml +++ b/main/src/ui/res/layout/faq.xml @@ -1,15 +1,15 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- ~ Copyright (c) 2012-2016 Arne Schwabe ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt --> <androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/faq_recycler_view" - android:paddingLeft="@dimen/stdpadding" - android:paddingRight="@dimen/stdpadding" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:verticalSpacing="@dimen/stdpadding" - android:horizontalSpacing="@dimen/stdpadding" - />
\ No newline at end of file + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/faq_recycler_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clipToPadding="false" + android:horizontalSpacing="@dimen/stdpadding" + android:paddingLeft="@dimen/stdpadding" + android:paddingRight="@dimen/stdpadding" + android:verticalSpacing="@dimen/stdpadding" />
\ No newline at end of file diff --git a/main/src/ui/res/layout/log_fragment.xml b/main/src/ui/res/layout/log_fragment.xml index df87d1c1..bac1fe94 100644 --- a/main/src/ui/res/layout/log_fragment.xml +++ b/main/src/ui/res/layout/log_fragment.xml @@ -35,6 +35,7 @@ /> <ListView + android:clipToPadding="false" android:id="@android:id/list" android:transcriptMode="normal" android:layout_width="fill_parent" diff --git a/main/src/ui/res/layout/log_silders.xml b/main/src/ui/res/layout/log_silders.xml index 4196e243..de6155fc 100644 --- a/main/src/ui/res/layout/log_silders.xml +++ b/main/src/ui/res/layout/log_silders.xml @@ -19,7 +19,8 @@ <TextView android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/log_verbosity_level"/> + android:text="@string/log_verbosity_level" + android:labelFor="@id/LogLevelSlider"/> <de.blinkt.openvpn.views.SeekBarTicks diff --git a/main/src/ui/res/layout/log_window.xml b/main/src/ui/res/layout/log_window.xml index 7c25dcfa..ffebc474 100644 --- a/main/src/ui/res/layout/log_window.xml +++ b/main/src/ui/res/layout/log_window.xml @@ -4,9 +4,18 @@ --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - android:id="@+id/container" - android:layout_width="match_parent" - android:layout_height="match_parent" - tools:context=".LogWindow" - tools:ignore="MergeRootFrame" />
\ No newline at end of file + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:ignore="MergeRootFrame"> + + + <FrameLayout + android:id="@+id/container" + tools:context=".LogWindow" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + + <include layout="@layout/status_bg" /> +</FrameLayout>
\ No newline at end of file diff --git a/main/src/ui/res/layout/main_activity.xml b/main/src/ui/res/layout/main_activity.xml index b2fe2251..6e0a3de9 100644 --- a/main/src/ui/res/layout/main_activity.xml +++ b/main/src/ui/res/layout/main_activity.xml @@ -2,30 +2,40 @@ ~ Copyright (c) 2012-2016 Arne Schwabe ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt --> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> - + android:layout_height="match_parent"> - <androidx.viewpager.widget.ViewPager - android:id="@+id/pager" + <LinearLayout + android:id="@+id/root_linear_layout" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:orientation="vertical"> + <com.google.android.material.tabs.TabLayout android:id="@+id/tab_layout" style="@style/blinkt.tabLayout" - app:tabMaxWidth="0dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" - app:tabMode="scrollable" + app:tabMaxWidth="0dp" + app:tabMode="scrollable" /> - /> + <androidx.viewpager2.widget.ViewPager2 + android:id="@+id/pager" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="3" /> + + </LinearLayout> - </androidx.viewpager.widget.ViewPager> -</LinearLayout> + <View + android:id="@+id/statusbar_background" + android:background="@color/primary_dark" + android:layout_width="match_parent" + android:layout_height="0dp" /> + +</FrameLayout>
\ No newline at end of file diff --git a/main/src/ui/res/layout/openssl_speed.xml b/main/src/ui/res/layout/openssl_speed.xml index c23d3567..d19b88d2 100644 --- a/main/src/ui/res/layout/openssl_speed.xml +++ b/main/src/ui/res/layout/openssl_speed.xml @@ -2,39 +2,47 @@ ~ Copyright (c) 2012-2017 Arne Schwabe ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> - <LinearLayout +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal"> - - - - <EditText - android:id="@+id/ciphername" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:ems="10" - android:text="@string/default_cipherlist_test" - android:hint="@string/openssl_cipher_name" - android:inputType="textPersonName" /> - - <Button - android:id="@+id/testSpecific" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:text="@string/test_algoirhtms" /> - </LinearLayout> + android:layout_height="match_parent"> - <ListView - android:id="@+id/results" - android:layout_width="match_parent" - android:layout_height="match_parent" /> + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:id="@+id/speed_root" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + + <EditText + android:id="@+id/ciphername" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:ems="10" + android:hint="@string/openssl_cipher_name" + android:inputType="textPersonName" + android:text="@string/default_cipherlist_test" /> + + <Button + android:id="@+id/testSpecific" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="@string/test_algoirhtms" /> + </LinearLayout> + + <ListView + android:id="@+id/results" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + </LinearLayout> -</LinearLayout> + <include layout="@layout/status_bg" /> +</FrameLayout> diff --git a/main/src/ui/res/layout/server_card.xml b/main/src/ui/res/layout/server_card.xml index 1395cd8b..8a19ae8f 100644 --- a/main/src/ui/res/layout/server_card.xml +++ b/main/src/ui/res/layout/server_card.xml @@ -327,6 +327,7 @@ android:layout_below="@+id/connect_timeout_label" android:ems="3" tools:text="232" + android:labelFor="@id/connect_silder" android:gravity="end" android:inputType="numberDecimal"/> @@ -364,6 +365,7 @@ android:id="@+id/warnung_custom" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:labelFor="@id/customoptions" android:text="@string/custom_connection_options_warng"/> <EditText diff --git a/main/src/ui/res/layout/status_bg.xml b/main/src/ui/res/layout/status_bg.xml new file mode 100644 index 00000000..3754664b --- /dev/null +++ b/main/src/ui/res/layout/status_bg.xml @@ -0,0 +1,5 @@ +<View xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/statusbar_background" + android:layout_width="match_parent" + android:layout_height="0dp" + android:background="@color/primary_dark" /> diff --git a/main/src/ui/res/layout/webview_internal.xml b/main/src/ui/res/layout/webview_internal.xml index f1bf17c8..740589e1 100644 --- a/main/src/ui/res/layout/webview_internal.xml +++ b/main/src/ui/res/layout/webview_internal.xml @@ -2,23 +2,29 @@ ~ Copyright (c) 2012-2020 Arne Schwabe ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt --> - -<LinearLayout android:layout_height="match_parent" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - xmlns:tools="http://schemas.android.com/tools" - android:orientation="vertical" - xmlns:android="http://schemas.android.com/apk/res/android"> - - <TextView - android:id="@+id/url_textview" - android:layout_width="match_parent" - android:layout_height="wrap_content" - tools:text="https://foo.bar.baz" /> + android:layout_height="match_parent"> - <WebView - android:id="@+id/internal_webview" + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/webview_root" android:layout_width="match_parent" android:layout_height="match_parent" - /> + android:orientation="vertical"> + + <TextView + android:id="@+id/url_textview" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:text="https://foo.bar.baz" /> + + <WebView + android:id="@+id/internal_webview" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + </LinearLayout> -</LinearLayout> + <include layout="@layout/status_bg" /> +</FrameLayout> diff --git a/main/src/ui/res/menu/connections.xml b/main/src/ui/res/menu/connections.xml index 631e01a8..f4dc1820 100644 --- a/main/src/ui/res/menu/connections.xml +++ b/main/src/ui/res/menu/connections.xml @@ -11,6 +11,7 @@ android:title="@string/add_remote" android:id="@+id/add_new_remote" android:titleCondensed="@string/add" + android:contentDescription="@string/add_remote" app:showAsAction="always" /> </menu>
\ No newline at end of file diff --git a/main/src/ui/res/values/styles.xml b/main/src/ui/res/values/styles.xml index 9e8e92b7..374a650d 100644 --- a/main/src/ui/res/values/styles.xml +++ b/main/src/ui/res/values/styles.xml @@ -10,6 +10,21 @@ <item name="colorPrimaryDark">@color/primary_dark</item> <item name="colorAccent">@color/accent</item> <item name="alertDialogTheme">@style/blinkt.alertDialog</item> + + + <item name="android:navigationBarColor"> + @android:color/transparent + </item> + + <!-- Optional: set to transparent if your app is drawing behind the status bar. --> + <item name="android:statusBarColor"> + @android:color/transparent + </item> + + <!-- Optional: set for a light status bar with dark content. --> + <item name="android:windowLightStatusBar"> + true + </item> </style> <style name="blinkt.dialog" parent="Theme.AppCompat.DayNight.Dialog"> @@ -89,10 +104,6 @@ <item name="tabTextAppearance">@style/AppTabTextAppearance</item> <item name="tabSelectedTextColor">@android:color/white</item> - <!-- <item name="tabPaddingStart">10dp</item>--> - <!-- <item name="tabPaddingEnd">10dp</item>--> - - <item name="tabGravity">fill</item> <item name="tabMaxWidth">0dp</item> |