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