Home | History | Annotate | Download | only in com.example.android.nfcprovisioning
      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 
     54     public ProvisioningValuesLoader(Context context) {
     55         super(context);
     56     }
     57 
     58     @Override
     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
     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
     77     protected void onStartLoading() {
     78         if (mValues != null) {
     79             deliverResult(mValues);
     80         }
     81         if (takeContentChanged() || mValues == null) {
     82             forceLoad();
     83         }
     84     }
     85 
     86     @Override
     87     protected void onStopLoading() {
     88         cancelLoad();
     89     }
     90 
     91     @Override
     92     protected void onReset() {
     93         super.onReset();
     94         onStopLoading();
     95         mValues = null;
     96     }
     97 
     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 
    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 
    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 
    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      */
    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 
    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