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