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