1 package com.android.hotspot2.app; 2 3 import android.app.Activity; 4 import android.app.AlertDialog; 5 import android.app.Notification; 6 import android.app.NotificationManager; 7 import android.app.PendingIntent; 8 import android.app.TaskStackBuilder; 9 import android.content.ComponentName; 10 import android.content.DialogInterface; 11 import android.content.Intent; 12 import android.content.ServiceConnection; 13 import android.graphics.BitmapFactory; 14 import android.graphics.drawable.BitmapDrawable; 15 import android.os.Bundle; 16 import android.os.IBinder; 17 import android.util.Log; 18 import android.view.LayoutInflater; 19 import android.view.View; 20 import android.view.ViewGroup; 21 import android.widget.AdapterView; 22 import android.widget.ArrayAdapter; 23 import android.widget.ImageView; 24 import android.widget.ListView; 25 import android.widget.TextView; 26 27 import com.android.hotspot2.AppBridge; 28 import com.android.hotspot2.R; 29 import com.android.hotspot2.osu.OSUManager; 30 31 import java.util.Collections; 32 import java.util.List; 33 import java.util.concurrent.TimeUnit; 34 35 /** 36 * Main activity. 37 */ 38 public class MainActivity extends Activity { 39 private static final int NOTIFICATION_ID = 0; // Used for OSU count 40 private static final int NOTIFICATION_MESSAGE_ID = 1; // Used for other messages 41 private static final String ACTION_SVC_BOUND = "SVC_BOUND"; 42 43 private volatile OSUService mLocalService; 44 45 private final ServiceConnection mConnection = new ServiceConnection() { 46 @Override 47 public void onServiceConnected(ComponentName name, IBinder service) { 48 LocalServiceBinder binder = (LocalServiceBinder) service; 49 mLocalService = binder.getService(); 50 showOsuSelection(mLocalService); 51 } 52 53 @Override 54 public void onServiceDisconnected(ComponentName name) { 55 mLocalService = null; 56 } 57 }; 58 59 private ListView osuListView; 60 private OsuListAdapter osuListAdapter; 61 private String message; 62 63 public MainActivity() { 64 65 } 66 67 @Override 68 protected void onStop() { 69 super.onStop(); 70 if (mLocalService != null) { 71 unbindService(mConnection); 72 mLocalService = null; 73 } 74 } 75 76 @Override 77 protected void onResume() { 78 super.onResume(); 79 if (message != null) { 80 showDialog(message); 81 message = null; 82 } 83 } 84 85 @Override 86 public void onCreate(Bundle savedInstanceState) { 87 super.onCreate(savedInstanceState); 88 89 final Intent intent = getIntent(); 90 Bundle bundle = intent.getExtras(); 91 92 if (intent.getAction() == null) { 93 if (mLocalService == null) { 94 bindService(new Intent(this, OSUService.class), mConnection, 0); 95 } 96 } else if (intent.getAction().equals(AppBridge.ACTION_OSU_NOTIFICATION)) { 97 if (bundle == null) { 98 Log.d(OSUManager.TAG, "No parameters for OSU notification"); 99 return; 100 } 101 if (bundle.containsKey(AppBridge.OSU_COUNT)) { 102 showOsuCount(bundle.getInt("osu-count", 0), Collections.<OSUData>emptyList()); 103 } else if (bundle.containsKey(AppBridge.PROV_SUCCESS)) { 104 showStatus(bundle.getBoolean(AppBridge.PROV_SUCCESS), 105 bundle.getString(AppBridge.SP_NAME), 106 bundle.getString(AppBridge.PROV_MESSAGE), 107 null); 108 } else if (bundle.containsKey(AppBridge.DEAUTH)) { 109 showDeauth(bundle.getString(AppBridge.SP_NAME), 110 bundle.getBoolean(AppBridge.DEAUTH), 111 bundle.getInt(AppBridge.DEAUTH_DELAY), 112 bundle.getString(AppBridge.DEAUTH_URL)); 113 } 114 } 115 } 116 117 private void showOsuSelection(final OSUService osuService) { 118 List<OSUData> osuData = osuService.getOsuData(); 119 120 setContentView(R.layout.activity_main); 121 Log.d("osu", "osu count:" + osuData.size()); 122 View noOsuView = findViewById(R.id.no_osu); 123 if (osuData.size() > 0) { 124 noOsuView.setVisibility(View.GONE); 125 osuListAdapter = new OsuListAdapter(this, osuData); 126 osuListView = findViewById(R.id.profile_list); 127 osuListView.setAdapter(osuListAdapter); 128 osuListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 129 @Override 130 public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { 131 OSUData osuData = (OSUData) adapterView.getAdapter().getItem(position); 132 Log.d("osu", "launch osu:" + osuData.getName() 133 + " id:" + osuData.getId()); 134 osuService.selectOsu(osuData.getId()); 135 finish(); 136 } 137 }); 138 } else { 139 noOsuView.setVisibility(View.VISIBLE); 140 } 141 } 142 143 private void showOsuCount(int osuCount, List<OSUData> osus) { 144 if (osuCount > 0) { 145 printOsuDataList(osus); 146 sendNotification(osuCount); 147 } else { 148 cancelNotification(); 149 } 150 finish(); 151 } 152 153 private void showStatus(boolean provSuccess, String spName, String provMessage, 154 String remoteStatus) { 155 if (provSuccess) { 156 sendDialogMessage( 157 String.format("Credentials for %s was successfully installed", spName)); 158 } else { 159 if (spName != null) { 160 if (remoteStatus != null) { 161 sendDialogMessage( 162 String.format("Failed to install credentials for %s: %s: %s", 163 spName, provMessage, remoteStatus)); 164 } else { 165 sendDialogMessage( 166 String.format("Failed to install credentials for %s: %s", 167 spName, provMessage)); 168 } 169 } else { 170 sendDialogMessage( 171 String.format("Failed to contact OSU: %s", provMessage)); 172 } 173 } 174 } 175 176 private void showDeauth(String spName, boolean ess, int delay, String url) { 177 String delayReadable = getReadableTimeInSeconds(delay); 178 if (ess) { 179 if (delay > 60) { 180 sendDialogMessage( 181 String.format("There is an issue connecting to %s [for the next %s]. " + 182 "Please visit %s for details", spName, delayReadable, url)); 183 } else { 184 sendDialogMessage( 185 String.format("There is an issue connecting to %s. " + 186 "Please visit %s for details", spName, url)); 187 } 188 } else { 189 sendDialogMessage( 190 String.format("There is an issue with the closest Access Point for %s. " + 191 "You may wait %s or move to another Access Point to " + 192 "regain access. Please visit %s for details.", 193 spName, delayReadable, url)); 194 } 195 } 196 197 private String getReadableTimeInSeconds(int timeSeconds) { 198 long hours = TimeUnit.SECONDS.toHours(timeSeconds); 199 long minutes = TimeUnit.SECONDS.toMinutes(timeSeconds) - TimeUnit.HOURS.toMinutes(hours); 200 long seconds = 201 timeSeconds - TimeUnit.HOURS.toSeconds(hours) - TimeUnit.MINUTES.toSeconds(minutes); 202 if (hours > 0) { 203 return String.format("%02d:%02d:%02d", hours, minutes, seconds); 204 } else { 205 return String.format("%ds", seconds); 206 } 207 } 208 209 private void sendNotification(int count) { 210 Notification.Builder builder = 211 new Notification.Builder(this) 212 .setContentTitle(String.format("%s OSU available", count)) 213 .setContentText("Choose one to connect") 214 .setSmallIcon(android.R.drawable.ic_dialog_info) 215 .setAutoCancel(false); 216 Intent resultIntent = new Intent(this, MainActivity.class); 217 218 TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); 219 stackBuilder.addParentStack(MainActivity.class); 220 stackBuilder.addNextIntent(resultIntent); 221 PendingIntent resultPendingIntent = 222 stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); 223 builder.setContentIntent(resultPendingIntent); 224 NotificationManager notificationManager = 225 (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 226 notificationManager.notify(NOTIFICATION_ID, builder.build()); 227 } 228 229 private void cancelNotification() { 230 NotificationManager notificationManager = 231 (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 232 notificationManager.cancel(NOTIFICATION_ID); 233 } 234 235 private void sendDialogMessage(String message) { 236 // sendNotificationMessage(message); 237 this.message = message; 238 } 239 240 private void showDialog(String message) { 241 AlertDialog.Builder builder = new AlertDialog.Builder(this); 242 builder.setMessage(message) 243 .setTitle("OSU"); 244 builder.setOnCancelListener(new DialogInterface.OnCancelListener() { 245 @Override 246 public void onCancel(DialogInterface dialogInterface) { 247 dialogInterface.cancel(); 248 finish(); 249 } 250 }); 251 AlertDialog dialog = builder.create(); 252 dialog.show(); 253 } 254 255 private void sendNotificationMessage(String title) { 256 Notification.Builder builder = 257 new Notification.Builder(this) 258 .setContentTitle(title) 259 .setContentText("Click to dismiss.") 260 .setSmallIcon(android.R.drawable.ic_dialog_info) 261 .setAutoCancel(true); 262 NotificationManager notificationManager = 263 (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 264 notificationManager.notify(NOTIFICATION_MESSAGE_ID, builder.build()); 265 } 266 267 private static class OsuListAdapter extends ArrayAdapter<OSUData> { 268 private Activity activity; 269 270 public OsuListAdapter(Activity activity, List<OSUData> osuDataList) { 271 super(activity, R.layout.list_item, osuDataList); 272 this.activity = activity; 273 } 274 275 @Override 276 public View getView(int position, View convertView, ViewGroup parent) { 277 View view = convertView; 278 if (view == null) { 279 view = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false); 280 } 281 OSUData osuData = getItem(position); 282 TextView osuName = (TextView) view.findViewById(R.id.profile_name); 283 osuName.setText(osuData.getName()); 284 TextView osuDetail = (TextView) view.findViewById(R.id.profile_detail); 285 osuDetail.setText(osuData.getServiceDescription()); 286 ImageView osuIcon = (ImageView) view.findViewById(R.id.profile_logo); 287 byte[] iconData = osuData.getIconData(); 288 osuIcon.setImageDrawable( 289 new BitmapDrawable(activity.getResources(), 290 BitmapFactory.decodeByteArray(iconData, 0, iconData.length))); 291 return view; 292 } 293 } 294 295 private void printOsuDataList(List<OSUData> osuDataList) { 296 for (OSUData osuData : osuDataList) { 297 Log.d("osu", String.format("OSUData:[%s][%s][%d]", 298 osuData.getName(), osuData.getServiceDescription(), 299 osuData.getId())); 300 } 301 } 302 303 } 304