From 73c6a29ede6ba33a215f347335131ce89a27f146 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 23 Apr 2020 16:19:33 +0100 Subject: [PATCH] Add transports activity. --- briar-android/src/main/AndroidManifest.xml | 177 +++++------ .../android/activity/ActivityComponent.java | 3 + .../android/navdrawer/NavDrawerActivity.java | 9 +- .../android/navdrawer/PluginViewModel.java | 139 ++++++++- .../android/navdrawer/TransportsActivity.java | 294 ++++++++++++++++++ .../main/res/layout/activity_transports.xml | 10 + .../res/layout/list_item_transport_card.xml | 73 +++++ .../src/main/res/layout/transports_list.xml | 1 - briar-android/src/main/res/values/strings.xml | 32 +- 9 files changed, 640 insertions(+), 98 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/navdrawer/TransportsActivity.java create mode 100644 briar-android/src/main/res/layout/activity_transports.xml create mode 100644 briar-android/src/main/res/layout/list_item_transport_card.xml diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml index 5055324bf..8a98d5c0c 100644 --- a/briar-android/src/main/AndroidManifest.xml +++ b/briar-android/src/main/AndroidManifest.xml @@ -1,46 +1,46 @@ - + + android:required="false" /> + android:required="false" /> - + android:required="false" /> + - - - - - - - + + + + + + + - - - - + + + + - - - - + + + + - - + + @@ -59,14 +59,13 @@ android:name="org.briarproject.briar.android.BriarService" android:exported="false"> - + - + android:exported="false"> - + android:windowSoftInputMode="adjustResize|stateHidden"> - + android:label="@string/app_name"> - + android:label="@string/app_name"> - + android:windowSoftInputMode="adjustResize|stateAlwaysVisible"> - - + + + @@ -111,17 +107,17 @@ android:launchMode="singleTask" android:theme="@style/BriarTheme.NoActionBar"> - + - - + + - + - - - + + + @@ -133,7 +129,7 @@ android:windowSoftInputMode="adjustResize|stateUnchanged"> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> + android:value="org.briarproject.briar.android.conversation.ConversationActivity" /> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> + android:value="org.briarproject.briar.android.privategroup.conversation.GroupActivity" /> + android:value="org.briarproject.briar.android.privategroup.conversation.GroupActivity" /> + android:value="org.briarproject.briar.android.privategroup.conversation.GroupActivity" /> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> + android:value="org.briarproject.briar.android.conversation.ConversationActivity" /> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> + android:value="org.briarproject.briar.android.forum.ForumActivity" /> + android:value="org.briarproject.briar.android.blog.BlogActivity" /> + android:value="org.briarproject.briar.android.forum.ForumActivity" /> + android:value="org.briarproject.briar.android.blog.BlogActivity" /> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> + android:value="org.briarproject.briar.android.blog.BlogActivity" /> + android:value="org.briarproject.briar.android.blog.BlogActivity" /> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> + android:value="org.briarproject.briar.android.conversation.ConversationActivity" /> - + android:label="@string/startup_failed_activity_title"> + android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity" /> - - + + + + + + + android:value="org.briarproject.briar.android.settings.SettingsActivity" /> + android:value="org.briarproject.briar.android.settings.SettingsActivity" /> + android:value="org.briarproject.briar.android.settings.SettingsActivity" /> - - + + - + android:theme="@android:style/Theme.NoDisplay"> - + android:theme="@android:style/Theme.NoDisplay"> + android:theme="@style/BriarTheme.NoActionBar" /> + android:windowSoftInputMode="adjustResize|stateHidden" /> + android:theme="@style/BriarTheme" /> diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java index 02c18b341..e71e7d786 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java @@ -47,6 +47,7 @@ import org.briarproject.briar.android.login.OpenDatabaseFragment; import org.briarproject.briar.android.login.PasswordFragment; import org.briarproject.briar.android.login.StartupActivity; import org.briarproject.briar.android.navdrawer.NavDrawerActivity; +import org.briarproject.briar.android.navdrawer.TransportsActivity; import org.briarproject.briar.android.panic.PanicPreferencesActivity; import org.briarproject.briar.android.panic.PanicResponderActivity; import org.briarproject.briar.android.privategroup.conversation.GroupActivity; @@ -163,6 +164,8 @@ public interface ActivityComponent { void inject(SettingsActivity activity); + void inject(TransportsActivity activity); + void inject(TestDataActivity activity); void inject(ChangePasswordActivity activity); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java index 5376dc8f0..e3f37e3b0 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/NavDrawerActivity.java @@ -97,6 +97,8 @@ public class NavDrawerActivity extends BriarActivity implements public static Uri SIGN_OUT_URI = Uri.parse("briar-content://org.briarproject.briar/sign-out"); + private final List transports = new ArrayList<>(3); + private NavDrawerViewModel navDrawerViewModel; private PluginViewModel pluginViewModel; private ActionBarDrawerToggle drawerToggle; @@ -110,7 +112,6 @@ public class NavDrawerActivity extends BriarActivity implements private DrawerLayout drawerLayout; private NavigationView navigation; - private List transports; private BaseAdapter transportsAdapter; @Override @@ -141,6 +142,10 @@ public class NavDrawerActivity extends BriarActivity implements drawerLayout = findViewById(R.id.drawer_layout); navigation = findViewById(R.id.navigation); GridView transportsView = findViewById(R.id.transportsView); + transportsView.setOnItemClickListener((parent, view, position, id) -> { + LOG.info("Starting transports activity"); + startActivity(new Intent(this, TransportsActivity.class)); + }); setSupportActionBar(toolbar); ActionBar actionBar = requireNonNull(getSupportActionBar()); @@ -380,8 +385,6 @@ public class NavDrawerActivity extends BriarActivity implements } private void initializeTransports() { - transports = new ArrayList<>(3); - transportsAdapter = new BaseAdapter() { @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/PluginViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/PluginViewModel.java index 8badce8c4..a879b087c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/PluginViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/PluginViewModel.java @@ -1,8 +1,18 @@ package org.briarproject.briar.android.navdrawer; +import android.app.Application; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import org.briarproject.bramble.api.db.DatabaseExecutor; +import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventListener; +import org.briarproject.bramble.api.network.NetworkManager; +import org.briarproject.bramble.api.network.NetworkStatus; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.BluetoothConstants; import org.briarproject.bramble.api.plugin.LanTcpConstants; @@ -12,28 +22,44 @@ import org.briarproject.bramble.api.plugin.PluginManager; import org.briarproject.bramble.api.plugin.TorConstants; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.event.TransportStateEvent; +import org.briarproject.bramble.api.settings.Settings; +import org.briarproject.bramble.api.settings.SettingsManager; +import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent; +import java.util.concurrent.Executor; import java.util.logging.Logger; import javax.inject.Inject; import androidx.annotation.Nullable; +import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; +import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED; +import static android.bluetooth.BluetoothAdapter.EXTRA_STATE; +import static android.bluetooth.BluetoothAdapter.STATE_ON; import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; +import static org.briarproject.bramble.api.plugin.Plugin.PREF_PLUGIN_ENABLE; import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING; +import static org.briarproject.bramble.util.LogUtils.logDuration; +import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.bramble.util.LogUtils.now; @NotNullByDefault -public class PluginViewModel extends ViewModel implements EventListener { +public class PluginViewModel extends AndroidViewModel implements EventListener { private static final Logger LOG = getLogger(PluginViewModel.class.getName()); + private final Application app; + private final Executor dbExecutor; + private final SettingsManager settingsManager; private final PluginManager pluginManager; private final EventBus eventBus; + private final BroadcastReceiver receiver; private final MutableLiveData torPluginState = new MutableLiveData<>(); @@ -42,24 +68,65 @@ public class PluginViewModel extends ViewModel implements EventListener { private final MutableLiveData btPluginState = new MutableLiveData<>(); + private final MutableLiveData torEnabledSetting = + new MutableLiveData<>(false); + private final MutableLiveData wifiEnabledSetting = + new MutableLiveData<>(false); + private final MutableLiveData btEnabledSetting = + new MutableLiveData<>(false); + + private final MutableLiveData networkStatus = + new MutableLiveData<>(); + + private final MutableLiveData bluetoothTurnedOn = + new MutableLiveData<>(false); + @Inject - PluginViewModel(PluginManager pluginManager, EventBus eventBus) { + PluginViewModel(Application app, @DatabaseExecutor Executor dbExecutor, + SettingsManager settingsManager, PluginManager pluginManager, + EventBus eventBus, NetworkManager networkManager) { + super(app); + this.app = app; + this.dbExecutor = dbExecutor; + this.settingsManager = settingsManager; this.pluginManager = pluginManager; this.eventBus = eventBus; eventBus.addListener(this); + receiver = new BluetoothStateReceiver(); + app.registerReceiver(receiver, new IntentFilter(ACTION_STATE_CHANGED)); + networkStatus.setValue(networkManager.getNetworkStatus()); torPluginState.setValue(getTransportState(TorConstants.ID)); wifiPluginState.setValue(getTransportState(LanTcpConstants.ID)); btPluginState.setValue(getTransportState(BluetoothConstants.ID)); + loadSettings(); } @Override protected void onCleared() { eventBus.removeListener(this); + app.unregisterReceiver(receiver); } @Override public void eventOccurred(Event e) { - if (e instanceof TransportStateEvent) { + if (e instanceof SettingsUpdatedEvent) { + SettingsUpdatedEvent s = (SettingsUpdatedEvent) e; + if (s.getNamespace().equals(TorConstants.ID.getString())) { + boolean enable = + s.getSettings().getBoolean(PREF_PLUGIN_ENABLE, true); + torEnabledSetting.setValue(enable); + } else if (s.getNamespace() + .equals(LanTcpConstants.ID.getString())) { + boolean enable = + s.getSettings().getBoolean(PREF_PLUGIN_ENABLE, false); + wifiEnabledSetting.setValue(enable); + } else if (s.getNamespace().equals( + BluetoothConstants.ID.getString())) { + boolean enable = + s.getSettings().getBoolean(PREF_PLUGIN_ENABLE, false); + btEnabledSetting.setValue(enable); + } + } else if (e instanceof TransportStateEvent) { TransportStateEvent t = (TransportStateEvent) e; TransportId id = t.getTransportId(); State state = t.getState(); @@ -77,6 +144,48 @@ public class PluginViewModel extends ViewModel implements EventListener { return liveData; } + LiveData getPluginEnabledSetting(TransportId id) { + if (id.equals(TorConstants.ID)) return torEnabledSetting; + else if (id.equals(LanTcpConstants.ID)) return wifiEnabledSetting; + else if (id.equals(BluetoothConstants.ID)) return btEnabledSetting; + else throw new IllegalArgumentException(); + } + + LiveData getNetworkStatus() { + return networkStatus; + } + + LiveData getBluetoothTurnedOn() { + return bluetoothTurnedOn; + } + + void enableTransport(TransportId id, boolean enable) { + Settings s = new Settings(); + s.putBoolean(PREF_PLUGIN_ENABLE, enable); + mergeSettings(s, id.getString()); + } + + private void loadSettings() { + dbExecutor.execute(() -> { + try { + boolean tor = isPluginEnabled(TorConstants.ID, true); + torEnabledSetting.postValue(tor); + boolean wifi = isPluginEnabled(LanTcpConstants.ID, false); + wifiEnabledSetting.postValue(wifi); + boolean bt = isPluginEnabled(BluetoothConstants.ID, false); + btEnabledSetting.postValue(bt); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + private boolean isPluginEnabled(TransportId id, boolean defaultValue) + throws DbException { + Settings s = settingsManager.getSettings(id.getString()); + return s.getBoolean(PREF_PLUGIN_ENABLE, defaultValue); + } + private State getTransportState(TransportId id) { Plugin plugin = pluginManager.getPlugin(id); return plugin == null ? STARTING_STOPPING : plugin.getState(); @@ -89,4 +198,26 @@ public class PluginViewModel extends ViewModel implements EventListener { else if (id.equals(BluetoothConstants.ID)) return btPluginState; else return null; } + + private void mergeSettings(Settings s, String namespace) { + dbExecutor.execute(() -> { + try { + long start = now(); + settingsManager.mergeSettings(s, namespace); + logDuration(LOG, "Merging settings", start); + } catch (DbException e) { + logException(LOG, WARNING, e); + } + }); + } + + private class BluetoothStateReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + int state = intent.getIntExtra(EXTRA_STATE, 0); + if (state == STATE_ON) bluetoothTurnedOn.postValue(true); + else bluetoothTurnedOn.postValue(false); + } + } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/TransportsActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/TransportsActivity.java new file mode 100644 index 000000000..f9bb76559 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/navdrawer/TransportsActivity.java @@ -0,0 +1,294 @@ +package org.briarproject.briar.android.navdrawer; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.TextView; + +import org.briarproject.bramble.api.network.NetworkStatus; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.plugin.BluetoothConstants; +import org.briarproject.bramble.api.plugin.LanTcpConstants; +import org.briarproject.bramble.api.plugin.Plugin.State; +import org.briarproject.bramble.api.plugin.TorConstants; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.briar.R; +import org.briarproject.briar.android.activity.ActivityComponent; +import org.briarproject.briar.android.activity.BriarActivity; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.SwitchCompat; +import androidx.core.content.ContextCompat; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; + +import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; +import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; +import static org.briarproject.bramble.api.plugin.Plugin.State.ENABLING; +import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class TransportsActivity extends BriarActivity { + + @Inject + ViewModelProvider.Factory viewModelFactory; + + private final List transports = new ArrayList<>(3); + + private PluginViewModel viewModel; + private BaseAdapter transportsAdapter; + + @Override + public void onCreate(@Nullable Bundle state) { + super.onCreate(state); + + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setHomeButtonEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(true); + } + + setContentView(R.layout.activity_transports); + + ViewModelProvider provider = + ViewModelProviders.of(this, viewModelFactory); + viewModel = provider.get(PluginViewModel.class); + + GridView grid = findViewById(R.id.grid); + initializeCards(); + grid.setAdapter(transportsAdapter); + } + + @Override + public void injectActivity(ActivityComponent component) { + component.inject(this); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return false; + } + + private void initializeCards() { + transportsAdapter = new BaseAdapter() { + + @Override + public int getCount() { + return transports.size(); + } + + @Override + public Transport getItem(int position) { + return transports.get(position); + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, + ViewGroup parent) { + View view; + if (convertView != null) { + view = convertView; + } else { + LayoutInflater inflater = getLayoutInflater(); + view = inflater.inflate(R.layout.list_item_transport_card, + parent, false); + } + + Transport t = getItem(position); + + ImageView icon = view.findViewById(R.id.icon); + icon.setImageDrawable(ContextCompat.getDrawable( + TransportsActivity.this, t.iconDrawable)); + icon.setColorFilter(ContextCompat.getColor( + TransportsActivity.this, t.iconColor)); + + TextView title = view.findViewById(R.id.title); + title.setText(getString(t.title)); + + SwitchCompat switchCompat = + view.findViewById(R.id.switchCompat); + switchCompat.setText(getString(t.switchLabel)); + switchCompat.setOnClickListener(v -> + viewModel.enableTransport(t.id, + switchCompat.isChecked())); + switchCompat.setChecked(t.isSwitchChecked); + + TextView deviceStatus = view.findViewById(R.id.deviceStatus); + deviceStatus.setText(getBulletString(t.deviceStatus)); + + TextView appStatus = view.findViewById(R.id.appStatus); + appStatus.setText(getBulletString(t.pluginStatus)); + + return view; + } + }; + + Transport tor = createTransport(TorConstants.ID, + R.drawable.transport_tor, R.string.transport_tor, + R.string.tor_enable_title, R.string.tor_device_status_offline, + R.string.tor_plugin_status_inactive); + transports.add(tor); + + Transport wifi = createTransport(LanTcpConstants.ID, + R.drawable.transport_lan, R.string.transport_lan_long, + R.string.wifi_setting, R.string.lan_device_status_off, + R.string.lan_plugin_status_inactive); + transports.add(wifi); + + Transport bt = createTransport(BluetoothConstants.ID, + R.drawable.transport_bt, R.string.transport_bt, + R.string.bluetooth_setting, R.string.bt_device_status_off, + R.string.bt_plugin_status_inactive); + transports.add(bt); + + viewModel.getNetworkStatus().observe(this, status -> { + tor.deviceStatus = getTorDeviceStatus(status); + wifi.deviceStatus = getWifiDeviceStatus(status); + transportsAdapter.notifyDataSetChanged(); + }); + + viewModel.getBluetoothTurnedOn().observe(this, on -> { + bt.deviceStatus = getBtDeviceStatus(on); + transportsAdapter.notifyDataSetChanged(); + }); + } + + private String getBulletString(@StringRes int resId) { + return "\u2022 " + getString(resId); + } + + @ColorRes + private int getIconColor(State state) { + if (state == ACTIVE) return R.color.briar_lime_400; + else if (state == ENABLING) return R.color.briar_orange_500; + else return android.R.color.tertiary_text_light; + } + + @StringRes + private int getTorDeviceStatus(NetworkStatus status) { + if (!status.isConnected()) return R.string.tor_device_status_offline; + if (status.isWifi()) return R.string.tor_device_status_online_wifi; + else return R.string.tor_device_status_online_mobile_data; + } + + @StringRes + private int getWifiDeviceStatus(NetworkStatus status) { + if (status.isWifi()) return R.string.lan_device_status_on; + else return R.string.lan_device_status_off; + } + + @StringRes + private int getBtDeviceStatus(boolean on) { + if (on) return R.string.bt_device_status_on; + else return R.string.bt_device_status_off; + } + + @StringRes + private int getPluginStatus(TransportId id, State state) { + if (id.equals(TorConstants.ID)) { + return getTorPluginStatus(state); + } else if (id.equals(LanTcpConstants.ID)) { + return getWifiPluginStatus(state); + } else if (id.equals(BluetoothConstants.ID)) { + return getBtPluginStatus(state); + } else throw new AssertionError(); + } + + @StringRes + private int getTorPluginStatus(State state) { + if (state == ENABLING) return R.string.tor_plugin_status_enabling; + else if (state == ACTIVE) return R.string.tor_plugin_status_active; + else if (state == DISABLED) return R.string.tor_plugin_status_disabled; + else return R.string.tor_plugin_status_inactive; + } + + @StringRes + private int getWifiPluginStatus(State state) { + if (state == ENABLING) return R.string.lan_plugin_status_enabling; + else if (state == ACTIVE) return R.string.lan_plugin_status_active; + else if (state == DISABLED) return R.string.lan_plugin_status_disabled; + else return R.string.lan_plugin_status_inactive; + } + + @StringRes + private int getBtPluginStatus(State state) { + if (state == ENABLING) return R.string.bt_plugin_status_enabling; + else if (state == ACTIVE) return R.string.bt_plugin_status_active; + else if (state == DISABLED) return R.string.bt_plugin_status_disabled; + else return R.string.bt_plugin_status_inactive; + } + + private Transport createTransport(TransportId id, + @DrawableRes int iconDrawable, @StringRes int title, + @StringRes int switchLabel, @StringRes int deviceStatus, + @StringRes int pluginStatus) { + int iconColor = getIconColor(STARTING_STOPPING); + Transport transport = new Transport(id, iconDrawable, iconColor, title, + switchLabel, false, deviceStatus, pluginStatus); + viewModel.getPluginState(id).observe(this, state -> { + transport.iconColor = getIconColor(state); + transport.pluginStatus = getPluginStatus(transport.id, state); + transportsAdapter.notifyDataSetChanged(); + }); + viewModel.getPluginEnabledSetting(id).observe(this, enabled -> { + transport.isSwitchChecked = enabled; + transportsAdapter.notifyDataSetChanged(); + }); + return transport; + } + + private static class Transport { + + private final TransportId id; + + @DrawableRes + private final int iconDrawable; + @StringRes + private final int title, switchLabel; + + @ColorRes + private int iconColor; + @StringRes + private int deviceStatus, pluginStatus; + private boolean isSwitchChecked; + + private Transport(TransportId id, @DrawableRes int iconDrawable, + @ColorRes int iconColor, @StringRes int title, + @StringRes int switchLabel, boolean isSwitchChecked, + @StringRes int deviceStatus, @StringRes int pluginStatus) { + this.id = id; + this.iconDrawable = iconDrawable; + this.iconColor = iconColor; + this.title = title; + this.switchLabel = switchLabel; + this.isSwitchChecked = isSwitchChecked; + this.deviceStatus = deviceStatus; + this.pluginStatus = pluginStatus; + } + } +} diff --git a/briar-android/src/main/res/layout/activity_transports.xml b/briar-android/src/main/res/layout/activity_transports.xml new file mode 100644 index 000000000..11f4f8dba --- /dev/null +++ b/briar-android/src/main/res/layout/activity_transports.xml @@ -0,0 +1,10 @@ + + diff --git a/briar-android/src/main/res/layout/list_item_transport_card.xml b/briar-android/src/main/res/layout/list_item_transport_card.xml new file mode 100644 index 000000000..8144f9e2a --- /dev/null +++ b/briar-android/src/main/res/layout/list_item_transport_card.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/briar-android/src/main/res/layout/transports_list.xml b/briar-android/src/main/res/layout/transports_list.xml index a484522c7..d25d038a4 100644 --- a/briar-android/src/main/res/layout/transports_list.xml +++ b/briar-android/src/main/res/layout/transports_list.xml @@ -12,7 +12,6 @@ android:id="@+id/transportsView" android:layout_width="match_parent" android:layout_height="wrap_content" - android:listSelector="@android:color/transparent" android:numColumns="3" tools:listitem="@layout/list_item_transport" /> diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 482b5ce1a..b4f0fd0e1 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -69,10 +69,37 @@ Settings Sign Out - + Internet - Bluetooth + Internet status: + Your phone has Internet access via Wi-Fi + Your phone has Internet access via mobile data + Your phone does not have Internet access + Briar is connecting to the Internet + Briar can connect to contacts via the Internet + Briar can\'t connect to contacts via the Internet + Briar is configured not to connect to contacts via the Internet + + Wi-Fi + Same Wi-Fi network + Wi-Fi status: + Your phone is connected to Wi-Fi + Your phone is not connected to Wi-Fi + Briar is connecting to the Wi-Fi network + Briar can connect to contacts on the same Wi-Fi network + Briar can\'t connect to contacts on the same Wi-Fi network + Briar is configured not to connect to contacts on the same Wi-Fi network + + + Bluetooth + Bluetooth status: + Your phone\'s Bluetooth is turned on + Your phone\'s Bluetooth is turned off + Briar is connecting to Bluetooth + Briar can connect to contacts via Bluetooth + Briar can\'t connect to contacts via Bluetooth + Briar is configured not to connect to contacts via Bluetooth Signed out of Briar @@ -121,6 +148,7 @@ Help Sorry Unavailable on your system + Status: No contacts to show