• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android;
2 
3 import android.app.Activity;
4 import android.app.AlertDialog;
5 import android.app.IntentService;
6 import android.app.Notification;
7 import android.app.NotificationManager;
8 import android.app.PendingIntent;
9 import android.app.TaskStackBuilder;
10 import android.content.BroadcastReceiver;
11 import android.content.Context;
12 import android.content.DialogInterface;
13 import android.content.Intent;
14 import android.graphics.BitmapFactory;
15 import android.graphics.drawable.BitmapDrawable;
16 import android.net.wifi.WifiConfiguration;
17 import android.net.wifi.WifiInfo;
18 import android.net.wifi.WifiManager;
19 import android.os.Binder;
20 import android.os.Bundle;
21 import android.os.IBinder;
22 import android.util.Log;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.widget.AdapterView;
27 import android.widget.ArrayAdapter;
28 import android.widget.ImageView;
29 import android.widget.ListView;
30 import android.widget.TextView;
31 
32 import com.android.anqp.OSUProvider;
33 import com.android.hotspot2.AppBridge;
34 import com.android.hotspot2.PasspointMatch;
35 import com.android.hotspot2.osu.OSUInfo;
36 import com.android.hotspot2.osu.OSUManager;
37 
38 import org.xml.sax.SAXException;
39 
40 import java.io.IOException;
41 import java.util.Collections;
42 import java.util.List;
43 import java.util.Locale;
44 import java.util.concurrent.TimeUnit;
45 
46 //import com.android.Osu.R;
47 
48 /**
49  * Main activity.
50  */
51 public class MainActivity extends Activity {
52     private static final int NOTIFICATION_ID = 0; // Used for OSU count
53     private static final int NOTIFICATION_MESSAGE_ID = 1; // Used for other messages
54     private static final Locale LOCALE = java.util.Locale.getDefault();
55 
56     private static volatile OSUService sOsuService;
57 
58     private ListView osuListView;
59     private OsuListAdapter2 osuListAdapter;
60     private String message;
61 
MainActivity()62     public MainActivity() {
63 
64     }
65 
66     @Override
onResume()67     protected void onResume() {
68         super.onResume();
69         if (message != null) {
70             showDialog(message);
71             message = null;
72         }
73     }
74 
75     @Override
onCreate(Bundle savedInstanceState)76     public void onCreate(Bundle savedInstanceState) {
77         super.onCreate(savedInstanceState);
78 
79         Intent intent = getIntent();
80         Bundle bundle = intent.getExtras();
81 
82         if (bundle == null) {   // User interaction
83             if (sOsuService == null) {
84                 Intent serviceIntent = new Intent(this, OSUService.class);
85                 serviceIntent.putExtra(ACTION_KEY, "dummy-key");
86                 startService(serviceIntent);
87                 return;
88             }
89 
90             List<OSUInfo> osuInfos = sOsuService.getOsuInfos();
91 
92             setContentView(R.layout.activity_main);
93             Log.d("osu", "osu count:" + osuInfos.size());
94             View noOsuView = findViewById(R.id.no_osu);
95             if (osuInfos.size() > 0) {
96                 noOsuView.setVisibility(View.GONE);
97                 osuListAdapter = new OsuListAdapter2(this, osuInfos);
98                 osuListView = (ListView) findViewById(R.id.profile_list);
99                 osuListView.setAdapter(osuListAdapter);
100                 osuListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
101                     @Override
102                     public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
103                         OSUInfo osuData = (OSUInfo) adapterView.getAdapter().getItem(position);
104                         Log.d("osu", "launch osu:" + osuData.getName(LOCALE)
105                                 + " id:" + osuData.getOsuID());
106                         sOsuService.selectOsu(osuData.getOsuID());
107                         finish();
108                     }
109                 });
110             } else {
111                 noOsuView.setVisibility(View.VISIBLE);
112             }
113         } else if (intent.getAction().equals(AppBridge.ACTION_OSU_NOTIFICATION)) {
114             if (bundle.containsKey(AppBridge.OSU_COUNT)) {
115                 showOsuCount(bundle.getInt("osu-count", 0), Collections.<OSUInfo>emptyList());
116             } else if (bundle.containsKey(AppBridge.PROV_SUCCESS)) {
117                 showStatus(bundle.getBoolean(AppBridge.PROV_SUCCESS),
118                         bundle.getString(AppBridge.SP_NAME),
119                         bundle.getString(AppBridge.PROV_MESSAGE),
120                         null);
121             } else if (bundle.containsKey(AppBridge.DEAUTH)) {
122                 showDeauth(bundle.getString(AppBridge.SP_NAME),
123                         bundle.getBoolean(AppBridge.DEAUTH),
124                         bundle.getInt(AppBridge.DEAUTH_DELAY),
125                         bundle.getString(AppBridge.DEAUTH_URL));
126             }
127             /*
128             else if (bundle.containsKey(AppBridge.OSU_INFO)) {
129                 List<OsuData> osus = printOsuDataList(bundle.getParcelableArray(AppBridge.OSU_INFO));
130                 showOsuList(osus);
131             }
132             */
133         }
134     }
135 
showOsuCount(int osuCount, List<OSUInfo> osus)136     private void showOsuCount(int osuCount, List<OSUInfo> osus) {
137         if (osuCount > 0) {
138             printOsuDataList(osus);
139             sendNotification(osuCount);
140         } else {
141             cancelNotification();
142         }
143         finish();
144     }
145 
showStatus(boolean provSuccess, String spName, String provMessage, String remoteStatus)146     private void showStatus(boolean provSuccess, String spName, String provMessage,
147                             String remoteStatus) {
148         if (provSuccess) {
149             sendDialogMessage(
150                     String.format("Credentials for %s was successfully installed", spName));
151         } else {
152             if (spName != null) {
153                 if (remoteStatus != null) {
154                     sendDialogMessage(
155                             String.format("Failed to install credentials for %s: %s: %s",
156                                     spName, provMessage, remoteStatus));
157                 } else {
158                     sendDialogMessage(
159                             String.format("Failed to install credentials for %s: %s",
160                                     spName, provMessage));
161                 }
162             } else {
163                 sendDialogMessage(
164                         String.format("Failed to contact OSU: %s", provMessage));
165             }
166         }
167     }
168 
showDeauth(String spName, boolean ess, int delay, String url)169     private void showDeauth(String spName, boolean ess, int delay, String url) {
170         String delayReadable = getReadableTimeInSeconds(delay);
171         if (ess) {
172             if (delay > 60) {
173                 sendDialogMessage(
174                         String.format("There is an issue connecting to %s [for the next %s]. " +
175                                 "Please visit %s for details", spName, delayReadable, url));
176             } else {
177                 sendDialogMessage(
178                         String.format("There is an issue connecting to %s. " +
179                                 "Please visit %s for details", spName, url));
180             }
181         } else {
182             sendDialogMessage(
183                     String.format("There is an issue with the closest Access Point for %s. " +
184                                     "You may wait %s or move to another Access Point to " +
185                                     "regain access. Please visit %s for details.",
186                             spName, delayReadable, url));
187         }
188     }
189 
190     private static final String ACTION_KEY = "action";
191 
192     public static class WifiReceiver extends BroadcastReceiver {
193         @Override
onReceive(Context c, Intent intent)194         public void onReceive(Context c, Intent intent) {
195             Log.d(OSUManager.TAG, "OSU App got intent: " + intent.getAction());
196             Intent serviceIntent;
197             serviceIntent = new Intent(c, OSUService.class);
198             serviceIntent.putExtra(ACTION_KEY, intent.getAction());
199             serviceIntent.putExtras(intent);
200             c.startService(serviceIntent);
201         }
202     }
203 
204     public static class OSUService extends IntentService {
205         private OSUManager mOsuManager;
206         private final IBinder mBinder = new Binder();
207 
OSUService()208         public OSUService() {
209             super("OSUService");
210         }
211 
212         @Override
onStartCommand(Intent intent, int flags, int startId)213         public int onStartCommand(Intent intent, int flags, int startId) {
214             onHandleIntent(intent);
215             return START_STICKY;
216         }
217 
218         @Override
onCreate()219         public void onCreate() {
220             super.onCreate();
221             Log.d("YYY", String.format("Service %x running, OSU %x",
222                     System.identityHashCode(this), System.identityHashCode(mOsuManager)));
223             if (mOsuManager == null) {
224                 mOsuManager = new OSUManager(this);
225             }
226             sOsuService = this;
227         }
228 
229         @Override
onDestroy()230         public void onDestroy() {
231             super.onDestroy();
232             Log.d("YYY", String.format("Service %x killed", System.identityHashCode(this)));
233         }
234 
235         @Override
onBind(Intent intent)236         public IBinder onBind(Intent intent) {
237             return mBinder;
238         }
239 
240         @Override
onHandleIntent(Intent intent)241         protected void onHandleIntent(Intent intent) {
242             Bundle bundle = intent.getExtras();
243             WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
244             Log.d(OSUManager.TAG, "OSU Service got intent: " + intent.getStringExtra(ACTION_KEY));
245             switch (intent.getStringExtra(ACTION_KEY)) {
246                 case WifiManager.SCAN_RESULTS_AVAILABLE_ACTION:
247                     mOsuManager.pushScanResults(wifiManager.getScanResults());
248                     break;
249                 case WifiManager.PASSPOINT_WNM_FRAME_RECEIVED_ACTION:
250                     long bssid = bundle.getLong(WifiManager.EXTRA_PASSPOINT_WNM_BSSID);
251                     String url = bundle.getString(WifiManager.EXTRA_PASSPOINT_WNM_URL);
252 
253                     try {
254                         if (bundle.containsKey(WifiManager.EXTRA_PASSPOINT_WNM_METHOD)) {
255                             int method = bundle.getInt(WifiManager.EXTRA_PASSPOINT_WNM_METHOD);
256                             if (method != OSUProvider.OSUMethod.SoapXml.ordinal()) {
257                                 Log.w(OSUManager.TAG, "Unsupported remediation method: " + method);
258                             }
259                             PasspointMatch match = null;
260                             if (bundle.containsKey(WifiManager.EXTRA_PASSPOINT_WNM_PPOINT_MATCH)) {
261                                 int ordinal =
262                                         bundle.getInt(WifiManager.EXTRA_PASSPOINT_WNM_PPOINT_MATCH);
263                                 if (ordinal >= 0 && ordinal < PasspointMatch.values().length) {
264                                     match = PasspointMatch.values()[ordinal];
265                                 }
266                             }
267                             mOsuManager.wnmRemediate(bssid, url, match);
268                         } else if (bundle.containsKey(WifiManager.EXTRA_PASSPOINT_WNM_ESS)) {
269                             boolean ess = bundle.getBoolean(WifiManager.EXTRA_PASSPOINT_WNM_ESS);
270                             int delay = bundle.getInt(WifiManager.EXTRA_PASSPOINT_WNM_DELAY);
271                             mOsuManager.deauth(bssid, ess, delay, url);
272                         } else {
273                             Log.w(OSUManager.TAG, "Unknown WNM event");
274                         }
275                     } catch (IOException | SAXException e) {
276                         Log.w(OSUManager.TAG, "Remediation event failed to parse: " + e);
277                     }
278                     break;
279                 case WifiManager.PASSPOINT_ICON_RECEIVED_ACTION:
280                     mOsuManager.notifyIconReceived(
281                             bundle.getLong(WifiManager.EXTRA_PASSPOINT_ICON_BSSID),
282                             bundle.getString(WifiManager.EXTRA_PASSPOINT_ICON_FILE),
283                             bundle.getByteArray(WifiManager.EXTRA_PASSPOINT_ICON_DATA));
284                     break;
285                 case WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION:
286                     mOsuManager.networkConfigChange((WifiConfiguration)
287                             intent.getParcelableExtra(WifiManager.EXTRA_WIFI_CONFIGURATION));
288                     break;
289                 case WifiManager.WIFI_STATE_CHANGED_ACTION:
290                     int state = bundle.getInt(WifiManager.EXTRA_WIFI_STATE);
291                     if (state == WifiManager.WIFI_STATE_DISABLED) {
292                         mOsuManager.wifiStateChange(false);
293                     } else if (state == WifiManager.WIFI_STATE_ENABLED) {
294                         mOsuManager.wifiStateChange(true);
295                     }
296                     break;
297                 case WifiManager.NETWORK_STATE_CHANGED_ACTION:
298                     mOsuManager.networkConnectEvent((WifiInfo)
299                             intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO));
300                     break;
301             }
302         }
303 
getOsuInfos()304         public List<OSUInfo> getOsuInfos() {
305             return mOsuManager.getAvailableOSUs();
306         }
307 
selectOsu(int id)308         public void selectOsu(int id) {
309             mOsuManager.setOSUSelection(id);
310         }
311     }
312 
getReadableTimeInSeconds(int timeSeconds)313     private String getReadableTimeInSeconds(int timeSeconds) {
314         long hours = TimeUnit.SECONDS.toHours(timeSeconds);
315         long minutes = TimeUnit.SECONDS.toMinutes(timeSeconds) - TimeUnit.HOURS.toMinutes(hours);
316         long seconds =
317                 timeSeconds - TimeUnit.HOURS.toSeconds(hours) - TimeUnit.MINUTES.toSeconds(minutes);
318         if (hours > 0) {
319             return String.format("%02d:%02d:%02d", hours, minutes, seconds);
320         } else {
321             return String.format("%ds", seconds);
322         }
323     }
324 
sendNotification(int count)325     private void sendNotification(int count) {
326         Notification.Builder builder =
327                 new Notification.Builder(this)
328                         .setContentTitle(String.format("%s OSU available", count))
329                         .setContentText("Choose one to connect")
330                         .setSmallIcon(android.R.drawable.ic_dialog_info)
331                         .setAutoCancel(false);
332         Intent resultIntent = new Intent(this, MainActivity.class);
333 
334         TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
335         stackBuilder.addParentStack(MainActivity.class);
336         stackBuilder.addNextIntent(resultIntent);
337         PendingIntent resultPendingIntent =
338                 stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
339         builder.setContentIntent(resultPendingIntent);
340         NotificationManager notificationManager =
341                 (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
342         notificationManager.notify(NOTIFICATION_ID, builder.build());
343     }
344 
cancelNotification()345     private void cancelNotification() {
346         NotificationManager notificationManager =
347                 (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
348         notificationManager.cancel(NOTIFICATION_ID);
349     }
350 
sendDialogMessage(String message)351     private void sendDialogMessage(String message) {
352 //        sendNotificationMessage(message);
353         this.message = message;
354     }
355 
showDialog(String message)356     private void showDialog(String message) {
357         AlertDialog.Builder builder = new AlertDialog.Builder(this);
358         builder.setMessage(message)
359                 .setTitle("OSU");
360         builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
361             @Override
362             public void onCancel(DialogInterface dialogInterface) {
363                 dialogInterface.cancel();
364                 finish();
365             }
366         });
367         AlertDialog dialog = builder.create();
368         dialog.show();
369     }
370 
sendNotificationMessage(String title)371     private void sendNotificationMessage(String title) {
372         Notification.Builder builder =
373                 new Notification.Builder(this)
374                         .setContentTitle(title)
375                         .setContentText("Click to dismiss.")
376                         .setSmallIcon(android.R.drawable.ic_dialog_info)
377                         .setAutoCancel(true);
378         NotificationManager notificationManager =
379                 (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
380         notificationManager.notify(NOTIFICATION_MESSAGE_ID, builder.build());
381     }
382 
383     private static class OsuListAdapter2 extends ArrayAdapter<OSUInfo> {
384         private Activity activity;
385 
OsuListAdapter2(Activity activity, List<OSUInfo> osuDataList)386         public OsuListAdapter2(Activity activity, List<OSUInfo> osuDataList) {
387             super(activity, R.layout.list_item, osuDataList);
388             this.activity = activity;
389         }
390 
391         @Override
getView(int position, View convertView, ViewGroup parent)392         public View getView(int position, View convertView, ViewGroup parent) {
393             View view = convertView;
394             if (view == null) {
395                 view = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false);
396             }
397             OSUInfo osuData = getItem(position);
398             TextView osuName = (TextView) view.findViewById(R.id.profile_name);
399             osuName.setText(osuData.getName(LOCALE));
400             TextView osuDetail = (TextView) view.findViewById(R.id.profile_detail);
401             osuDetail.setText(osuData.getServiceDescription(LOCALE));
402             ImageView osuIcon = (ImageView) view.findViewById(R.id.profile_logo);
403             byte[] iconData = osuData.getIconFileElement().getIconData();
404             osuIcon.setImageDrawable(
405                     new BitmapDrawable(activity.getResources(),
406                             BitmapFactory.decodeByteArray(iconData, 0, iconData.length)));
407             return view;
408         }
409     }
410 
printOsuDataList(List<OSUInfo> osuDataList)411     private void printOsuDataList(List<OSUInfo> osuDataList) {
412         for (OSUInfo osuData : osuDataList) {
413             Log.d("osu", String.format("OSUData:[%s][%s][%d]",
414                     osuData.getName(LOCALE), osuData.getServiceDescription(LOCALE),
415                     osuData.getOsuID()));
416         }
417     }
418 
419 }
420