/*
* Copyright (C) 2013 Sasha Vasko <sasha at aftercode dot net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wifiafterconnect;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.Set;
import com.wifiafterconnect.URLRedirectChecker.AuthorizationType;
import com.wifiafterconnect.util.WifiTools;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.ToggleButton;
public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor> {
private SimpleCursorAdapter adapter;
private ListView lvRememberedSites;
private Button deleteSelected;
private WifiAuthDatabase wifiDb = null;
private WifiTools wifiTools = null;
private ToggleButton toggleWifi;
private Button buttonAuthenticateNow;
public enum InternetStatus { UNKNOWN, CHECKING, ONLINE, OFFLINE };
public InternetStatus inetStatus = InternetStatus.UNKNOWN;
private TextView inetStatusInd;
private WifiBroadcastReceiver receiverWifiConnect = null;
public class RedirectCheckerTask extends AsyncTask<Context, Void, Boolean> {
@Override
protected void onPostExecute(Boolean result) {
setInternetStatus (result ? InternetStatus.ONLINE : InternetStatus.OFFLINE);
setAuthenticateNowEnabled();
}
public URLRedirectChecker configureChecker (URLRedirectChecker checker) {
return checker;
}
@Override
protected Boolean doInBackground(Context... params) {
URLRedirectChecker checker = configureChecker (new URLRedirectChecker (Constants.TAG, params[0]));
return checker.checkHttpConnection ();
}
}
public class RunAuthTask extends RedirectCheckerTask {
@Override
public URLRedirectChecker configureChecker (URLRedirectChecker checker) {
checker.setSaveLogFile (null);
return checker;
}
}
public class CheckOnlineAuthTask extends RedirectCheckerTask {
@Override
public URLRedirectChecker configureChecker (URLRedirectChecker checker) {
checker.setDefaultType (AuthorizationType.None);
return checker;
}
}
private void setInternetStatus (InternetStatus status) {
if (inetStatus != status) {
inetStatus = status;
if (inetStatusInd != null) {
switch (status) {
case ONLINE :
inetStatusInd.setText(R.string.label_available);
inetStatusInd.setTextColor(getResources().getColor(android.R.color.holo_green_dark));
break;
case OFFLINE :
inetStatusInd.setText(R.string.label_unavailable);
inetStatusInd.setTextColor(getResources().getColor(android.R.color.holo_red_dark));
break;
case UNKNOWN :
checkInetOnline ();
default :
inetStatusInd.setText(R.string.label_inet_checking);
inetStatusInd.setTextColor(getResources().getColor(android.R.color.holo_orange_dark));
}
}
}
}
public boolean checkInetOnline () {
if (inetStatus == InternetStatus.UNKNOWN) {
setInternetStatus (InternetStatus.CHECKING);
//Log.d(Constants.TAG, "starting CheckOnlineAuthTask task");
CheckOnlineAuthTask task = new CheckOnlineAuthTask();
task.execute(this);
}
return (inetStatus == InternetStatus.ONLINE);
}
private void setAuthenticateNowEnabled (boolean enabled, int disabledLabelId) {
if (buttonAuthenticateNow != null) {
buttonAuthenticateNow.setEnabled(enabled);
buttonAuthenticateNow.setText(disabledLabelId);
}
}
private void setAuthenticateNowEnabled () {
if (!wifiTools.isWifiConnected())
setAuthenticateNowEnabled (false, R.string.auth_now_disabled_label);
else {
if (checkInetOnline()) // must be the first call as it changes the status
setAuthenticateNowEnabled (false, R.string.auth_now_online_label);
else if (inetStatus == InternetStatus.UNKNOWN
|| inetStatus == InternetStatus.CHECKING)
setAuthenticateNowEnabled (false, R.string.auth_now_checking_label);
else
setAuthenticateNowEnabled (true, R.string.auth_now_label);
}
}
public void onAuthenticateNowClick(View v) {
if (wifiTools.isWifiConnected()) {
setAuthenticateNowEnabled(false, R.string.auth_now_inprocess_label);
RunAuthTask task = new RunAuthTask();
task.execute(getBaseContext());
}
}
public void onWifiToggle(View v) {
CompoundButton btn = (CompoundButton)v;
wifiTools.setWifiEnabled(btn.isChecked());
if (!btn.isChecked())
setAuthenticateNowEnabled(false, R.string.auth_now_disabled_label);;
}
public void onBakcgroundAuthEnabledToggle(View v) {
CompoundButton btn = (CompoundButton)v;
WifiBroadcastReceiver.setEnabled(this, btn.isChecked());
}
private Set<Long> selectedSiteIds = Collections.synchronizedSet(new HashSet<Long>());
private Long lastSelectedSiteId = -1L;
private class DeleteAndUpdateCursorTask extends AsyncTask<Void, Void, Cursor> {
protected void onPostExecute(Cursor result) {
adapter.changeCursor(result);
deleteSelected.setEnabled(false);
}
@Override
protected Cursor doInBackground(Void... params) {
try {
for (long id : selectedSiteIds)
wifiDb.deleteSite (id);
}catch(ConcurrentModificationException e){}
selectedSiteIds.clear();
Cursor result = wifiDb.getWifiTableCursor (new String[] {WifiAuthDatabase.COLUMN_ID,WifiAuthDatabase.COLUMN_HOSTNAME}, (String)null);
return result;
}
}
public void onDeleteSelectedClick(View v) {
DeleteAndUpdateCursorTask delTask = new DeleteAndUpdateCursorTask();
delTask.execute();
}
public void onEditCredentialsClick (View v) {
if (!selectedSiteIds.contains(lastSelectedSiteId))
return;
Intent intent = new Intent(this, EditCredentialsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra (WifiAuthenticator.OPTION_SITE_ID, lastSelectedSiteId);
startActivity (intent);
}
public void onSettingsClick(View v) {
startActivity (new Intent(this, SettingsActivity.class));
}
public class WifiSitesCursorAdapter extends SimpleCursorAdapter {
public class CheckBoxViewBinder implements SimpleCursorAdapter.ViewBinder {
@Override
public boolean setViewValue(View v, Cursor cursor, int field) {
if (v instanceof CheckBox) {
CheckBox cb = (CheckBox)v;
long id = cursor.getLong(0);
//Log.d(Constants.TAG, " site id = [" + id + "]");
cb.setTag(Long.valueOf(id));
if (field != 0) {
String val = cursor.getString(field);
cb.setChecked(val!=null && val.equalsIgnoreCase("true"));
}
return true;
} else if (v instanceof TextView) {
String val = cursor.getString(field);
//Log.d(Constants.TAG, "displaying site [" + val + "]");
setViewText((TextView)v, val);
return true;
}
return false;
}
}
public WifiSitesCursorAdapter(Context context) {
super(context, R.layout.sites_list_item, null,
new String[] {WifiAuthDatabase.COLUMN_ID, WifiAuthDatabase.COLUMN_HOSTNAME},
new int[] {R.id.checkSelected, R.id.textSiteHost}, 0);
setViewBinder (new CheckBoxViewBinder());
}
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
if (v != null) {
CheckBox cb = (CheckBox)v.findViewById (R.id.checkSelected);
if (cb != null) {
cb.setOnCheckedChangeListener(new OnCheckedChangeListener ()
{@Override public void onCheckedChanged(CompoundButton view, boolean isChecked) {
Long id = (Long)view.getTag();
lastSelectedSiteId = id;
if (isChecked)
selectedSiteIds.add(id);
else
selectedSiteIds.remove(id);
deleteSelected.setEnabled(!selectedSiteIds.isEmpty());
}
});
}
}
return v;
}
}
protected void refreshStatusIndicators () {
/*
ToggleButton toggleBackAuth = (ToggleButton) findViewById(R.id.toggleEnableWifiAfterconnect);
if (toggleBackAuth != null)
toggleBackAuth.setChecked(WifiBroadcastReceiver.isEnabled(this));
*/
if (wifiTools != null) {
boolean enabled = wifiTools.isWifiEnabled();
//if (!enabled || !wifiTools.isWifiConnected())
setInternetStatus (InternetStatus.UNKNOWN);
setAuthenticateNowEnabled();
if (toggleWifi != null)
toggleWifi.setChecked(enabled);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancelAll();
wifiTools = WifiTools.getInstance(this);
if (getIntent().getAction().equals(getString(R.string.action_reenable_wifi))) {
wifiTools.enableWifi();
finish();
return;
}
setContentView(R.layout.main_activity);
toggleWifi = (ToggleButton) findViewById(R.id.toggleWifi);
// toggleWifi.setEnabled(checkCallingOrSelfPermission("android.permission.CHANGE_NETWORK_STATE")
// == PackageManager.PERMISSION_GRANTED);
buttonAuthenticateNow = (Button) findViewById(R.id.buttonAuthenticateNow);
lvRememberedSites = (ListView) findViewById(R.id.listKnownSites);
deleteSelected = (Button)findViewById (R.id.buttonDeleteSelected);
inetStatusInd = (TextView)findViewById (R.id.textInetStatusInd);
// Create an empty adapter we will use to display the loaded data.
// We pass null for the cursor, then update it in onLoadFinished()
adapter = new WifiSitesCursorAdapter(this);
lvRememberedSites.setAdapter(adapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getSupportLoaderManager().initLoader(0, null, this);
// WE would really like to keep track of connectivity state so that our buttons
// reflect the state correctly
IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
receiverWifiConnect = new WifiBroadcastReceiver(){
@Override
public void onWifiConnectivityChange(Context context, boolean connected) {
refreshStatusIndicators ();
}
};
registerReceiver(receiverWifiConnect, intentFilter);
// finally let us check if the device is connected to Internet presently
checkInetOnline ();
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
adapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
adapter.swapCursor(null);
}
public static class WifiSitesCursorLoader extends AsyncTaskLoader<Cursor> {
WifiAuthDatabase wifiDb = null;
Cursor cursor;
public WifiSitesCursorLoader(Context context, WifiAuthDatabase wifiDb) {
super(context);
this.wifiDb = wifiDb;
}
@Override
public Cursor loadInBackground() {
Cursor c = wifiDb.getWifiTableCursor (new String[] {WifiAuthDatabase.COLUMN_ID,WifiAuthDatabase.COLUMN_HOSTNAME}, (String)null);
if (c != null) {
int count = c.getCount();
Log.d(Constants.TAG, "Loaded " + count + " known sites");
}else {
Log.d(Constants.TAG, "Cursor = null loading known sites");
}
return c;
}
/* Runs on the UI thread */
@Override
public void deliverResult(Cursor cursor) {
if (isReset()) {
// An async query came in while the loader is stopped
if (cursor != null) {
cursor.close();
}
return;
}
Cursor oldCursor = this.cursor;
this.cursor = cursor;
if (isStarted()) {
super.deliverResult(cursor);
}
if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
oldCursor.close();
}
}
/**
* Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
* will be called on the UI thread. If a previous load has been completed and is still valid
* the result may be passed to the callbacks immediately.
*
* Must be called from the UI thread
*/
@Override
protected void onStartLoading() {
if (cursor != null) {
deliverResult(cursor);
}
if (takeContentChanged() || cursor == null) {
forceLoad();
}
}
/**
* Must be called from the UI thread
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
@Override
public void onCanceled(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
cursor = null;
}
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
wifiDb = WifiAuthDatabase.getInstance(this);
return new WifiSitesCursorLoader(this, wifiDb);
// return new CursorLoader(this, WifiAuthContent.CONTENT_URI, new String[] {WifiAuthDatabase.COLUMN_ID,WifiAuthDatabase.COLUMN_HOSTNAME}, null, null, null);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.settings, menu);
return true;
}
@Override
public boolean onOptionsItemSelected (MenuItem item) {
if (item.getItemId() == R.id.action_settings) {
startActivity (new Intent(this, SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
unregisterReceiver (receiverWifiConnect);
} catch(IllegalArgumentException e) {}
}
@Override
protected void onResume() {
super.onResume();
refreshStatusIndicators ();
getSupportLoaderManager().restartLoader(0, null, this);
}
}