1 /* 2 * Copyright (C) 2011 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.android.settings.bluetooth; 18 19 import android.bluetooth.BluetoothDevice; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.content.DialogInterface; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.os.Bundle; 26 import android.preference.Preference; 27 import android.util.Log; 28 import android.view.View; 29 import android.widget.CheckBox; 30 import android.widget.CompoundButton; 31 import android.widget.EditText; 32 import android.widget.TextView; 33 import android.widget.Button; 34 import android.widget.CompoundButton.OnCheckedChangeListener; 35 36 import com.android.internal.app.AlertActivity; 37 import com.android.internal.app.AlertController; 38 39 import com.android.settings.R; 40 41 /** 42 * BluetoothPermissionActivity shows a dialog for accepting incoming 43 * profile connection request from untrusted devices. 44 * It is also used to show a dialogue for accepting incoming phonebook 45 * read request. The request could be initiated by PBAP PCE or by HF AT+CPBR. 46 */ 47 public class BluetoothPermissionActivity extends AlertActivity implements 48 DialogInterface.OnClickListener, Preference.OnPreferenceChangeListener { 49 private static final String TAG = "BluetoothPermissionActivity"; 50 private static final boolean DEBUG = Utils.D; 51 52 private View mView; 53 private TextView messageView; 54 private Button mOkButton; 55 private BluetoothDevice mDevice; 56 private String mReturnPackage = null; 57 private String mReturnClass = null; 58 59 private CheckBox mRememberChoice; 60 private boolean mRememberChoiceValue = false; 61 62 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 63 @Override 64 public void onReceive(Context context, Intent intent) { 65 String action = intent.getAction(); 66 if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)) { 67 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 68 if (mDevice.equals(device)) dismissDialog(); 69 } 70 } 71 }; 72 private boolean mReceiverRegistered = false; 73 74 private void dismissDialog() { 75 this.dismiss(); 76 } 77 78 @Override 79 protected void onCreate(Bundle savedInstanceState) { 80 super.onCreate(savedInstanceState); 81 82 Intent i = getIntent(); 83 String action = i.getAction(); 84 if (!action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST)) { 85 Log.e(TAG, "Error: this activity may be started only with intent " 86 + "ACTION_CONNECTION_ACCESS_REQUEST"); 87 finish(); 88 return; 89 } 90 91 mDevice = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 92 mReturnPackage = i.getStringExtra(BluetoothDevice.EXTRA_PACKAGE_NAME); 93 mReturnClass = i.getStringExtra(BluetoothDevice.EXTRA_CLASS_NAME); 94 int requestType = i.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, 95 BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS); 96 97 if (requestType == BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION) { 98 showConnectionDialog(); 99 } else if (requestType == BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) { 100 showPhonebookDialog(); 101 } else { 102 Log.e(TAG, "Error: bad request type: " + requestType); 103 finish(); 104 return; 105 } 106 registerReceiver(mReceiver, 107 new IntentFilter(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)); 108 mReceiverRegistered = true; 109 } 110 111 private void showConnectionDialog() { 112 final AlertController.AlertParams p = mAlertParams; 113 p.mIconId = android.R.drawable.ic_dialog_info; 114 p.mTitle = getString(R.string.bluetooth_connection_permission_request); 115 p.mView = createConnectionDialogView(); 116 p.mPositiveButtonText = getString(R.string.yes); 117 p.mPositiveButtonListener = this; 118 p.mNegativeButtonText = getString(R.string.no); 119 p.mNegativeButtonListener = this; 120 mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); 121 setupAlert(); 122 } 123 124 private void showPhonebookDialog() { 125 final AlertController.AlertParams p = mAlertParams; 126 p.mIconId = android.R.drawable.ic_dialog_info; 127 p.mTitle = getString(R.string.bluetooth_phonebook_request); 128 p.mView = createPhonebookDialogView(); 129 p.mPositiveButtonText = getString(android.R.string.yes); 130 p.mPositiveButtonListener = this; 131 p.mNegativeButtonText = getString(android.R.string.no); 132 p.mNegativeButtonListener = this; 133 mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); 134 setupAlert(); 135 } 136 137 private String createConnectionDisplayText() { 138 String mRemoteName = mDevice != null ? mDevice.getAliasName() : null; 139 140 if (mRemoteName == null) mRemoteName = getString(R.string.unknown); 141 String mMessage1 = getString(R.string.bluetooth_connection_dialog_text, 142 mRemoteName); 143 return mMessage1; 144 } 145 146 private String createPhonebookDisplayText() { 147 String mRemoteName = mDevice != null ? mDevice.getAliasName() : null; 148 149 if (mRemoteName == null) mRemoteName = getString(R.string.unknown); 150 String mMessage1 = getString(R.string.bluetooth_pb_acceptance_dialog_text, 151 mRemoteName, mRemoteName); 152 return mMessage1; 153 } 154 155 private View createConnectionDialogView() { 156 mView = getLayoutInflater().inflate(R.layout.bluetooth_connection_access, null); 157 messageView = (TextView)mView.findViewById(R.id.message); 158 messageView.setText(createConnectionDisplayText()); 159 return mView; 160 } 161 162 private View createPhonebookDialogView() { 163 mView = getLayoutInflater().inflate(R.layout.bluetooth_pb_access, null); 164 messageView = (TextView)mView.findViewById(R.id.message); 165 messageView.setText(createPhonebookDisplayText()); 166 mRememberChoice = (CheckBox)mView.findViewById(R.id.bluetooth_pb_remember_choice); 167 mRememberChoice.setChecked(false); 168 mRememberChoice.setOnCheckedChangeListener(new OnCheckedChangeListener() { 169 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 170 if (isChecked) { 171 mRememberChoiceValue = true; 172 } else { 173 mRememberChoiceValue = false; 174 } 175 } 176 }); 177 return mView; 178 } 179 180 private void onPositive() { 181 if (DEBUG) Log.d(TAG, "onPositive mRememberChoiceValue: " + mRememberChoiceValue); 182 183 if (mRememberChoiceValue) { 184 savePhonebookPermissionChoice(CachedBluetoothDevice.PHONEBOOK_ACCESS_ALLOWED); 185 } 186 sendIntentToReceiver(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY, true, 187 BluetoothDevice.EXTRA_ALWAYS_ALLOWED, mRememberChoiceValue); 188 finish(); 189 } 190 191 private void onNegative() { 192 if (DEBUG) Log.d(TAG, "onNegative mRememberChoiceValue: " + mRememberChoiceValue); 193 194 if (mRememberChoiceValue) { 195 savePhonebookPermissionChoice(CachedBluetoothDevice.PHONEBOOK_ACCESS_REJECTED); 196 } 197 sendIntentToReceiver(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY, false, 198 null, false // dummy value, no effect since last param is null 199 ); 200 finish(); 201 } 202 203 private void sendIntentToReceiver(final String intentName, final boolean allowed, 204 final String extraName, final boolean extraValue) { 205 Intent intent = new Intent(intentName); 206 207 if (mReturnPackage != null && mReturnClass != null) { 208 intent.setClassName(mReturnPackage, mReturnClass); 209 } 210 211 intent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, 212 allowed ? BluetoothDevice.CONNECTION_ACCESS_YES : 213 BluetoothDevice.CONNECTION_ACCESS_NO); 214 215 if (extraName != null) { 216 intent.putExtra(extraName, extraValue); 217 } 218 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); 219 sendBroadcast(intent, android.Manifest.permission.BLUETOOTH_ADMIN); 220 } 221 222 public void onClick(DialogInterface dialog, int which) { 223 switch (which) { 224 case DialogInterface.BUTTON_POSITIVE: 225 onPositive(); 226 break; 227 228 case DialogInterface.BUTTON_NEGATIVE: 229 onNegative(); 230 break; 231 default: 232 break; 233 } 234 } 235 236 @Override 237 protected void onDestroy() { 238 super.onDestroy(); 239 if (mReceiverRegistered) { 240 unregisterReceiver(mReceiver); 241 mReceiverRegistered = false; 242 } 243 } 244 245 public boolean onPreferenceChange(Preference preference, Object newValue) { 246 return true; 247 } 248 249 private void savePhonebookPermissionChoice(int permissionChoice) { 250 LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(this); 251 CachedBluetoothDeviceManager cachedDeviceManager = 252 bluetoothManager.getCachedDeviceManager(); 253 CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice); 254 if (cachedDevice != null ) { 255 cachedDevice.setPhonebookPermissionChoice(permissionChoice); 256 } else { 257 cachedDevice = cachedDeviceManager.addDevice(bluetoothManager.getBluetoothAdapter(), 258 bluetoothManager.getProfileManager(), 259 mDevice); 260 cachedDevice.setPhonebookPermissionChoice(permissionChoice); 261 } 262 } 263 } 264