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