• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2008-2009, Motorola, Inc.
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * - Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * - Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * - Neither the name of the Motorola, Inc. nor the names of its contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 package com.android.bluetooth.pbap;
34 
35 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
36 
37 import android.bluetooth.AlertActivity;
38 import android.bluetooth.BluetoothDevice;
39 import android.content.BroadcastReceiver;
40 import android.content.Context;
41 import android.content.DialogInterface;
42 import android.content.Intent;
43 import android.content.IntentFilter;
44 import android.os.Bundle;
45 import android.os.Handler;
46 import android.os.Message;
47 import android.preference.Preference;
48 import android.text.InputFilter;
49 import android.text.InputFilter.LengthFilter;
50 import android.text.TextWatcher;
51 import android.util.Log;
52 import android.view.View;
53 import android.widget.EditText;
54 import android.widget.TextView;
55 
56 import com.android.bluetooth.R;
57 
58 /**
59  * PbapActivity shows two dialogues: One for accepting incoming pbap request and
60  * the other prompts the user to enter a session key for authentication with a
61  * remote Bluetooth device.
62  */
63 public class BluetoothPbapActivity extends AlertActivity
64         implements Preference.OnPreferenceChangeListener, TextWatcher {
65     private static final String TAG = "BluetoothPbapActivity";
66 
67     private static final boolean V = BluetoothPbapService.VERBOSE;
68 
69     private static final int BLUETOOTH_OBEX_AUTHKEY_MAX_LENGTH = 16;
70 
71     private static final int DIALOG_YES_NO_AUTH = 1;
72 
73     private static final String KEY_USER_TIMEOUT = "user_timeout";
74 
75     private View mView;
76 
77     private EditText mKeyView;
78 
79     private TextView mMessageView;
80 
81     private String mSessionKey = "";
82 
83     private int mCurrentDialog;
84 
85     private boolean mTimeout = false;
86 
87     private static final int DISMISS_TIMEOUT_DIALOG = 0;
88 
89     private static final int DISMISS_TIMEOUT_DIALOG_VALUE = 2000;
90 
91     private BluetoothDevice mDevice;
92 
93     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
94         @Override
95         public void onReceive(Context context, Intent intent) {
96             if (!BluetoothPbapService.USER_CONFIRM_TIMEOUT_ACTION.equals(intent.getAction())) {
97                 return;
98             }
99             onTimeout();
100         }
101     };
102 
103     @Override
onCreate(Bundle savedInstanceState)104     protected void onCreate(Bundle savedInstanceState) {
105         super.onCreate(savedInstanceState);
106 
107         getWindow().addPrivateFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
108         Intent i = getIntent();
109         String action = i.getAction();
110         mDevice = i.getParcelableExtra(BluetoothPbapService.EXTRA_DEVICE);
111         if (action != null && action.equals(BluetoothPbapService.AUTH_CHALL_ACTION)) {
112             showPbapDialog(DIALOG_YES_NO_AUTH);
113             mCurrentDialog = DIALOG_YES_NO_AUTH;
114         } else {
115             Log.e(TAG, "Error: this activity may be started only with intent "
116                     + "PBAP_ACCESS_REQUEST or PBAP_AUTH_CHALL ");
117             finish();
118         }
119         registerReceiver(mReceiver,
120                 new IntentFilter(BluetoothPbapService.USER_CONFIRM_TIMEOUT_ACTION));
121     }
122 
showPbapDialog(int id)123     private void showPbapDialog(int id) {
124         switch (id) {
125             case DIALOG_YES_NO_AUTH:
126                 mAlertBuilder.setTitle(getString(R.string.pbap_session_key_dialog_header));
127                 mAlertBuilder.setView(createView(DIALOG_YES_NO_AUTH));
128                 mAlertBuilder.setPositiveButton(android.R.string.ok,
129                         (dialog, which) -> onPositive());
130                 mAlertBuilder.setNegativeButton(android.R.string.cancel,
131                         (dialog, which) -> onNegative());
132                 setupAlert();
133                 changeButtonEnabled(DialogInterface.BUTTON_POSITIVE, false);
134                 break;
135             default:
136                 break;
137         }
138     }
139 
createDisplayText(final int id)140     private String createDisplayText(final int id) {
141         switch (id) {
142             case DIALOG_YES_NO_AUTH:
143                 String mMessage2 = getString(R.string.pbap_session_key_dialog_title, mDevice);
144                 return mMessage2;
145             default:
146                 return null;
147         }
148     }
149 
createView(final int id)150     private View createView(final int id) {
151         switch (id) {
152             case DIALOG_YES_NO_AUTH:
153                 mView = getLayoutInflater().inflate(R.layout.auth, null);
154                 mMessageView = (TextView) mView.findViewById(R.id.message);
155                 mMessageView.setText(createDisplayText(id));
156                 mKeyView = (EditText) mView.findViewById(R.id.text);
157                 mKeyView.addTextChangedListener(this);
158                 mKeyView.setFilters(new InputFilter[]{
159                         new LengthFilter(BLUETOOTH_OBEX_AUTHKEY_MAX_LENGTH)
160                 });
161                 return mView;
162             default:
163                 return null;
164         }
165     }
166 
onPositive()167     private void onPositive() {
168         if (mCurrentDialog == DIALOG_YES_NO_AUTH) {
169             mSessionKey = mKeyView.getText().toString();
170         }
171 
172         if (!mTimeout) {
173             if (mCurrentDialog == DIALOG_YES_NO_AUTH) {
174                 sendIntentToReceiver(BluetoothPbapService.AUTH_RESPONSE_ACTION,
175                         BluetoothPbapService.EXTRA_SESSION_KEY, mSessionKey);
176                 mKeyView.removeTextChangedListener(this);
177             }
178         }
179         mTimeout = false;
180         finish();
181     }
182 
onNegative()183     private void onNegative() {
184         if (mCurrentDialog == DIALOG_YES_NO_AUTH) {
185             sendIntentToReceiver(BluetoothPbapService.AUTH_CANCELLED_ACTION, null, null);
186             mKeyView.removeTextChangedListener(this);
187         }
188         finish();
189     }
190 
sendIntentToReceiver(final String intentName, final String extraName, final String extraValue)191     private void sendIntentToReceiver(final String intentName, final String extraName,
192             final String extraValue) {
193         Intent intent = new Intent(intentName);
194         intent.setPackage(BluetoothPbapService.THIS_PACKAGE_NAME);
195         intent.putExtra(BluetoothPbapService.EXTRA_DEVICE, mDevice);
196         if (extraName != null) {
197             intent.putExtra(extraName, extraValue);
198         }
199         sendBroadcast(intent);
200     }
201 
onTimeout()202     private void onTimeout() {
203         mTimeout = true;
204         if (mCurrentDialog == DIALOG_YES_NO_AUTH) {
205             mMessageView.setText(getString(R.string.pbap_authentication_timeout_message, mDevice));
206             mKeyView.setVisibility(View.GONE);
207             mKeyView.clearFocus();
208             mKeyView.removeTextChangedListener(this);
209             changeButtonEnabled(DialogInterface.BUTTON_POSITIVE, true);
210             changeButtonVisibility(DialogInterface.BUTTON_NEGATIVE, View.GONE);
211         }
212 
213         mTimeoutHandler.sendMessageDelayed(mTimeoutHandler.obtainMessage(DISMISS_TIMEOUT_DIALOG),
214                 DISMISS_TIMEOUT_DIALOG_VALUE);
215     }
216 
217     @Override
onRestoreInstanceState(Bundle savedInstanceState)218     protected void onRestoreInstanceState(Bundle savedInstanceState) {
219         super.onRestoreInstanceState(savedInstanceState);
220         mTimeout = savedInstanceState.getBoolean(KEY_USER_TIMEOUT);
221         if (V) {
222             Log.v(TAG, "onRestoreInstanceState() mTimeout: " + mTimeout);
223         }
224         if (mTimeout) {
225             onTimeout();
226         }
227     }
228 
229     @Override
onSaveInstanceState(Bundle outState)230     protected void onSaveInstanceState(Bundle outState) {
231         super.onSaveInstanceState(outState);
232         outState.putBoolean(KEY_USER_TIMEOUT, mTimeout);
233     }
234 
235     @Override
onDestroy()236     protected void onDestroy() {
237         super.onDestroy();
238         unregisterReceiver(mReceiver);
239     }
240 
241     @Override
onPreferenceChange(Preference preference, Object newValue)242     public boolean onPreferenceChange(Preference preference, Object newValue) {
243         return true;
244     }
245 
246     @Override
beforeTextChanged(CharSequence s, int start, int before, int after)247     public void beforeTextChanged(CharSequence s, int start, int before, int after) {
248     }
249 
250     @Override
onTextChanged(CharSequence s, int start, int before, int count)251     public void onTextChanged(CharSequence s, int start, int before, int count) {
252     }
253 
254     @Override
afterTextChanged(android.text.Editable s)255     public void afterTextChanged(android.text.Editable s) {
256         if (s.length() > 0) {
257             changeButtonEnabled(DialogInterface.BUTTON_POSITIVE, true);
258         }
259     }
260 
261     private final Handler mTimeoutHandler = new Handler() {
262         @Override
263         public void handleMessage(Message msg) {
264             switch (msg.what) {
265                 case DISMISS_TIMEOUT_DIALOG:
266                     if (V) {
267                         Log.v(TAG, "Received DISMISS_TIMEOUT_DIALOG msg.");
268                     }
269                     finish();
270                     break;
271                 default:
272                     break;
273             }
274         }
275     };
276 }
277