• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.text.TextUtils;
29 import android.telephony.SubscriptionInfo;
30 import android.telephony.SubscriptionManager;
31 import android.util.Log;
32 import android.view.View;
33 import android.widget.Button;
34 import android.widget.TextView;
35 
36 import androidx.preference.Preference;
37 
38 import com.android.internal.annotations.VisibleForTesting;
39 import com.android.internal.app.AlertActivity;
40 import com.android.internal.app.AlertController;
41 import com.android.settings.R;
42 import com.android.settings.network.SubscriptionUtil;
43 
44 import java.util.List;
45 
46 /**
47  * BluetoothPermissionActivity shows a dialog for accepting incoming
48  * profile connection request from untrusted devices.
49  * It is also used to show a dialogue for accepting incoming phonebook
50  * read request. The request could be initiated by PBAP PCE or by HF AT+CPBR.
51  */
52 public class BluetoothPermissionActivity extends AlertActivity implements
53         DialogInterface.OnClickListener, Preference.OnPreferenceChangeListener {
54     private static final String TAG = "BluetoothPermissionActivity";
55     private static final boolean DEBUG = Utils.D;
56 
57     private View mView;
58     private TextView messageView;
59     private Button mOkButton;
60     private BluetoothDevice mDevice;
61 
62     private int mRequestType = 0;
63     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
64         @Override
65         public void onReceive(Context context, Intent intent) {
66             String action = intent.getAction();
67             if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)) {
68                 int requestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
69                         BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
70                 if (requestType != mRequestType) return;
71                 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
72                 if (mDevice.equals(device)) dismissDialog();
73             }
74         }
75     };
76     private boolean mReceiverRegistered = false;
77 
dismissDialog()78     private void dismissDialog() {
79         this.dismiss();
80     }
81 
82     @Override
onCreate(Bundle savedInstanceState)83     protected void onCreate(Bundle savedInstanceState) {
84         super.onCreate(savedInstanceState);
85 
86         getWindow().addPrivateFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
87         Intent i = getIntent();
88         String action = i.getAction();
89         if (!action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST)) {
90             Log.e(TAG, "Error: this activity may be started only with intent "
91                   + "ACTION_CONNECTION_ACCESS_REQUEST");
92             finish();
93             return;
94         }
95 
96         mDevice = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
97         mRequestType = i.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
98                                      BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
99 
100         if(DEBUG) Log.i(TAG, "onCreate() Request type: " + mRequestType);
101 
102         if (mRequestType == BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION) {
103             showDialog(getString(R.string.bluetooth_connect_access_dialog_title), mRequestType);
104         } else if (mRequestType == BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) {
105             showDialog(getString(R.string.bluetooth_phonebook_access_dialog_title), mRequestType);
106         } else if (mRequestType == BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS) {
107             showDialog(getString(R.string.bluetooth_message_access_dialog_title), mRequestType);
108         } else if (mRequestType == BluetoothDevice.REQUEST_TYPE_SIM_ACCESS) {
109             showDialog(getString(R.string.bluetooth_sim_card_access_dialog_title), mRequestType);
110         }
111         else {
112             Log.e(TAG, "Error: bad request type: " + mRequestType);
113             finish();
114             return;
115         }
116         registerReceiver(mReceiver,
117                          new IntentFilter(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL));
118         mReceiverRegistered = true;
119     }
120 
121 
showDialog(String title, int requestType)122     private void showDialog(String title, int requestType)
123     {
124         final AlertController.AlertParams p = mAlertParams;
125         p.mTitle = title;
126         if(DEBUG) Log.i(TAG, "showDialog() Request type: " + mRequestType + " this: " + this);
127         switch(requestType)
128         {
129         case BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION:
130             p.mView = createConnectionDialogView();
131             break;
132         case BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS:
133             p.mView = createPhonebookDialogView();
134             break;
135         case BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS:
136             p.mView = createMapDialogView();
137             break;
138         case BluetoothDevice.REQUEST_TYPE_SIM_ACCESS:
139             p.mView = createSapDialogView();
140             break;
141         }
142         p.mPositiveButtonText = getString(
143                 requestType == BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION
144                         ? R.string.bluetooth_connect_access_dialog_positive : R.string.allow);
145         p.mPositiveButtonListener = this;
146         p.mNegativeButtonText = getString(
147                 requestType == BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION
148                         ? R.string.bluetooth_connect_access_dialog_negative
149                         : R.string.request_manage_bluetooth_permission_dont_allow);
150         p.mNegativeButtonListener = this;
151         mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
152         setupAlert();
153 
154     }
155     @Override
onBackPressed()156     public void onBackPressed() {
157         /*we need an answer so ignore back button presses during auth */
158         if(DEBUG) Log.i(TAG, "Back button pressed! ignoring");
159     }
160 
161     // TODO(edjee): createConnectionDialogView, createPhonebookDialogView and createMapDialogView
162     // are similar. Refactor them into one method.
createConnectionDialogView()163     private View createConnectionDialogView() {
164         String mRemoteName = Utils.createRemoteName(this, mDevice);
165         mView = getLayoutInflater().inflate(R.layout.bluetooth_access, null);
166         messageView = (TextView)mView.findViewById(R.id.message);
167         messageView.setText(getString(R.string.bluetooth_connect_access_dialog_content,
168                 mRemoteName, mRemoteName));
169         return mView;
170     }
171 
createPhonebookDialogView()172     private View createPhonebookDialogView() {
173         String mRemoteName = Utils.createRemoteName(this, mDevice);
174         mView = getLayoutInflater().inflate(R.layout.bluetooth_access, null);
175         messageView = (TextView)mView.findViewById(R.id.message);
176         messageView.setText(getString(R.string.bluetooth_phonebook_access_dialog_content,
177                 mRemoteName, mRemoteName));
178         return mView;
179     }
180 
createMapDialogView()181     private View createMapDialogView() {
182         String mRemoteName = Utils.createRemoteName(this, mDevice);
183         mView = getLayoutInflater().inflate(R.layout.bluetooth_access, null);
184         messageView = (TextView)mView.findViewById(R.id.message);
185         messageView.setText(getString(R.string.bluetooth_message_access_dialog_content,
186                 mRemoteName, mRemoteName));
187         return mView;
188     }
189 
createSapDialogView()190     private View createSapDialogView() {
191         String mRemoteName = Utils.createRemoteName(this, mDevice);
192         mView = getLayoutInflater().inflate(R.layout.bluetooth_access, null);
193         messageView = (TextView)mView.findViewById(R.id.message);
194         messageView.setText(getString(R.string.bluetooth_sim_card_access_dialog_content,
195                 mRemoteName, mRemoteName, getAnyPhoneNumberFromSubscriptions()));
196         return mView;
197     }
198 
onPositive()199     private void onPositive() {
200         if (DEBUG) Log.d(TAG, "onPositive");
201         sendReplyIntentToReceiver(true, true);
202         finish();
203     }
204 
onNegative()205     private void onNegative() {
206         if (DEBUG) Log.d(TAG, "onNegative");
207         sendReplyIntentToReceiver(false, true);
208     }
209 
210     @VisibleForTesting
sendReplyIntentToReceiver(final boolean allowed, final boolean always)211     void sendReplyIntentToReceiver(final boolean allowed, final boolean always) {
212         Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
213 
214         if (DEBUG) {
215             Log.i(TAG, "sendReplyIntentToReceiver() Request type: " + mRequestType
216                     + " mReturnPackage");
217         }
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_CONNECT);
226     }
227 
onClick(DialogInterface dialog, int which)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
onDestroy()243     protected void onDestroy() {
244         super.onDestroy();
245         if (mReceiverRegistered) {
246             unregisterReceiver(mReceiver);
247             mReceiverRegistered = false;
248         }
249     }
250 
onPreferenceChange(Preference preference, Object newValue)251     public boolean onPreferenceChange(Preference preference, Object newValue) {
252         return true;
253     }
254 
255     // find any phone number available from active subscriptions
getAnyPhoneNumberFromSubscriptions()256     String getAnyPhoneNumberFromSubscriptions() {
257         SubscriptionManager sm = getSystemService(SubscriptionManager.class);
258         List<SubscriptionInfo> subs = SubscriptionUtil.getActiveSubscriptions(sm);
259         if ((subs == null) || (subs.size() == 0)) {
260             return "";
261         }
262         return subs.stream()
263                 .map(subinfo -> SubscriptionUtil.getFormattedPhoneNumber(this, subinfo))
264                 .filter(phoneNumber -> !TextUtils.isEmpty(phoneNumber))
265                 .findAny().orElse("");
266     }
267 }
268