1/* 2 * Copyright (C) 2017 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 */ 16package com.android.car.trust; 17 18import android.bluetooth.BluetoothDevice; 19import android.bluetooth.BluetoothGatt; 20import android.bluetooth.BluetoothGattCharacteristic; 21import android.bluetooth.BluetoothGattService; 22import android.content.Context; 23import android.content.SharedPreferences; 24import android.os.Handler; 25import android.os.ParcelUuid; 26import android.preference.PreferenceManager; 27import android.util.Base64; 28import android.util.Log; 29import android.view.View; 30import android.widget.Button; 31import android.widget.TextView; 32import com.android.car.trust.comms.SimpleBleClient; 33 34import java.util.UUID; 35 36/** 37 * A controller that sets up a {@link SimpleBleClient} to connect to the BLE unlock service. 38 */ 39public class PhoneUnlockController { 40 private static final String TAG = "PhoneUnlockController"; 41 42 private String mTokenHandleKey; 43 private String mEscrowTokenKey; 44 45 // BLE characteristics associated with the enrolment/add escrow token service. 46 private BluetoothGattCharacteristic mUnlockTokenHandle; 47 private BluetoothGattCharacteristic mUnlockEscrowToken; 48 49 private ParcelUuid mUnlockServiceUuid; 50 51 private SimpleBleClient mClient; 52 private Context mContext; 53 54 private TextView mTextView; 55 private Handler mHandler; 56 57 private Button mScanButton; 58 private Button mUnlockButton; 59 60 public PhoneUnlockController(Context context) { 61 mContext = context; 62 63 mTokenHandleKey = context.getString(R.string.pref_key_token_handle); 64 mEscrowTokenKey = context.getString(R.string.pref_key_escrow_token); 65 66 mClient = new SimpleBleClient(context); 67 mUnlockServiceUuid = new ParcelUuid( 68 UUID.fromString(mContext.getString(R.string.unlock_service_uuid))); 69 mClient.addCallback(mCallback /* callback */); 70 71 mHandler = new Handler(mContext.getMainLooper()); 72 } 73 74 /** 75 * Binds the views to the actions that can be performed by this controller. 76 * 77 * @param textView A text view used to display results from various BLE actions 78 * @param scanButton Button used to start scanning for available BLE devices. 79 * @param enrolButton Button used to send new escrow token to remote device. 80 */ 81 public void bind(TextView textView, Button scanButton, Button enrolButton) { 82 mTextView = textView; 83 mScanButton = scanButton; 84 mUnlockButton = enrolButton; 85 86 mScanButton.setOnClickListener(new View.OnClickListener() { 87 @Override 88 public void onClick(View v) { 89 mClient.start(mUnlockServiceUuid); 90 } 91 }); 92 93 mUnlockButton.setEnabled(false); 94 mUnlockButton.setAlpha(0.3f); 95 mUnlockButton.setOnClickListener(new View.OnClickListener() { 96 @Override 97 public void onClick(View v) { 98 appendOutputText("Sending unlock token and handle to remote device"); 99 sendUnlockRequest(); 100 } 101 }); 102 } 103 104 private void sendUnlockRequest() { 105 // Retrieve stored token and handle and write to remote device. 106 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); 107 long handle = prefs.getLong(mTokenHandleKey, -1); 108 byte[] token = Base64.decode(prefs.getString(mEscrowTokenKey, null), Base64.DEFAULT); 109 110 mUnlockEscrowToken.setValue(token); 111 mUnlockTokenHandle.setValue(Utils.getBytes(handle)); 112 113 mClient.writeCharacteristic(mUnlockEscrowToken); 114 mClient.writeCharacteristic(mUnlockTokenHandle); 115 } 116 117 private SimpleBleClient.ClientCallback mCallback = new SimpleBleClient.ClientCallback() { 118 @Override 119 public void onDeviceConnected(BluetoothDevice device) { 120 appendOutputText("Device connected: " + device.getName() 121 + " addr: " + device.getAddress()); 122 } 123 124 @Override 125 public void onDeviceDisconnected() { 126 appendOutputText("Device disconnected"); 127 } 128 129 @Override 130 public void onCharacteristicChanged(BluetoothGatt gatt, 131 BluetoothGattCharacteristic characteristic) { 132 // Not expecting any characteristics changes for the unlocking client. 133 } 134 135 @Override 136 public void onServiceDiscovered(BluetoothGattService service) { 137 if (!service.getUuid().equals(mUnlockServiceUuid.getUuid())) { 138 if (Log.isLoggable(TAG, Log.DEBUG)) { 139 Log.d(TAG, "Service UUID: " + service.getUuid() 140 + " does not match Enrolment UUID " + mUnlockServiceUuid.getUuid()); 141 } 142 return; 143 } 144 145 if (Log.isLoggable(TAG, Log.DEBUG)) { 146 Log.d(TAG, "Unlock Service # characteristics: " 147 + service.getCharacteristics().size()); 148 } 149 mUnlockEscrowToken 150 = Utils.getCharacteristic(R.string.unlock_escrow_token_uiid, service, mContext); 151 mUnlockTokenHandle 152 = Utils.getCharacteristic(R.string.unlock_handle_uiid, service, mContext); 153 appendOutputText("Unlock BLE client successfully connected"); 154 155 mHandler.post(new Runnable() { 156 @Override 157 public void run() { 158 // Services are now set up, allow users to enrol new escrow tokens. 159 mUnlockButton.setEnabled(true); 160 mUnlockButton.setAlpha(1.0f); 161 } 162 }); 163 } 164 }; 165 166 private void appendOutputText(final String text) { 167 mHandler.post(new Runnable() { 168 @Override 169 public void run() { 170 mTextView.append("\n" + text); 171 } 172 }); 173 } 174} 175