blob: 7e7d49af631ac5534ce705f7f9c3f9e0648af6c9 [file] [log] [blame]
package com.android;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.android.anqp.OSUProvider;
import com.android.hotspot2.AppBridge;
import com.android.hotspot2.PasspointMatch;
import com.android.hotspot2.osu.OSUInfo;
import com.android.hotspot2.osu.OSUManager;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
//import com.android.Osu.R;
/**
* Main activity.
*/
public class MainActivity extends Activity {
private static final int NOTIFICATION_ID = 0; // Used for OSU count
private static final int NOTIFICATION_MESSAGE_ID = 1; // Used for other messages
private static final Locale LOCALE = java.util.Locale.getDefault();
private static volatile OSUService sOsuService;
private ListView osuListView;
private OsuListAdapter2 osuListAdapter;
private String message;
public MainActivity() {
}
@Override
protected void onResume() {
super.onResume();
if (message != null) {
showDialog(message);
message = null;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
if (bundle == null) { // User interaction
if (sOsuService == null) {
Intent serviceIntent = new Intent(this, OSUService.class);
serviceIntent.putExtra(ACTION_KEY, "dummy-key");
startService(serviceIntent);
return;
}
List<OSUInfo> osuInfos = sOsuService.getOsuInfos();
setContentView(R.layout.activity_main);
Log.d("osu", "osu count:" + osuInfos.size());
View noOsuView = findViewById(R.id.no_osu);
if (osuInfos.size() > 0) {
noOsuView.setVisibility(View.GONE);
osuListAdapter = new OsuListAdapter2(this, osuInfos);
osuListView = (ListView) findViewById(R.id.profile_list);
osuListView.setAdapter(osuListAdapter);
osuListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
OSUInfo osuData = (OSUInfo) adapterView.getAdapter().getItem(position);
Log.d("osu", "launch osu:" + osuData.getName(LOCALE)
+ " id:" + osuData.getOsuID());
sOsuService.selectOsu(osuData.getOsuID());
finish();
}
});
} else {
noOsuView.setVisibility(View.VISIBLE);
}
} else if (intent.getAction().equals(AppBridge.ACTION_OSU_NOTIFICATION)) {
if (bundle.containsKey(AppBridge.OSU_COUNT)) {
showOsuCount(bundle.getInt("osu-count", 0), Collections.<OSUInfo>emptyList());
} else if (bundle.containsKey(AppBridge.PROV_SUCCESS)) {
showStatus(bundle.getBoolean(AppBridge.PROV_SUCCESS),
bundle.getString(AppBridge.SP_NAME),
bundle.getString(AppBridge.PROV_MESSAGE),
null);
} else if (bundle.containsKey(AppBridge.DEAUTH)) {
showDeauth(bundle.getString(AppBridge.SP_NAME),
bundle.getBoolean(AppBridge.DEAUTH),
bundle.getInt(AppBridge.DEAUTH_DELAY),
bundle.getString(AppBridge.DEAUTH_URL));
}
/*
else if (bundle.containsKey(AppBridge.OSU_INFO)) {
List<OsuData> osus = printOsuDataList(bundle.getParcelableArray(AppBridge.OSU_INFO));
showOsuList(osus);
}
*/
}
}
private void showOsuCount(int osuCount, List<OSUInfo> osus) {
if (osuCount > 0) {
printOsuDataList(osus);
sendNotification(osuCount);
} else {
cancelNotification();
}
finish();
}
private void showStatus(boolean provSuccess, String spName, String provMessage,
String remoteStatus) {
if (provSuccess) {
sendDialogMessage(
String.format("Credentials for %s was successfully installed", spName));
} else {
if (spName != null) {
if (remoteStatus != null) {
sendDialogMessage(
String.format("Failed to install credentials for %s: %s: %s",
spName, provMessage, remoteStatus));
} else {
sendDialogMessage(
String.format("Failed to install credentials for %s: %s",
spName, provMessage));
}
} else {
sendDialogMessage(
String.format("Failed to contact OSU: %s", provMessage));
}
}
}
private void showDeauth(String spName, boolean ess, int delay, String url) {
String delayReadable = getReadableTimeInSeconds(delay);
if (ess) {
if (delay > 60) {
sendDialogMessage(
String.format("There is an issue connecting to %s [for the next %s]. " +
"Please visit %s for details", spName, delayReadable, url));
} else {
sendDialogMessage(
String.format("There is an issue connecting to %s. " +
"Please visit %s for details", spName, url));
}
} else {
sendDialogMessage(
String.format("There is an issue with the closest Access Point for %s. " +
"You may wait %s or move to another Access Point to " +
"regain access. Please visit %s for details.",
spName, delayReadable, url));
}
}
private static final String ACTION_KEY = "action";
public static class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent intent) {
Log.d(OSUManager.TAG, "OSU App got intent: " + intent.getAction());
Intent serviceIntent;
serviceIntent = new Intent(c, OSUService.class);
serviceIntent.putExtra(ACTION_KEY, intent.getAction());
serviceIntent.putExtras(intent);
c.startService(serviceIntent);
}
}
public static class OSUService extends IntentService {
private OSUManager mOsuManager;
private final IBinder mBinder = new Binder();
public OSUService() {
super("OSUService");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onHandleIntent(intent);
return START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
Log.d("YYY", String.format("Service %x running, OSU %x",
System.identityHashCode(this), System.identityHashCode(mOsuManager)));
if (mOsuManager == null) {
mOsuManager = new OSUManager(this);
}
sOsuService = this;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("YYY", String.format("Service %x killed", System.identityHashCode(this)));
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
protected void onHandleIntent(Intent intent) {
Bundle bundle = intent.getExtras();
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Log.d(OSUManager.TAG, "OSU Service got intent: " + intent.getStringExtra(ACTION_KEY));
switch (intent.getStringExtra(ACTION_KEY)) {
case WifiManager.SCAN_RESULTS_AVAILABLE_ACTION:
mOsuManager.pushScanResults(wifiManager.getScanResults());
break;
case WifiManager.PASSPOINT_WNM_FRAME_RECEIVED_ACTION:
long bssid = bundle.getLong(WifiManager.EXTRA_PASSPOINT_WNM_BSSID);
String url = bundle.getString(WifiManager.EXTRA_PASSPOINT_WNM_URL);
try {
if (bundle.containsKey(WifiManager.EXTRA_PASSPOINT_WNM_METHOD)) {
int method = bundle.getInt(WifiManager.EXTRA_PASSPOINT_WNM_METHOD);
if (method != OSUProvider.OSUMethod.SoapXml.ordinal()) {
Log.w(OSUManager.TAG, "Unsupported remediation method: " + method);
}
PasspointMatch match = null;
if (bundle.containsKey(WifiManager.EXTRA_PASSPOINT_WNM_PPOINT_MATCH)) {
int ordinal =
bundle.getInt(WifiManager.EXTRA_PASSPOINT_WNM_PPOINT_MATCH);
if (ordinal >= 0 && ordinal < PasspointMatch.values().length) {
match = PasspointMatch.values()[ordinal];
}
}
mOsuManager.wnmRemediate(bssid, url, match);
} else if (bundle.containsKey(WifiManager.EXTRA_PASSPOINT_WNM_ESS)) {
boolean ess = bundle.getBoolean(WifiManager.EXTRA_PASSPOINT_WNM_ESS);
int delay = bundle.getInt(WifiManager.EXTRA_PASSPOINT_WNM_DELAY);
mOsuManager.deauth(bssid, ess, delay, url);
} else {
Log.w(OSUManager.TAG, "Unknown WNM event");
}
} catch (IOException | SAXException e) {
Log.w(OSUManager.TAG, "Remediation event failed to parse: " + e);
}
break;
case WifiManager.PASSPOINT_ICON_RECEIVED_ACTION:
mOsuManager.notifyIconReceived(
bundle.getLong(WifiManager.EXTRA_PASSPOINT_ICON_BSSID),
bundle.getString(WifiManager.EXTRA_PASSPOINT_ICON_FILE),
bundle.getByteArray(WifiManager.EXTRA_PASSPOINT_ICON_DATA));
break;
case WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION:
mOsuManager.networkConfigChange((WifiConfiguration)
intent.getParcelableExtra(WifiManager.EXTRA_WIFI_CONFIGURATION));
break;
case WifiManager.WIFI_STATE_CHANGED_ACTION:
int state = bundle.getInt(WifiManager.EXTRA_WIFI_STATE);
if (state == WifiManager.WIFI_STATE_DISABLED) {
mOsuManager.wifiStateChange(false);
} else if (state == WifiManager.WIFI_STATE_ENABLED) {
mOsuManager.wifiStateChange(true);
}
break;
case WifiManager.NETWORK_STATE_CHANGED_ACTION:
mOsuManager.networkConnectEvent((WifiInfo)
intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO));
break;
}
}
public List<OSUInfo> getOsuInfos() {
return mOsuManager.getAvailableOSUs();
}
public void selectOsu(int id) {
mOsuManager.setOSUSelection(id);
}
}
private String getReadableTimeInSeconds(int timeSeconds) {
long hours = TimeUnit.SECONDS.toHours(timeSeconds);
long minutes = TimeUnit.SECONDS.toMinutes(timeSeconds) - TimeUnit.HOURS.toMinutes(hours);
long seconds =
timeSeconds - TimeUnit.HOURS.toSeconds(hours) - TimeUnit.MINUTES.toSeconds(minutes);
if (hours > 0) {
return String.format("%02d:%02d:%02d", hours, minutes, seconds);
} else {
return String.format("%ds", seconds);
}
}
private void sendNotification(int count) {
Notification.Builder builder =
new Notification.Builder(this)
.setContentTitle(String.format("%s OSU available", count))
.setContentText("Choose one to connect")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setAutoCancel(false);
Intent resultIntent = new Intent(this, MainActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
private void cancelNotification() {
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION_ID);
}
private void sendDialogMessage(String message) {
// sendNotificationMessage(message);
this.message = message;
}
private void showDialog(String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(message)
.setTitle("OSU");
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
dialogInterface.cancel();
finish();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
private void sendNotificationMessage(String title) {
Notification.Builder builder =
new Notification.Builder(this)
.setContentTitle(title)
.setContentText("Click to dismiss.")
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setAutoCancel(true);
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_MESSAGE_ID, builder.build());
}
private static class OsuListAdapter2 extends ArrayAdapter<OSUInfo> {
private Activity activity;
public OsuListAdapter2(Activity activity, List<OSUInfo> osuDataList) {
super(activity, R.layout.list_item, osuDataList);
this.activity = activity;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
view = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false);
}
OSUInfo osuData = getItem(position);
TextView osuName = (TextView) view.findViewById(R.id.profile_name);
osuName.setText(osuData.getName(LOCALE));
TextView osuDetail = (TextView) view.findViewById(R.id.profile_detail);
osuDetail.setText(osuData.getServiceDescription(LOCALE));
ImageView osuIcon = (ImageView) view.findViewById(R.id.profile_logo);
byte[] iconData = osuData.getIconFileElement().getIconData();
osuIcon.setImageDrawable(
new BitmapDrawable(activity.getResources(),
BitmapFactory.decodeByteArray(iconData, 0, iconData.length)));
return view;
}
}
private void printOsuDataList(List<OSUInfo> osuDataList) {
for (OSUInfo osuData : osuDataList) {
Log.d("osu", String.format("OSUData:[%s][%s][%d]",
osuData.getName(LOCALE), osuData.getServiceDescription(LOCALE),
osuData.getOsuID()));
}
}
}