1 package com.android.certinstaller; 2 3 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; 4 5 import android.app.Activity; 6 import android.app.AlertDialog; 7 import android.content.Context; 8 import android.content.DialogInterface; 9 import android.content.Intent; 10 import android.content.res.Resources; 11 import android.net.Uri; 12 import android.net.wifi.WifiManager; 13 import android.net.wifi.hotspot2.ConfigParser; 14 import android.net.wifi.hotspot2.PasspointConfiguration; 15 import android.os.AsyncTask; 16 import android.os.Bundle; 17 import android.provider.DocumentsContract; 18 import android.text.TextUtils; 19 import android.util.EventLog; 20 import android.util.Log; 21 import android.view.View; 22 import android.widget.TextView; 23 import android.widget.Toast; 24 25 /** 26 * An Activity for provisioning a Hotspot 2.0 Release 1 configuration. 27 */ 28 public class WiFiInstaller extends Activity { 29 30 private static final String TAG = "WifiInstaller"; 31 private static final String NETWORK_NAME = "network_name"; 32 private static final String INSTALL_STATE = "install_state"; 33 private static final String TYPE_WIFI_CONFIG = "application/x-wifi-config"; 34 public static final int INSTALL_SUCCESS = 2; 35 public static final int INSTALL_FAIL = 1; 36 public static final int INSTALL_FAIL_NO_WIFI = 0; 37 private PasspointConfiguration mPasspointConfig; 38 private boolean mIsPasspointConfigurationValid; 39 40 @Override onCreate(Bundle savedStates)41 protected void onCreate(Bundle savedStates) { 42 super.onCreate(savedStates); 43 getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); 44 45 mIsPasspointConfigurationValid = false; 46 Bundle bundle = getIntent().getExtras(); 47 if (bundle == null) { 48 Log.e(TAG, "Invalid inputs"); 49 return; 50 } 51 String uriString = bundle.getString(CertInstallerMain.WIFI_CONFIG_FILE); 52 String mimeType = bundle.getString(CertInstallerMain.WIFI_CONFIG); 53 byte[] data = bundle.getByteArray(CertInstallerMain.WIFI_CONFIG_DATA); 54 55 Log.d(TAG, "WiFi data for " + CertInstallerMain.WIFI_CONFIG + ": " + 56 mimeType + " is " + (data != null ? data.length : "-")); 57 58 // Make sure that the input is valid 59 if (data == null || data.length == 0 || TextUtils.isEmpty(uriString)) { 60 Log.e(TAG, "Invalid inputs"); 61 return; 62 } 63 64 // Verify MIME type before parsing 65 if (!TextUtils.equals(mimeType, TYPE_WIFI_CONFIG)) { 66 Log.e(TAG, "Unexpected MIME type: " + mimeType); 67 EventLog.writeEvent(0x534e4554, "176756691", -1, "Invalid mime-type"); 68 return; 69 } 70 71 mPasspointConfig = ConfigParser.parsePasspointConfig(mimeType, data); 72 if (mPasspointConfig == null) { 73 Log.e(TAG, "Failed to build Passpoint configuration"); 74 EventLog.writeEvent(0x534e4554, "176756691", -1, "Invalid data in file " 75 + uriString); 76 return; 77 } 78 if (mPasspointConfig.getHomeSp() == null) { 79 Log.e(TAG, "Passpoint profile missing HomeSP information"); 80 } else { 81 // Passpoint configuration parsed successfully and valid. Mark to be installed. 82 mIsPasspointConfigurationValid = true; 83 } 84 // Delete the file only if the Passpoint configuration was parsed successfully 85 dropFile(Uri.parse(uriString), getApplicationContext()); 86 } 87 88 @Override onResume()89 protected void onResume() { 90 super.onResume(); 91 createMainDialog(); 92 } 93 94 /** 95 * Create a dialog that guides the user through Hotspot 2.0 Release 1 configuration file 96 * installation. 97 */ createMainDialog()98 private void createMainDialog() { 99 Resources res = getResources(); 100 AlertDialog.Builder builder = new AlertDialog.Builder(this); 101 View layout = getLayoutInflater().inflate(R.layout.wifi_main_dialog, null); 102 builder.setView(layout); 103 104 TextView text = (TextView) layout.findViewById(R.id.wifi_info); 105 if (mIsPasspointConfigurationValid) { 106 WifiManager wifiManager = getSystemService(WifiManager.class); 107 text.setText(String.format(getResources().getString(R.string.wifi_installer_detail), 108 mPasspointConfig.getHomeSp().getFriendlyName())); 109 110 builder.setTitle(mPasspointConfig.getHomeSp().getFriendlyName()); 111 builder.setIcon(res.getDrawable(R.drawable.signal_wifi_4_bar_lock_black_24dp)); 112 113 builder.setPositiveButton(R.string.wifi_install_label, 114 new DialogInterface.OnClickListener() { 115 @Override 116 public void onClick(DialogInterface dialog, int which) { 117 Toast.makeText(WiFiInstaller.this, getString(R.string.wifi_installing_label), 118 Toast.LENGTH_LONG).show(); 119 AsyncTask.execute(new Runnable() { 120 @Override 121 public void run() { 122 boolean success = true; 123 try { 124 wifiManager.removePasspointConfiguration( 125 mPasspointConfig.getHomeSp().getFqdn()); 126 } catch (IllegalArgumentException e) { 127 // Do nothing. This is expected if a profile with this FQDN does not 128 // exist. 129 } 130 try { 131 wifiManager.addOrUpdatePasspointConfiguration(mPasspointConfig); 132 } catch (RuntimeException rte) { 133 Log.w(TAG, "Caught exception while installing wifi config: " + 134 rte, rte); 135 success = false; 136 } 137 if (success) { 138 Intent intent = new Intent(getApplicationContext(), 139 CredentialsInstallDialog.class); 140 intent.putExtra(NETWORK_NAME, 141 mPasspointConfig.getHomeSp().getFriendlyName()); 142 intent.putExtra(INSTALL_STATE, INSTALL_SUCCESS); 143 startActivity(intent); 144 } else { 145 Intent intent = new Intent(getApplicationContext(), 146 CredentialsInstallDialog.class); 147 intent.putExtra(INSTALL_STATE, INSTALL_FAIL); 148 startActivity(intent); 149 } 150 finish(); 151 } 152 }); 153 dialog.dismiss(); 154 } 155 }); 156 157 builder.setNegativeButton(R.string.wifi_cancel_label, new 158 DialogInterface.OnClickListener() { 159 @Override 160 public void onClick(DialogInterface dialog, int which) { 161 dialog.dismiss(); 162 finish(); 163 } 164 }); 165 } else { 166 text.setText(getResources().getString(R.string.wifi_installer_download_error)); 167 builder.setPositiveButton(R.string.done_label, new DialogInterface.OnClickListener() { 168 @Override 169 public void onClick(DialogInterface dialog, int which) { 170 dialog.dismiss(); 171 finish(); 172 } 173 }); 174 } 175 final AlertDialog alertDialog = builder.create(); 176 alertDialog.show(); 177 alertDialog.getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); 178 } 179 180 /** 181 * Delete the file specified by the given URI. 182 * 183 * @param uri The URI of the file 184 * @param context The context of the current application 185 */ dropFile(Uri uri, Context context)186 private static void dropFile(Uri uri, Context context) { 187 try { 188 if (DocumentsContract.isDocumentUri(context, uri)) { 189 DocumentsContract.deleteDocument(context.getContentResolver(), uri); 190 } else { 191 context.getContentResolver().delete(uri, null, null); 192 } 193 } catch (Exception e) { 194 Log.e(TAG, "could not delete document " + uri); 195 } 196 } 197 } 198