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.util.Log; 27 import android.view.View; 28 import android.widget.Button; 29 import android.widget.TextView; 30 31 import androidx.preference.Preference; 32 33 import com.android.internal.app.AlertActivity; 34 import com.android.internal.app.AlertController; 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 dismissDialog()71 private void dismissDialog() { 72 this.dismiss(); 73 } 74 75 @Override onCreate(Bundle savedInstanceState)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 } else if (mRequestType == BluetoothDevice.REQUEST_TYPE_SIM_ACCESS) { 103 showDialog(getString(R.string.bluetooth_sap_request), mRequestType); 104 } 105 else { 106 Log.e(TAG, "Error: bad request type: " + mRequestType); 107 finish(); 108 return; 109 } 110 registerReceiver(mReceiver, 111 new IntentFilter(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)); 112 mReceiverRegistered = true; 113 } 114 115 showDialog(String title, int requestType)116 private void showDialog(String title, int requestType) 117 { 118 final AlertController.AlertParams p = mAlertParams; 119 p.mTitle = title; 120 if(DEBUG) Log.i(TAG, "showDialog() Request type: " + mRequestType + " this: " + this); 121 switch(requestType) 122 { 123 case BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION: 124 p.mView = createConnectionDialogView(); 125 break; 126 case BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS: 127 p.mView = createPhonebookDialogView(); 128 break; 129 case BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS: 130 p.mView = createMapDialogView(); 131 break; 132 case BluetoothDevice.REQUEST_TYPE_SIM_ACCESS: 133 p.mView = createSapDialogView(); 134 break; 135 } 136 p.mPositiveButtonText = getString(R.string.yes); 137 p.mPositiveButtonListener = this; 138 p.mNegativeButtonText = getString(R.string.no); 139 p.mNegativeButtonListener = this; 140 mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); 141 setupAlert(); 142 143 } 144 @Override onBackPressed()145 public void onBackPressed() { 146 /*we need an answer so ignore back button presses during auth */ 147 if(DEBUG) Log.i(TAG, "Back button pressed! ignoring"); 148 return; 149 } 150 151 // TODO(edjee): createConnectionDialogView, createPhonebookDialogView and createMapDialogView 152 // are similar. Refactor them into one method. 153 // Also, the string resources bluetooth_remember_choice and bluetooth_pb_remember_choice should 154 // be removed. createConnectionDialogView()155 private View createConnectionDialogView() { 156 String mRemoteName = Utils.createRemoteName(this, mDevice); 157 mView = getLayoutInflater().inflate(R.layout.bluetooth_access, null); 158 messageView = (TextView)mView.findViewById(R.id.message); 159 messageView.setText(getString(R.string.bluetooth_connection_dialog_text, 160 mRemoteName)); 161 return mView; 162 } 163 createPhonebookDialogView()164 private View createPhonebookDialogView() { 165 String mRemoteName = Utils.createRemoteName(this, mDevice); 166 mView = getLayoutInflater().inflate(R.layout.bluetooth_access, null); 167 messageView = (TextView)mView.findViewById(R.id.message); 168 messageView.setText(getString(R.string.bluetooth_pb_acceptance_dialog_text, 169 mRemoteName, mRemoteName)); 170 return mView; 171 } 172 createMapDialogView()173 private View createMapDialogView() { 174 String mRemoteName = Utils.createRemoteName(this, mDevice); 175 mView = getLayoutInflater().inflate(R.layout.bluetooth_access, null); 176 messageView = (TextView)mView.findViewById(R.id.message); 177 messageView.setText(getString(R.string.bluetooth_map_acceptance_dialog_text, 178 mRemoteName, mRemoteName)); 179 return mView; 180 } 181 createSapDialogView()182 private View createSapDialogView() { 183 String mRemoteName = Utils.createRemoteName(this, mDevice); 184 mView = getLayoutInflater().inflate(R.layout.bluetooth_access, null); 185 messageView = (TextView)mView.findViewById(R.id.message); 186 messageView.setText(getString(R.string.bluetooth_sap_acceptance_dialog_text, 187 mRemoteName, mRemoteName)); 188 return mView; 189 } 190 onPositive()191 private void onPositive() { 192 if (DEBUG) Log.d(TAG, "onPositive"); 193 sendReplyIntentToReceiver(true, true); 194 finish(); 195 } 196 onNegative()197 private void onNegative() { 198 if (DEBUG) Log.d(TAG, "onNegative"); 199 sendReplyIntentToReceiver(false, true); 200 } 201 sendReplyIntentToReceiver(final boolean allowed, final boolean always)202 private void sendReplyIntentToReceiver(final boolean allowed, final boolean always) { 203 Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); 204 205 if (mReturnPackage != null && mReturnClass != null) { 206 intent.setClassName(mReturnPackage, mReturnClass); 207 } 208 if (DEBUG) Log.i(TAG, "sendReplyIntentToReceiver() Request type: " + mRequestType + 209 " mReturnPackage" + mReturnPackage + " mReturnClass" + mReturnClass); 210 211 intent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, 212 allowed ? BluetoothDevice.CONNECTION_ACCESS_YES 213 : BluetoothDevice.CONNECTION_ACCESS_NO); 214 intent.putExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, always); 215 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); 216 intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, mRequestType); 217 sendBroadcast(intent, android.Manifest.permission.BLUETOOTH_ADMIN); 218 } 219 onClick(DialogInterface dialog, int which)220 public void onClick(DialogInterface dialog, int which) { 221 switch (which) { 222 case DialogInterface.BUTTON_POSITIVE: 223 onPositive(); 224 break; 225 226 case DialogInterface.BUTTON_NEGATIVE: 227 onNegative(); 228 break; 229 default: 230 break; 231 } 232 } 233 234 @Override onDestroy()235 protected void onDestroy() { 236 super.onDestroy(); 237 if (mReceiverRegistered) { 238 unregisterReceiver(mReceiver); 239 mReceiverRegistered = false; 240 } 241 } 242 onPreferenceChange(Preference preference, Object newValue)243 public boolean onPreferenceChange(Preference preference, Object newValue) { 244 return true; 245 } 246 } 247