From 62b080a8d9f5593c8354e6a7c49c5e848564e7fd Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Sun, 28 Feb 2016 12:36:06 +1100 Subject: [PATCH 1/4] Rename logging tag to make logcat debugging clearer. --- F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java index 7203aefa5..e5e7aabc0 100644 --- a/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java +++ b/F-Droid/src/org/fdroid/fdroid/localrepo/SwapService.java @@ -82,7 +82,7 @@ import rx.schedulers.Schedulers; */ public class SwapService extends Service { - private static final String TAG = "SwapManager"; + private static final String TAG = "SwapService"; public static final String SHARED_PREFERENCES = "swap-state"; private static final String KEY_APPS_TO_SWAP = "appsToSwap"; private static final String KEY_BLUETOOTH_ENABLED = "bluetoothEnabled"; From 209afd6bf2ad98354fe7f62a36085f1b6b7b9cc0 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Sun, 28 Feb 2016 12:49:50 +1100 Subject: [PATCH 2/4] Extract switch change listeners to member variables, so that they can be unregistered. When the view is detached, then the listeners will be unregistered. This will also help in the future so that they can be temporarily unregistered when manually changing the state of the switches. --- .../fdroid/views/swap/StartSwapView.java | 101 +++++++++++------- 1 file changed, 65 insertions(+), 36 deletions(-) diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java b/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java index 2923865cf..cee8d95ab 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java @@ -102,7 +102,10 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In @Nullable /* Emulators typically don't have bluetooth adapters */ private final BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter(); + private SwitchCompat wifiSwitch; + private SwitchCompat bluetoothSwitch; private TextView viewBluetoothId; + private TextView textBluetoothVisible; private TextView viewWifiId; private TextView viewWifiNetwork; private TextView peopleNearbyText; @@ -136,7 +139,12 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In private Subscription peerFinderSubscription; - // TODO: Not sure if this is the best place to handle being removed from the view. + /** + * Remove relevant listeners/subscriptions/etc so that they do not receive and process events + * when this view is not in use. + * + * TODO: Not sure if this is the best place to handle being removed from the view. + */ @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); @@ -144,6 +152,14 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In peerFinderSubscription.unsubscribe(); peerFinderSubscription = null; } + + if (wifiSwitch != null) { + wifiSwitch.setOnCheckedChangeListener(null); + } + + if (bluetoothSwitch != null) { + bluetoothSwitch.setOnCheckedChangeListener(null); + } } @Override @@ -227,7 +243,7 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In private void uiInitBluetooth() { if (bluetooth != null) { - final TextView textBluetoothVisible = (TextView) findViewById(R.id.bluetooth_visible); + textBluetoothVisible = (TextView) findViewById(R.id.bluetooth_visible); viewBluetoothId = (TextView) findViewById(R.id.device_id_bluetooth); viewBluetoothId.setText(bluetooth.getName()); @@ -236,28 +252,10 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In int textResource = getManager().isBluetoothDiscoverable() ? R.string.swap_visible_bluetooth : R.string.swap_not_visible_bluetooth; textBluetoothVisible.setText(textResource); - final SwitchCompat bluetoothSwitch = (SwitchCompat) findViewById(R.id.switch_bluetooth); + bluetoothSwitch = (SwitchCompat) findViewById(R.id.switch_bluetooth); Utils.debugLog(TAG, getManager().isBluetoothDiscoverable() ? "Initially marking switch as checked, because Bluetooth is discoverable." : "Initially marking switch as not-checked, because Bluetooth is not discoverable."); bluetoothSwitch.setChecked(getManager().isBluetoothDiscoverable()); - bluetoothSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - Utils.debugLog(TAG, "Received onCheckChanged(true) for Bluetooth swap, prompting user as to whether they want to enable Bluetooth."); - getActivity().startBluetoothSwap(); - textBluetoothVisible.setText(R.string.swap_visible_bluetooth); - viewBluetoothId.setVisibility(View.VISIBLE); - Utils.debugLog(TAG, "Received onCheckChanged(true) for Bluetooth swap (prompting user or setup Bluetooth complete)"); - // TODO: When they deny the request for enabling bluetooth, we need to disable this switch... - } else { - Utils.debugLog(TAG, "Received onCheckChanged(false) for Bluetooth swap, disabling Bluetooth swap."); - getManager().getBluetoothSwap().stop(); - textBluetoothVisible.setText(R.string.swap_not_visible_bluetooth); - viewBluetoothId.setVisibility(View.GONE); - Utils.debugLog(TAG, "Received onCheckChanged(false) for Bluetooth swap, Bluetooth swap disabled successfully."); - } - } - }); + bluetoothSwitch.setOnCheckedChangeListener(onBluetoothSwitchToggled); // TODO: Unregister receiver correctly... LocalBroadcastManager.getInstance(getContext()).registerReceiver(new BroadcastReceiver() { @@ -288,26 +286,34 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In } } + private final CompoundButton.OnCheckedChangeListener onBluetoothSwitchToggled = new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + Utils.debugLog(TAG, "Received onCheckChanged(true) for Bluetooth swap, prompting user as to whether they want to enable Bluetooth."); + getActivity().startBluetoothSwap(); + textBluetoothVisible.setText(R.string.swap_visible_bluetooth); + viewBluetoothId.setVisibility(View.VISIBLE); + Utils.debugLog(TAG, "Received onCheckChanged(true) for Bluetooth swap (prompting user or setup Bluetooth complete)"); + // TODO: When they deny the request for enabling bluetooth, we need to disable this switch... + } else { + Utils.debugLog(TAG, "Received onCheckChanged(false) for Bluetooth swap, disabling Bluetooth swap."); + getManager().getBluetoothSwap().stop(); + textBluetoothVisible.setText(R.string.swap_not_visible_bluetooth); + viewBluetoothId.setVisibility(View.GONE); + Utils.debugLog(TAG, "Received onCheckChanged(false) for Bluetooth swap, Bluetooth swap disabled successfully."); + } + } + }; + private void uiInitWifi() { viewWifiId = (TextView) findViewById(R.id.device_id_wifi); viewWifiNetwork = (TextView) findViewById(R.id.wifi_network); - final SwitchCompat wifiSwitch = (SwitchCompat) findViewById(R.id.switch_wifi); + wifiSwitch = (SwitchCompat) findViewById(R.id.switch_wifi); wifiSwitch.setChecked(getManager().isBonjourDiscoverable()); - wifiSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - Utils.debugLog(TAG, "Received onCheckChanged(true) for WiFi swap, asking in background thread to ensure WiFi swap is running."); - getManager().getWifiSwap().ensureRunningInBackground(); - } else { - Utils.debugLog(TAG, "Received onCheckChanged(false) for WiFi swap, disabling WiFi swap in background thread."); - getManager().getWifiSwap().stopInBackground(); - } - uiUpdateWifiNetwork(); - } - }); + wifiSwitch.setOnCheckedChangeListener(onWifiSwitchToggled); final TextView textWifiVisible = (TextView) findViewById(R.id.wifi_visible); int textResource = getManager().isBonjourDiscoverable() ? R.string.swap_visible_wifi : R.string.swap_not_visible_wifi; @@ -357,6 +363,29 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In uiUpdateWifiNetwork(); } + /** + * When the wifi switch is: + * + * Toggled on: Ask the swap service to ensure wifi swap is running. + * Toggled off: Ask the swap service to prevent the wifi swap service from running. + * + * Both of these actions will be performed in a background thread which will send broadcast + * intents when they are completed. + */ + private final CompoundButton.OnCheckedChangeListener onWifiSwitchToggled = new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + Utils.debugLog(TAG, "Received onCheckChanged(true) for WiFi swap, asking in background thread to ensure WiFi swap is running."); + getManager().getWifiSwap().ensureRunningInBackground(); + } else { + Utils.debugLog(TAG, "Received onCheckChanged(false) for WiFi swap, disabling WiFi swap in background thread."); + getManager().getWifiSwap().stopInBackground(); + } + uiUpdateWifiNetwork(); + } + }; + private void uiUpdateWifiNetwork() { viewWifiId.setText(FDroidApp.ipAddressString); From 1323e800b76cd6489089d5200beecc5f81ad39cc Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Sun, 28 Feb 2016 13:42:35 +1100 Subject: [PATCH 3/4] Temporarily disable listeners when updating switch state in response to background process. Previously, something like this would happen: * Swap service is cancelled * WiFi swap is asked to stop * Event is broadcast when done * UI listens to this event * Upon receiving the event, it updates the UI * Updating the UI triggers an event, causing the process to happen again An alternative solution to this would have been for the UI to stop listening to listeners before WiFi swap is shut down, but that is then only specific to the case when the swap view is being destroyed/removed. This could also happen in other situations however, such as when the swap service times out. --- .../fdroid/views/swap/StartSwapView.java | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java b/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java index cee8d95ab..68236e4a7 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java @@ -254,8 +254,8 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In bluetoothSwitch = (SwitchCompat) findViewById(R.id.switch_bluetooth); Utils.debugLog(TAG, getManager().isBluetoothDiscoverable() ? "Initially marking switch as checked, because Bluetooth is discoverable." : "Initially marking switch as not-checked, because Bluetooth is not discoverable."); - bluetoothSwitch.setChecked(getManager().isBluetoothDiscoverable()); bluetoothSwitch.setOnCheckedChangeListener(onBluetoothSwitchToggled); + setBluetoothSwitchState(getManager().isBluetoothDiscoverable(), true); // TODO: Unregister receiver correctly... LocalBroadcastManager.getInstance(getContext()).registerReceiver(new BroadcastReceiver() { @@ -267,15 +267,15 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In textBluetoothVisible.setText(R.string.swap_setting_up_bluetooth); // bluetoothSwitch.setChecked(true); } else { - bluetoothSwitch.setEnabled(true); if (intent.hasExtra(SwapService.EXTRA_STARTED)) { Utils.debugLog(TAG, "Bluetooth service has started (updating text to visible, but not marking as checked)."); textBluetoothVisible.setText(R.string.swap_visible_bluetooth); + bluetoothSwitch.setEnabled(true); // bluetoothSwitch.setChecked(true); } else { Utils.debugLog(TAG, "Bluetooth service has stopped (setting switch to not-visible)."); textBluetoothVisible.setText(R.string.swap_not_visible_bluetooth); - bluetoothSwitch.setChecked(false); + setBluetoothSwitchState(false, true); } } } @@ -286,6 +286,19 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In } } + /** + * @see StartSwapView#setWifiSwitchState(boolean, boolean) + */ + private void setBluetoothSwitchState(boolean isChecked, boolean isEnabled) { + bluetoothSwitch.setOnCheckedChangeListener(null); + bluetoothSwitch.setChecked(isChecked); + bluetoothSwitch.setEnabled(isEnabled); + bluetoothSwitch.setOnCheckedChangeListener(onBluetoothSwitchToggled); + } + + /** + * @see StartSwapView#onWifiSwitchToggled + */ private final CompoundButton.OnCheckedChangeListener onBluetoothSwitchToggled = new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { @@ -312,8 +325,8 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In viewWifiNetwork = (TextView) findViewById(R.id.wifi_network); wifiSwitch = (SwitchCompat) findViewById(R.id.switch_wifi); - wifiSwitch.setChecked(getManager().isBonjourDiscoverable()); wifiSwitch.setOnCheckedChangeListener(onWifiSwitchToggled); + setWifiSwitchState(getManager().isBonjourDiscoverable(), true); final TextView textWifiVisible = (TextView) findViewById(R.id.wifi_visible); int textResource = getManager().isBonjourDiscoverable() ? R.string.swap_visible_wifi : R.string.swap_not_visible_wifi; @@ -330,23 +343,20 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In if (intent.hasExtra(SwapService.EXTRA_STARTING)) { Utils.debugLog(TAG, "WiFi service is starting (setting toggle to checked, but disabled)."); textWifiVisible.setText(R.string.swap_setting_up_wifi); - wifiSwitch.setEnabled(false); - wifiSwitch.setChecked(true); + setWifiSwitchState(true, false); } else if (intent.hasExtra(SwapService.EXTRA_STOPPING)) { Utils.debugLog(TAG, "WiFi service is stopping (setting toggle to unchecked and disabled)."); textWifiVisible.setText(R.string.swap_stopping_wifi); - wifiSwitch.setEnabled(false); - wifiSwitch.setChecked(false); + setWifiSwitchState(false, false); } else { - wifiSwitch.setEnabled(true); if (intent.hasExtra(SwapService.EXTRA_STARTED)) { Utils.debugLog(TAG, "WiFi service has started (setting toggle to visible)."); textWifiVisible.setText(R.string.swap_visible_wifi); - wifiSwitch.setChecked(true); + setWifiSwitchState(true, true); } else { Utils.debugLog(TAG, "WiFi service has stopped (setting toggle to not-visible)."); textWifiVisible.setText(R.string.swap_not_visible_wifi); - wifiSwitch.setChecked(false); + setWifiSwitchState(false, true); } } uiUpdateWifiNetwork(); @@ -363,6 +373,25 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In uiUpdateWifiNetwork(); } + /** + * Helper function to set the "enable wifi" switch, but prevents the listeners from + * being notified. This enables the UI to be updated without triggering further enable/disable + * events being queued. + * + * This is required because the SwitchCompat and its parent classes will always try to notify + * their listeners if there is one (e.g. http://stackoverflow.com/a/15523518). + * + * The fact that this method also deals with enabling/disabling the switch is more of a convenience + * Nigh on all times this UI wants to change the state of the switch, it is also interested in + * ensuring the enabled state of the switch. + */ + private void setWifiSwitchState(boolean isChecked, boolean isEnabled) { + wifiSwitch.setOnCheckedChangeListener(null); + wifiSwitch.setChecked(isChecked); + wifiSwitch.setEnabled(isEnabled); + wifiSwitch.setOnCheckedChangeListener(onWifiSwitchToggled); + } + /** * When the wifi switch is: * From ad63e52e50c8e07ed0f7d5e0223da0897aa74336 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Sun, 28 Feb 2016 13:57:46 +1100 Subject: [PATCH 4/4] Extract `BroadcastReceivers` to member variables, so they can be unregistered correctly. Previously, they were registered, then forgotten. This means that each time the start swap view was run, another receiver was registered. As a result, they were being invoked multiple times. It doesn't appear that this had any specific side effects which were terrible, but they definitely have the potential to going forward. Note that because we are not using `Fragments` with their convoluted, but at least well documented API, I'm not 100% certain that I've unregistered the receivers at the right location. --- .../fdroid/views/swap/StartSwapView.java | 133 ++++++++++-------- 1 file changed, 74 insertions(+), 59 deletions(-) diff --git a/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java b/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java index 68236e4a7..64e2004e7 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java +++ b/F-Droid/src/org/fdroid/fdroid/views/swap/StartSwapView.java @@ -104,6 +104,7 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In private SwitchCompat wifiSwitch; private SwitchCompat bluetoothSwitch; + private TextView textWifiVisible; private TextView viewBluetoothId; private TextView textBluetoothVisible; private TextView viewWifiId; @@ -160,6 +161,10 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In if (bluetoothSwitch != null) { bluetoothSwitch.setOnCheckedChangeListener(null); } + + LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(onWifiSwapStateChanged); + LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(onBluetoothSwapStateChanged); + LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(onWifiNetworkChanged); } @Override @@ -176,18 +181,17 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In uiInitButtons(); uiShowSearchingForPeers(); - // TODO: Unregister this receiver at some point. LocalBroadcastManager.getInstance(getActivity()).registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - uiUpdateWifiNetwork(); - } - }, - new IntentFilter(WifiStateChangeService.BROADCAST) - ); + onWifiNetworkChanged, new IntentFilter(WifiStateChangeService.BROADCAST)); } + private BroadcastReceiver onWifiNetworkChanged = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + uiUpdateWifiNetwork(); + } + }; + private void uiInitButtons() { findViewById(R.id.btn_send_fdroid).setOnClickListener(new OnClickListener() { @Override @@ -257,35 +261,39 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In bluetoothSwitch.setOnCheckedChangeListener(onBluetoothSwitchToggled); setBluetoothSwitchState(getManager().isBluetoothDiscoverable(), true); - // TODO: Unregister receiver correctly... - LocalBroadcastManager.getInstance(getContext()).registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.hasExtra(SwapService.EXTRA_STARTING)) { - Utils.debugLog(TAG, "Bluetooth service is starting (setting toggle to disabled, not checking because we will wait for an intent that bluetooth is actually enabled)"); - bluetoothSwitch.setEnabled(false); - textBluetoothVisible.setText(R.string.swap_setting_up_bluetooth); - // bluetoothSwitch.setChecked(true); - } else { - if (intent.hasExtra(SwapService.EXTRA_STARTED)) { - Utils.debugLog(TAG, "Bluetooth service has started (updating text to visible, but not marking as checked)."); - textBluetoothVisible.setText(R.string.swap_visible_bluetooth); - bluetoothSwitch.setEnabled(true); - // bluetoothSwitch.setChecked(true); - } else { - Utils.debugLog(TAG, "Bluetooth service has stopped (setting switch to not-visible)."); - textBluetoothVisible.setText(R.string.swap_not_visible_bluetooth); - setBluetoothSwitchState(false, true); - } - } - } - }, new IntentFilter(SwapService.BLUETOOTH_STATE_CHANGE)); + LocalBroadcastManager.getInstance(getContext()).registerReceiver(onBluetoothSwapStateChanged, new IntentFilter(SwapService.BLUETOOTH_STATE_CHANGE)); } else { findViewById(R.id.bluetooth_info).setVisibility(View.GONE); } } + /** + * @see StartSwapView#onWifiSwapStateChanged + */ + private BroadcastReceiver onBluetoothSwapStateChanged = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.hasExtra(SwapService.EXTRA_STARTING)) { + Utils.debugLog(TAG, "Bluetooth service is starting (setting toggle to disabled, not checking because we will wait for an intent that bluetooth is actually enabled)"); + bluetoothSwitch.setEnabled(false); + textBluetoothVisible.setText(R.string.swap_setting_up_bluetooth); + // bluetoothSwitch.setChecked(true); + } else { + if (intent.hasExtra(SwapService.EXTRA_STARTED)) { + Utils.debugLog(TAG, "Bluetooth service has started (updating text to visible, but not marking as checked)."); + textBluetoothVisible.setText(R.string.swap_visible_bluetooth); + bluetoothSwitch.setEnabled(true); + // bluetoothSwitch.setChecked(true); + } else { + Utils.debugLog(TAG, "Bluetooth service has stopped (setting switch to not-visible)."); + textBluetoothVisible.setText(R.string.swap_not_visible_bluetooth); + setBluetoothSwitchState(false, true); + } + } + } + }; + /** * @see StartSwapView#setWifiSwitchState(boolean, boolean) */ @@ -328,7 +336,7 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In wifiSwitch.setOnCheckedChangeListener(onWifiSwitchToggled); setWifiSwitchState(getManager().isBonjourDiscoverable(), true); - final TextView textWifiVisible = (TextView) findViewById(R.id.wifi_visible); + textWifiVisible = (TextView) findViewById(R.id.wifi_visible); int textResource = getManager().isBonjourDiscoverable() ? R.string.swap_visible_wifi : R.string.swap_not_visible_wifi; textWifiVisible.setText(textResource); @@ -336,32 +344,7 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In // and the Bonjour service at the same time. Technically swap will work fine without // Bonjour, and that is more of a convenience. Thus, we should show feedback once wifi // is ready, even if Bonjour is not yet. - // TODO: Unregister receiver correctly... - LocalBroadcastManager.getInstance(getContext()).registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.hasExtra(SwapService.EXTRA_STARTING)) { - Utils.debugLog(TAG, "WiFi service is starting (setting toggle to checked, but disabled)."); - textWifiVisible.setText(R.string.swap_setting_up_wifi); - setWifiSwitchState(true, false); - } else if (intent.hasExtra(SwapService.EXTRA_STOPPING)) { - Utils.debugLog(TAG, "WiFi service is stopping (setting toggle to unchecked and disabled)."); - textWifiVisible.setText(R.string.swap_stopping_wifi); - setWifiSwitchState(false, false); - } else { - if (intent.hasExtra(SwapService.EXTRA_STARTED)) { - Utils.debugLog(TAG, "WiFi service has started (setting toggle to visible)."); - textWifiVisible.setText(R.string.swap_visible_wifi); - setWifiSwitchState(true, true); - } else { - Utils.debugLog(TAG, "WiFi service has stopped (setting toggle to not-visible)."); - textWifiVisible.setText(R.string.swap_not_visible_wifi); - setWifiSwitchState(false, true); - } - } - uiUpdateWifiNetwork(); - } - }, new IntentFilter(SwapService.WIFI_STATE_CHANGE)); + LocalBroadcastManager.getInstance(getContext()).registerReceiver(onWifiSwapStateChanged, new IntentFilter(SwapService.WIFI_STATE_CHANGE)); viewWifiNetwork.setOnClickListener(new OnClickListener() { @Override @@ -373,6 +356,38 @@ public class StartSwapView extends ScrollView implements SwapWorkflowActivity.In uiUpdateWifiNetwork(); } + /** + * When the WiFi swap service is started or stopped, update the UI appropriately. + * This includes both the in-transit states of "Starting" and "Stopping". In these two cases, + * the UI should be disabled to prevent the user quickly switching back and forth - causing + * multiple start/stop actions to be sent to the swap service. + */ + private final BroadcastReceiver onWifiSwapStateChanged = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.hasExtra(SwapService.EXTRA_STARTING)) { + Utils.debugLog(TAG, "WiFi service is starting (setting toggle to checked, but disabled)."); + textWifiVisible.setText(R.string.swap_setting_up_wifi); + setWifiSwitchState(true, false); + } else if (intent.hasExtra(SwapService.EXTRA_STOPPING)) { + Utils.debugLog(TAG, "WiFi service is stopping (setting toggle to unchecked and disabled)."); + textWifiVisible.setText(R.string.swap_stopping_wifi); + setWifiSwitchState(false, false); + } else { + if (intent.hasExtra(SwapService.EXTRA_STARTED)) { + Utils.debugLog(TAG, "WiFi service has started (setting toggle to visible)."); + textWifiVisible.setText(R.string.swap_visible_wifi); + setWifiSwitchState(true, true); + } else { + Utils.debugLog(TAG, "WiFi service has stopped (setting toggle to not-visible)."); + textWifiVisible.setText(R.string.swap_not_visible_wifi); + setWifiSwitchState(false, true); + } + } + uiUpdateWifiNetwork(); + } + }; + /** * Helper function to set the "enable wifi" switch, but prevents the listeners from * being notified. This enables the UI to be updated without triggering further enable/disable