/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.nfcprovisioning; import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.nfc.NfcEvent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Map; import java.util.Properties; /** * Provides UI and logic for NFC provisioning. * <p> * This fragment creates an intent, which sends parameters to a second device via an Nfc bump. If * the second device is factory reset, this will start provisioning the second device to set it up * as an owned device. * </p> */ public class NfcProvisioningFragment extends Fragment implements NfcAdapter.CreateNdefMessageCallback, TextWatcherWrapper.OnTextChangedListener, LoaderManager.LoaderCallbacks<Map<String, String>> { private static final int LOADER_PROVISIONING_VALUES = 1; // View references private EditText mEditPackageName; private EditText mEditLocale; private EditText mEditTimezone; private EditText mEditWifiSsid; private EditText mEditWifiSecurityType; private EditText mEditWifiPassword; // Values to be set via NFC bump private Map<String, String> mProvisioningValues; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_nfc_provisioning, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { // Retrieve view references mEditPackageName = (EditText) view.findViewById(R.id.package_name); mEditLocale = (EditText) view.findViewById(R.id.locale); mEditTimezone = (EditText) view.findViewById(R.id.timezone); mEditWifiSsid = (EditText) view.findViewById(R.id.wifi_ssid); mEditWifiSecurityType = (EditText) view.findViewById(R.id.wifi_security_type); mEditWifiPassword = (EditText) view.findViewById(R.id.wifi_password); // Bind event handlers mEditPackageName.addTextChangedListener(new TextWatcherWrapper(R.id.package_name, this)); mEditLocale.addTextChangedListener(new TextWatcherWrapper(R.id.locale, this)); mEditTimezone.addTextChangedListener(new TextWatcherWrapper(R.id.timezone, this)); mEditWifiSsid.addTextChangedListener(new TextWatcherWrapper(R.id.wifi_ssid, this)); mEditWifiSecurityType.addTextChangedListener( new TextWatcherWrapper(R.id.wifi_security_type, this)); mEditWifiPassword.addTextChangedListener(new TextWatcherWrapper(R.id.wifi_password, this)); } @Override public void onStart() { super.onStart(); Activity activity = getActivity(); NfcAdapter adapter = NfcAdapter.getDefaultAdapter(activity); if (adapter != null) { adapter.setNdefPushMessageCallback(this, activity); } getLoaderManager().initLoader(LOADER_PROVISIONING_VALUES, null, this); } @Override public NdefMessage createNdefMessage(NfcEvent event) { if (mProvisioningValues == null) { return null; } ByteArrayOutputStream stream = new ByteArrayOutputStream(); Properties properties = new Properties(); // Store all the values into the Properties object for (Map.Entry<String, String> e : mProvisioningValues.entrySet()) { if (!TextUtils.isEmpty(e.getValue())) { String value; if (e.getKey().equals(DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID)) { // Make sure to surround SSID with double quotes value = e.getValue(); if (!value.startsWith("\"") || !value.endsWith("\"")) { value = "\"" + value + "\""; } } else { value = e.getValue(); } properties.put(e.getKey(), value); } } // Make sure to put local time in the properties. This is necessary on some devices to // reliably download the device owner APK from an HTTPS connection. if (!properties.contains(DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME)) { properties.put(DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME, String.valueOf(System.currentTimeMillis())); } try { properties.store(stream, getString(R.string.nfc_comment)); NdefRecord record = NdefRecord.createMime( DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC, stream.toByteArray()); return new NdefMessage(new NdefRecord[]{record}); } catch (IOException e) { e.printStackTrace(); } return null; } @Override public void onTextChanged(int id, String s) { if (mProvisioningValues == null) { return; } switch (id) { case R.id.package_name: mProvisioningValues.put( DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, s); break; case R.id.locale: mProvisioningValues.put(DevicePolicyManager.EXTRA_PROVISIONING_LOCALE, s); break; case R.id.timezone: mProvisioningValues.put(DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE, s); break; case R.id.wifi_ssid: mProvisioningValues.put(DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID, s); break; case R.id.wifi_security_type: mProvisioningValues.put( DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE, s); break; case R.id.wifi_password: mProvisioningValues.put(DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PASSWORD, s); break; } } @Override public Loader<Map<String, String>> onCreateLoader(int id, Bundle args) { if (id == LOADER_PROVISIONING_VALUES) { return new ProvisioningValuesLoader(getActivity()); } return null; } @Override public void onLoadFinished(Loader<Map<String, String>> loader, Map<String, String> values) { if (loader.getId() == LOADER_PROVISIONING_VALUES) { mProvisioningValues = values; mEditPackageName.setText(values.get( DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME)); mEditLocale.setText(values.get(DevicePolicyManager.EXTRA_PROVISIONING_LOCALE)); mEditTimezone.setText(values.get(DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE)); mEditWifiSsid.setText(values.get(DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID)); mEditWifiSecurityType.setText(values.get( DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE)); mEditWifiPassword.setText(null); } } @Override public void onLoaderReset(Loader<Map<String, String>> loader) { // Do nothing } }