1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.nfcprovisioning; 18 19 import android.app.Activity; 20 import android.app.admin.DevicePolicyManager; 21 import android.content.Context; 22 import android.net.wifi.WifiInfo; 23 import android.net.wifi.WifiManager; 24 import android.os.Environment; 25 import android.support.v4.content.AsyncTaskLoader; 26 27 import com.example.android.common.logger.Log; 28 29 import java.io.BufferedReader; 30 import java.io.File; 31 import java.io.FileReader; 32 import java.io.IOException; 33 import java.io.StringWriter; 34 import java.util.HashMap; 35 import java.util.HashSet; 36 import java.util.Map; 37 import java.util.Properties; 38 import java.util.Set; 39 import java.util.TimeZone; 40 41 /** 42 * Loads default values for NFC provisioning. 43 * <p/> 44 * This loader first tries to load values from a config file in SD card. Then it fills in missing 45 * values using constants and settings on the programming device. 46 */ 47 public class ProvisioningValuesLoader extends AsyncTaskLoader<Map<String, String>> { 48 49 private static final String FILENAME = "nfcprovisioning.txt"; 50 private static final String TAG = "LoadProvisioningValuesTask"; 51 52 private Map<String, String> mValues; 53 ProvisioningValuesLoader(Context context)54 public ProvisioningValuesLoader(Context context) { 55 super(context); 56 } 57 58 @Override loadInBackground()59 public Map<String, String> loadInBackground() { 60 HashMap<String, String> values = new HashMap<>(); 61 loadFromDisk(values); 62 gatherAdminExtras(values); 63 loadSystemValues(values); 64 return values; 65 } 66 67 @Override deliverResult(Map<String, String> values)68 public void deliverResult(Map<String, String> values) { 69 if (isReset()) { 70 return; 71 } 72 mValues = values; 73 super.deliverResult(values); 74 } 75 76 @Override onStartLoading()77 protected void onStartLoading() { 78 if (mValues != null) { 79 deliverResult(mValues); 80 } 81 if (takeContentChanged() || mValues == null) { 82 forceLoad(); 83 } 84 } 85 86 @Override onStopLoading()87 protected void onStopLoading() { 88 cancelLoad(); 89 } 90 91 @Override onReset()92 protected void onReset() { 93 super.onReset(); 94 onStopLoading(); 95 mValues = null; 96 } 97 loadFromDisk(HashMap<String, String> values)98 private void loadFromDisk(HashMap<String, String> values) { 99 File directory = Environment.getExternalStorageDirectory(); 100 File file = new File(directory, FILENAME); 101 if (!file.exists()) { 102 return; 103 } 104 Log.d(TAG, "Loading the config file..."); 105 try { 106 loadFromFile(values, file); 107 } catch (IOException e) { 108 e.printStackTrace(); 109 Log.e(TAG, "Error loading data from " + file, e); 110 } 111 } 112 loadFromFile(HashMap<String, String> values, File file)113 private void loadFromFile(HashMap<String, String> values, File file) throws IOException { 114 BufferedReader reader = null; 115 try { 116 reader = new BufferedReader(new FileReader(file)); 117 String line; 118 while (null != (line = reader.readLine())) { 119 if (line.startsWith("#")) { 120 continue; 121 } 122 int position = line.indexOf("="); 123 if (position < 0) { // Not found 124 continue; 125 } 126 String key = line.substring(0, position); 127 String value = line.substring(position + 1); 128 values.put(key, value); 129 Log.d(TAG, key + "=" + value); 130 } 131 } finally { 132 if (reader != null) { 133 reader.close(); 134 } 135 } 136 } 137 gatherAdminExtras(HashMap<String, String> values)138 private void gatherAdminExtras(HashMap<String, String> values) { 139 HashMap<String, String> newMap = new HashMap<String, String>(); 140 Properties props = new Properties(); 141 Set<String>keys = new HashSet(values.keySet()); 142 for (String key : keys) { 143 if (key.startsWith("android.app.extra")) { 144 continue; 145 } 146 props.put(key, values.get(key)); 147 values.remove(key); 148 } 149 StringWriter sw = new StringWriter(); 150 try{ 151 props.store(sw, "admin extras bundle"); 152 values.put(DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, 153 sw.toString()); 154 Log.d(TAG, "Admin extras bundle=" + values.get( 155 DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE)); 156 } catch (IOException e) { 157 Log.e(TAG, "Unable to build admin extras bundle"); 158 } 159 } 160 loadSystemValues(HashMap<String, String> values)161 private void loadSystemValues(HashMap<String, String> values) { 162 Context context = getContext(); 163 putIfMissing(values, DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, 164 "com.example.android.deviceowner"); 165 putIfMissing(values, DevicePolicyManager.EXTRA_PROVISIONING_LOCALE, 166 context.getResources().getConfiguration().locale.toString()); 167 putIfMissing(values, DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE, 168 TimeZone.getDefault().getID()); 169 if (!values.containsKey(DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID)) { 170 WifiManager wifiManager = (WifiManager) context 171 .getSystemService(Activity.WIFI_SERVICE); 172 WifiInfo info = wifiManager.getConnectionInfo(); 173 values.put(DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID, trimSsid(info.getSSID())); 174 } 175 } 176 177 /** 178 * {@link WifiInfo#getSSID} returns the WiFi SSID surrounded by double quotation marks. This 179 * method removes them if wifiSsid contains them. 180 */ trimSsid(String wifiSsid)181 private static String trimSsid(String wifiSsid) { 182 int head = wifiSsid.startsWith("\"") ? 1 : 0; 183 int tail = wifiSsid.endsWith("\"") ? 1 : 0; 184 return wifiSsid.substring(head, wifiSsid.length() - tail); 185 } 186 putIfMissing(HashMap<Key, Value> map, Key key, Value value)187 private static <Key, Value> void putIfMissing(HashMap<Key, Value> map, Key key, Value value) { 188 if (!map.containsKey(key)) { 189 map.put(key, value); 190 } 191 } 192 193 } 194