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.nfc.NdefMessage;
     22 import android.nfc.NdefRecord;
     23 import android.nfc.NfcAdapter;
     24 import android.nfc.NfcEvent;
     25 import android.os.Bundle;
     26 import android.support.annotation.Nullable;
     27 import android.support.v4.app.Fragment;
     28 import android.support.v4.app.LoaderManager;
     29 import android.support.v4.content.Loader;
     30 import android.text.TextUtils;
     31 import android.view.LayoutInflater;
     32 import android.view.View;
     33 import android.view.ViewGroup;
     34 import android.widget.EditText;
     35 
     36 import java.io.ByteArrayOutputStream;
     37 import java.io.IOException;
     38 import java.util.Map;
     39 import java.util.Properties;
     40 
     41 /**
     42  * Provides UI and logic for NFC provisioning.
     43  * <p>
     44  * This fragment creates an intent, which sends parameters to a second device via an Nfc bump. If
     45  * the second device is factory reset, this will start provisioning the second device to set it up
     46  * as an owned device.
     47  * </p>
     48  */
     49 public class NfcProvisioningFragment extends Fragment implements
     50         NfcAdapter.CreateNdefMessageCallback,
     51         TextWatcherWrapper.OnTextChangedListener,
     52         LoaderManager.LoaderCallbacks<Map<String, String>> {
     53 
     54     private static final int LOADER_PROVISIONING_VALUES = 1;
     55 
     56     // View references
     57     private EditText mEditPackageName;
     58     private EditText mEditLocale;
     59     private EditText mEditTimezone;
     60     private EditText mEditWifiSsid;
     61     private EditText mEditWifiSecurityType;
     62     private EditText mEditWifiPassword;
     63 
     64     // Values to be set via NFC bump
     65     private Map<String, String> mProvisioningValues;
     66 
     67     @Override
     68     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
     69                              @Nullable Bundle savedInstanceState) {
     70         return inflater.inflate(R.layout.fragment_nfc_provisioning, container, false);
     71     }
     72 
     73     @Override
     74     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
     75         // Retrieve view references
     76         mEditPackageName = (EditText) view.findViewById(R.id.package_name);
     77         mEditLocale = (EditText) view.findViewById(R.id.locale);
     78         mEditTimezone = (EditText) view.findViewById(R.id.timezone);
     79         mEditWifiSsid = (EditText) view.findViewById(R.id.wifi_ssid);
     80         mEditWifiSecurityType = (EditText) view.findViewById(R.id.wifi_security_type);
     81         mEditWifiPassword = (EditText) view.findViewById(R.id.wifi_password);
     82         // Bind event handlers
     83         mEditPackageName.addTextChangedListener(new TextWatcherWrapper(R.id.package_name, this));
     84         mEditLocale.addTextChangedListener(new TextWatcherWrapper(R.id.locale, this));
     85         mEditTimezone.addTextChangedListener(new TextWatcherWrapper(R.id.timezone, this));
     86         mEditWifiSsid.addTextChangedListener(new TextWatcherWrapper(R.id.wifi_ssid, this));
     87         mEditWifiSecurityType.addTextChangedListener(
     88                 new TextWatcherWrapper(R.id.wifi_security_type, this));
     89         mEditWifiPassword.addTextChangedListener(new TextWatcherWrapper(R.id.wifi_password, this));
     90     }
     91 
     92     @Override
     93     public void onStart() {
     94         super.onStart();
     95         Activity activity = getActivity();
     96         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(activity);
     97         if (adapter != null) {
     98             adapter.setNdefPushMessageCallback(this, activity);
     99         }
    100         getLoaderManager().initLoader(LOADER_PROVISIONING_VALUES, null, this);
    101     }
    102 
    103     @Override
    104     public NdefMessage createNdefMessage(NfcEvent event) {
    105         if (mProvisioningValues == null) {
    106             return null;
    107         }
    108         ByteArrayOutputStream stream = new ByteArrayOutputStream();
    109         Properties properties = new Properties();
    110         // Store all the values into the Properties object
    111         for (Map.Entry<String, String> e : mProvisioningValues.entrySet()) {
    112             if (!TextUtils.isEmpty(e.getValue())) {
    113                 String value;
    114                 if (e.getKey().equals(DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID)) {
    115                     // Make sure to surround SSID with double quotes
    116                     value = e.getValue();
    117                     if (!value.startsWith("\"") || !value.endsWith("\"")) {
    118                         value = "\"" + value + "\"";
    119                     }
    120                 } else {
    121                     value = e.getValue();
    122                 }
    123                 properties.put(e.getKey(), value);
    124             }
    125         }
    126         // Make sure to put local time in the properties. This is necessary on some devices to
    127         // reliably download the device owner APK from an HTTPS connection.
    128         if (!properties.contains(DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME)) {
    129             properties.put(DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME,
    130                     String.valueOf(System.currentTimeMillis()));
    131         }
    132         try {
    133             properties.store(stream, getString(R.string.nfc_comment));
    134             NdefRecord record = NdefRecord.createMime(
    135                     DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC, stream.toByteArray());
    136             return new NdefMessage(new NdefRecord[]{record});
    137         } catch (IOException e) {
    138             e.printStackTrace();
    139         }
    140         return null;
    141     }
    142 
    143     @Override
    144     public void onTextChanged(int id, String s) {
    145         if (mProvisioningValues == null) {
    146             return;
    147         }
    148         switch (id) {
    149             case R.id.package_name:
    150                 mProvisioningValues.put(
    151                         DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, s);
    152                 break;
    153             case R.id.locale:
    154                 mProvisioningValues.put(DevicePolicyManager.EXTRA_PROVISIONING_LOCALE, s);
    155                 break;
    156             case R.id.timezone:
    157                 mProvisioningValues.put(DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE, s);
    158                 break;
    159             case R.id.wifi_ssid:
    160                 mProvisioningValues.put(DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID, s);
    161                 break;
    162             case R.id.wifi_security_type:
    163                 mProvisioningValues.put(
    164                         DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE, s);
    165                 break;
    166             case R.id.wifi_password:
    167                 mProvisioningValues.put(DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PASSWORD, s);
    168                 break;
    169         }
    170     }
    171 
    172     @Override
    173     public Loader<Map<String, String>> onCreateLoader(int id, Bundle args) {
    174         if (id == LOADER_PROVISIONING_VALUES) {
    175             return new ProvisioningValuesLoader(getActivity());
    176         }
    177         return null;
    178     }
    179 
    180     @Override
    181     public void onLoadFinished(Loader<Map<String, String>> loader, Map<String, String> values) {
    182         if (loader.getId() == LOADER_PROVISIONING_VALUES) {
    183             mProvisioningValues = values;
    184             mEditPackageName.setText(values.get(
    185                     DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME));
    186             mEditLocale.setText(values.get(DevicePolicyManager.EXTRA_PROVISIONING_LOCALE));
    187             mEditTimezone.setText(values.get(DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE));
    188             mEditWifiSsid.setText(values.get(DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID));
    189             mEditWifiSecurityType.setText(values.get(
    190                     DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE));
    191             mEditWifiPassword.setText(null);
    192         }
    193     }
    194 
    195     @Override
    196     public void onLoaderReset(Loader<Map<String, String>> loader) {
    197         // Do nothing
    198     }
    199 
    200 }
    201