Commit da85b37e authored by kirk's avatar kirk

prepare for version 18

parent deadc5fe
......@@ -11,6 +11,7 @@
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:contentDescription="@string/qr_code_label"
android:scaleType="centerInside"
android:src="@drawable/ic_placeholder" />
</RelativeLayout>
......@@ -32,7 +32,7 @@
<string name="null_message">Status OK but message is null</string>
<string name="empty_message">Empty message</string>
<string name="unparseable_payload">Unparseable payload</string>
<string name="initialized_from_active_connection">Initialized from active connection to %1%s</string>
<string name="initialized_from_active_connection">Initialized from active connection to %1$s</string>
<string name="no_active_connection">No active connection</string>
</resources>
......@@ -16,7 +16,6 @@
package us.rader.wyfy;
import us.rader.wyfy.model.WifiSettings;
import us.rader.wyfy.model.WifiSettings.ConnectionOutcome;
import us.rader.wyfy.nfc.ForegroundDispatchActivity;
import us.rader.wyfy.nfc.NdefReaderActivity;
import android.app.Activity;
......@@ -24,18 +23,13 @@ import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
......@@ -47,156 +41,6 @@ import android.view.MenuItem;
public final class MainActivity extends FragmentActivity implements
WifiSettingsFragment.OnWifiSettingsChangedListener {
/**
* Attempt to connect to wifi in a worker thread
*
* @author Kirk
*/
private class ConnectTask extends
AsyncTask<Void, Void, WifiSettings.ConnectionOutcome> {
/**
* Connect to wifi in a worker thread
*
* @param params
* ignored
*
* @see android.os.AsyncTask#doInBackground(Void...)
*/
@Override
protected WifiSettings.ConnectionOutcome doInBackground(Void... params) {
try {
return WifiSettings.getInstance().connect(
(WifiManager) getSystemService(WIFI_SERVICE));
} catch (Exception e) {
Log.e(getClass().getName(), "error connecting to wifi", e); //$NON-NLS-1$
return ConnectionOutcome.FAILED;
}
}
/**
* Report outcome to user
*
* @param result
* value returned by
* {@link WifiSettings#connect(WifiManager)} in the worker
* thread
*
* @see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
@Override
protected void onPostExecute(WifiSettings.ConnectionOutcome result) {
String ssid = WifiSettings.getInstance().getSsid();
switch (result) {
case ADDED:
alert(getString(R.string.successfully_added_wifi, ssid));
break;
case ENABLED:
alert(getString(R.string.successfully_enabled_wifi, ssid));
break;
case FAILED:
alert(getString(R.string.failed_to_enable_wifi, ssid));
break;
default:
alert(getString(R.string.unrecognized_connection_outcome,
result));
break;
}
if (qrCodeFragment != null) {
qrCodeFragment.updateQrCode();
}
}
}
/**
* Invoke {@link WifiSettings#getActiveConnection(WifiManager)} in a worker
* thread
*
* @author Kirk
*/
private class GetActiveConnectionTask extends
AsyncTask<Void, Void, Boolean> {
/**
* Invoke {@link WifiSettings#getActiveConnection(WifiManager)}
*
* @param params
* ignored
*
* @return result of calling
* {@link WifiSettings#getActiveConnection(WifiManager)}
*
* @see android.os.AsyncTask#doInBackground(Void...)
*/
@Override
protected Boolean doInBackground(Void... params) {
try {
WifiManager manager = (WifiManager) getSystemService(WIFI_SERVICE);
return WifiSettings.getInstance().getActiveConnection(manager);
} catch (Exception e) {
Log.e(getClass().getName(), "getActiveConnection", e); //$NON-NLS-1$
return Boolean.FALSE;
}
}
/**
* Update the QR code if in two-pane mode
*
* @param result
* result of calling
* {@link WifiSettings#getActiveConnection(WifiManager)}
*
* @see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
@Override
protected void onPostExecute(Boolean result) {
if (result) {
alert(getString(R.string.initialized_from_active_connection,
WifiSettings.getInstance().getSsid()));
} else {
alert(getString(R.string.no_active_connection));
}
if (qrCodeFragment != null) {
qrCodeFragment.updateQrCode();
}
}
}
/**
* {@link Activity#startActivityForResult(Intent, int)} request code when
* launching {@link WriteTagActivity}
......@@ -325,22 +169,8 @@ public final class MainActivity extends FragmentActivity implements
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setFragments(savedInstanceState);
if (savedInstanceState == null) {
Intent intent = getIntent();
if (intent != null) {
if (!parseIntentData(intent)) {
getActiveConnection();
}
}
}
}
/**
......@@ -370,16 +200,6 @@ public final class MainActivity extends FragmentActivity implements
}
/**
* Initialize the wi fi settings model based on the currently active
* connection, if any
*/
private void getActiveConnection() {
new GetActiveConnectionTask().execute();
}
/**
* Handle result from {@link WriteTagActivity}
*
......@@ -443,115 +263,6 @@ public final class MainActivity extends FragmentActivity implements
}
/**
* Parse the data passed in the given {@link Intent} at launch
*
* @param intent
* the {@link Intent}
*
* @return <code>true</code> if and only if an asynchronouse attempt to
* connect was launched
*/
private boolean parseIntentData(Intent intent) {
Uri uri = intent.getData();
if (uri != null) {
return parseUri(uri.toString());
}
Parcelable[] ndefMessages = intent
.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if ((ndefMessages != null) && (ndefMessages.length > 0)) {
return parseLegacyMessage((NdefMessage) ndefMessages[0]);
}
return false;
}
/**
* Initialize from a legacy {@link NdefMessage}
*
* Provide backward compatibility for tags written with older versions of
* this app
*
* @param ndefMessage
* legacy {@link NdefMessage}
*
* @return <code>true</code> if and only if an asynchronouse attempt to
* connect was launched
*/
private boolean parseLegacyMessage(NdefMessage ndefMessage) {
try {
NdefRecord[] records = ndefMessage.getRecords();
if (records.length > 0) {
NdefRecord record = records[0];
if (record.getTnf() != NdefRecord.TNF_MIME_MEDIA) {
return false;
}
String type = new String(record.getType(), "US-ASCII"); //$NON-NLS-1$
if ("application/x-wyfy".equals(type)) { //$NON-NLS-1$
String payload = new String(record.getPayload(), "US-ASCII"); //$NON-NLS-1$
return parseUri(payload);
}
}
} catch (Exception e) {
Log.e(getClass().getName(), "initializeNdefMessage", e); //$NON-NLS-1$
}
return false;
}
/**
* Initialize wi fi model state from the given WIFI: {@link Uri}
*
* @param uri
* WIFI: {@link Uri}
*
* @return <code>true</code> if and only if an asynchronous attempt to
* connect was launched
*/
private boolean parseUri(String uri) {
try {
if (WifiSettings.getInstance().parse(uri)) {
new ConnectTask().execute();
return true;
}
} catch (Exception e) {
Log.e(getClass().getName(), "error parsing URI", e); //$NON-NLS-1$
}
return false;
}
/**
* Initialize the UI {@link Fragment} instances according to the current
* screen layout
......
......@@ -17,6 +17,8 @@ package us.rader.wyfy;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Timer;
import java.util.TimerTask;
import us.rader.wyfy.model.WifiSettings;
import us.rader.wyfy.provider.FileProvider;
......@@ -155,6 +157,34 @@ public final class QrCodeFragment extends Fragment {
}
/**
* Update the QR code bitmap now that the settings have, presumably, been
* restored and the view is, hopefully, ready
*
* @see android.support.v4.app.Fragment#onResume()
*/
@Override
public void onResume() {
super.onResume();
// TODO: figure out a better way to work around state-management bug in
// Android UI classes than using a Timer to delay this initial refresh
TimerTask task = new TimerTask() {
@Override
public void run() {
updateQrCode();
}
};
new Timer().schedule(task, 500);
}
/**
* Save QR code to a file and then send a sharing {@link Intent} wrapped in
* a chooser
......
......@@ -16,9 +16,19 @@
package us.rader.wyfy;
import us.rader.wyfy.model.WifiSettings;
import us.rader.wyfy.model.WifiSettings.ConnectionOutcome;
import us.rader.wyfy.model.WifiSettings.Security;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
......@@ -57,6 +67,133 @@ public final class WifiSettingsFragment extends Fragment implements
}
/**
* Attempt to connect to wifi in a worker thread
*
* @author Kirk
*/
private class ConnectTask extends
AsyncTask<Void, Void, WifiSettings.ConnectionOutcome> {
/**
* Connect to wifi in a worker thread
*
* @param params
* ignored
*
* @see android.os.AsyncTask#doInBackground(Void...)
*/
@Override
protected WifiSettings.ConnectionOutcome doInBackground(Void... params) {
try {
return WifiSettings.getInstance().connect(
(WifiManager) getActivity().getSystemService(
Context.WIFI_SERVICE));
} catch (Exception e) {
Log.e(getClass().getName(), "error connecting to wifi", e); //$NON-NLS-1$
return ConnectionOutcome.FAILED;
}
}
/**
* Report outcome to user
*
* @param result
* value returned by
* {@link WifiSettings#connect(WifiManager)} in the worker
* thread
*
* @see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
@Override
protected void onPostExecute(WifiSettings.ConnectionOutcome result) {
updateSettings();
}
}
/**
* Invoke {@link WifiSettings#getActiveConnection(WifiManager)} in a worker
* thread
*
* @author Kirk
*/
private class GetActiveConnectionTask extends
AsyncTask<Void, Void, Boolean> {
/**
* Invoke {@link WifiSettings#getActiveConnection(WifiManager)}
*
* @param params
* ignored
*
* @return result of calling
* {@link WifiSettings#getActiveConnection(WifiManager)}
*
* @see android.os.AsyncTask#doInBackground(Void...)
*/
@Override
protected Boolean doInBackground(Void... params) {
try {
WifiManager manager = (WifiManager) getActivity()
.getSystemService(Context.WIFI_SERVICE);
return WifiSettings.getInstance().getActiveConnection(manager);
} catch (Exception e) {
Log.e(getClass().getName(), "getActiveConnection", e); //$NON-NLS-1$
return Boolean.FALSE;
}
}
/**
* Update the QR code if in two-pane mode
*
* @param result
* result of calling
* {@link WifiSettings#getActiveConnection(WifiManager)}
*
* @see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
@Override
protected void onPostExecute(Boolean result) {
updateSettings();
}
}
/**
*
*/
private static final String HIDDEN_PARAMETER = "HIDDEN"; //$NON-NLS-1$
/**
*
*/
private static final String PASSWORD_PARAMETER = "PASSWORD"; //$NON-NLS-1$
/**
*
*/
private static final String SECURITY_PARAMETER = "SECURITY"; //$NON-NLS-1$
/**
*
*/
private static final String SSID_PARAMETER = "SSID"; //$NON-NLS-1$
/**
* Turn {@link #notifyListener()} into a no-op while
* {@link #delayNotifications} is greater than 0
......@@ -230,6 +367,45 @@ public final class WifiSettingsFragment extends Fragment implements
}
/**
* Prepare this instance to be displayed
*
* @param savedInstanceState
* saved state or <code>null</code>
*
* @see android.support.v4.app.Fragment#onCreate(android.os.Bundle)
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
Intent intent = getActivity().getIntent();
if (intent != null) {
if (!parseIntentData(intent)) {
getActiveConnection();
}
}
} else {
WifiSettings settings = WifiSettings.getInstance();
settings.setSsid(savedInstanceState.getString(SSID_PARAMETER));
settings.setPassword(savedInstanceState
.getString(PASSWORD_PARAMETER));
settings.setHidden(savedInstanceState.getBoolean(HIDDEN_PARAMETER));
settings.setSecurity((Security) savedInstanceState
.getSerializable(SECURITY_PARAMETER));
}
}
/**
* Inflate the {@ink View}
*
......@@ -288,6 +464,26 @@ public final class WifiSettingsFragment extends Fragment implements
}
/**
* Save the app-specific state of this instance
*
* @param outState
* saved state
*
* @see android.support.v4.app.Fragment#onSaveInstanceState(android.os.Bundle)
*/
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
WifiSettings settings = WifiSettings.getInstance();
outState.putString(SSID_PARAMETER, settings.getSsid());
outState.putString(PASSWORD_PARAMETER, settings.getPassword());
outState.putBoolean(HIDDEN_PARAMETER, settings.isHidden());
outState.putSerializable(SECURITY_PARAMETER, settings.getSecurity());
}
/**
* Ignored
*
......@@ -358,6 +554,16 @@ public final class WifiSettingsFragment extends Fragment implements
}
}
/**
* Initialize the wi fi settings model based on the currently active
* connection, if any
*/
private void getActiveConnection() {
new GetActiveConnectionTask().execute();
}
/**
* Notify {@link #listener} that the wi fi settings habe been changed by the
* user
......@@ -379,4 +585,113 @@ public final class WifiSettingsFragment extends Fragment implements
}
}
/**
* Parse the data passed in the given {@link Intent} at launch
*
* @param intent
* the {@link Intent}
*
* @return <code>true</code> if and only if an asynchronouse attempt to
* connect was launched
*/
private boolean parseIntentData(Intent intent) {
Uri uri = intent.getData();
if (uri != null) {
return parseUri(uri.toString());
}
Parcelable[] ndefMessages = intent
.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if ((ndefMessages != null) && (ndefMessages.length > 0)) {
return parseLegacyMessage((NdefMessage) ndefMessages[0]);
}
return false;
}
/**
* Initialize from a legacy {@link NdefMessage}
*
* Provide backward compatibility for tags written with older versions of
* this app
*
* @param ndefMessage
* legacy {@link NdefMessage}
*
* @return <code>true</code> if and only if an asynchronouse attempt to
* connect was launched
*/
private boolean parseLegacyMessage(NdefMessage ndefMessage) {
try {
NdefRecord[] records = ndefMessage.getRecords();
if (records.length > 0) {
NdefRecord record = records[0];
if (record.getTnf() != NdefRecord.TNF_MIME_MEDIA) {
return false;
}
String type = new String(record.getType(), "US-ASCII"); //$NON-NLS-1$
if ("application/x-wyfy".equals(type)) { //$NON-NLS-1$
String payload = new String(record.getPayload(), "US-ASCII"); //$NON-NLS-1$
return parseUri(payload);
}
}
} catch (Exception e) {
Log.e(getClass().getName(), "initializeNdefMessage", e); //$NON-NLS-1$
}
return false;
}
/**
* Initialize wi fi model state from the given WIFI: {@link Uri}
*
* @param uri
* WIFI: {@link Uri}
*