Home | History | Annotate | Download | only in android
      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 
     62     public MainActivity() {
     63 
     64     }
     65 
     66     @Override
     67     protected void onResume() {
     68         super.onResume();
     69         if (message != null) {
     70             showDialog(message);
     71             message = null;
     72         }
     73     }
     74 
     75     @Override
     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 
    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 
    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 
    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
    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 
    208         public OSUService() {
    209             super("OSUService");
    210         }
    211 
    212         @Override
    213         public int onStartCommand(Intent intent, int flags, int startId) {
    214             onHandleIntent(intent);
    215             return START_STICKY;
    216         }
    217 
    218         @Override
    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
    230         public void onDestroy() {
    231             super.onDestroy();
    232             Log.d("YYY", String.format("Service %x killed", System.identityHashCode(this)));
    233         }
    234 
    235         @Override
    236         public IBinder onBind(Intent intent) {
    237             return mBinder;
    238         }
    239 
    240         @Override
    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 
    304         public List<OSUInfo> getOsuInfos() {
    305             return mOsuManager.getAvailableOSUs();
    306         }
    307 
    308         public void selectOsu(int id) {
    309             mOsuManager.setOSUSelection(id);
    310         }
    311     }
    312 
    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 
    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 
    345     private void cancelNotification() {
    346         NotificationManager notificationManager =
    347                 (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    348         notificationManager.cancel(NOTIFICATION_ID);
    349     }
    350 
    351     private void sendDialogMessage(String message) {
    352 //        sendNotificationMessage(message);
    353         this.message = message;
    354     }
    355 
    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 
    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 
    386         public OsuListAdapter2(Activity activity, List<OSUInfo> osuDataList) {
    387             super(activity, R.layout.list_item, osuDataList);
    388             this.activity = activity;
    389         }
    390 
    391         @Override
    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 
    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