Loading android/app/src/com/android/bluetooth/pbap/BluetoothPbapActivity.java +7 −19 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ package com.android.bluetooth.pbap; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; Loading @@ -47,7 +48,6 @@ import android.text.TextWatcher; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.TextView; Loading Loading @@ -85,16 +85,14 @@ public class BluetoothPbapActivity extends AlertActivity private Button mOkButton; private CheckBox mAlwaysAllowed; private boolean mTimeout = false; private boolean mAlwaysAllowedValue = true; private static final int DISMISS_TIMEOUT_DIALOG = 0; private static final int DISMISS_TIMEOUT_DIALOG_VALUE = 2000; private BluetoothDevice mDevice; private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -110,6 +108,7 @@ public class BluetoothPbapActivity extends AlertActivity super.onCreate(savedInstanceState); Intent i = getIntent(); String action = i.getAction(); mDevice = i.getParcelableExtra(BluetoothPbapService.EXTRA_DEVICE); if (action.equals(BluetoothPbapService.AUTH_CHALL_ACTION)) { showPbapDialog(DIALOG_YES_NO_AUTH); mCurrentDialog = DIALOG_YES_NO_AUTH; Loading Loading @@ -142,10 +141,9 @@ public class BluetoothPbapActivity extends AlertActivity } private String createDisplayText(final int id) { String mRemoteName = BluetoothPbapService.getRemoteDeviceName(); switch (id) { case DIALOG_YES_NO_AUTH: String mMessage2 = getString(R.string.pbap_session_key_dialog_title, mRemoteName); String mMessage2 = getString(R.string.pbap_session_key_dialog_title, mDevice); return mMessage2; default: return null; Loading Loading @@ -193,16 +191,7 @@ public class BluetoothPbapActivity extends AlertActivity final String extraValue) { Intent intent = new Intent(intentName); intent.setPackage(BluetoothPbapService.THIS_PACKAGE_NAME); if (extraName != null) { intent.putExtra(extraName, extraValue); } sendBroadcast(intent); } private void sendIntentToReceiver(final String intentName, final String extraName, final boolean extraValue) { Intent intent = new Intent(intentName); intent.setPackage(BluetoothPbapService.THIS_PACKAGE_NAME); intent.putExtra(BluetoothPbapService.EXTRA_DEVICE, mDevice); if (extraName != null) { intent.putExtra(extraName, extraValue); } Loading Loading @@ -230,8 +219,7 @@ public class BluetoothPbapActivity extends AlertActivity private void onTimeout() { mTimeout = true; if (mCurrentDialog == DIALOG_YES_NO_AUTH) { mMessageView.setText(getString(R.string.pbap_authentication_timeout_message, BluetoothPbapService.getRemoteDeviceName())); mMessageView.setText(getString(R.string.pbap_authentication_timeout_message, mDevice)); mKeyView.setVisibility(View.GONE); mKeyView.clearFocus(); mKeyView.removeTextChangedListener(this); Loading android/app/src/com/android/bluetooth/pbap/BluetoothPbapAuthenticator.java +11 −17 Original line number Diff line number Diff line Loading @@ -32,8 +32,6 @@ package com.android.bluetooth.pbap; import android.os.Handler; import android.os.Message; import android.util.Log; import javax.obex.Authenticator; Loading @@ -44,39 +42,36 @@ import javax.obex.PasswordAuthentication; * authentication procedure. */ public class BluetoothPbapAuthenticator implements Authenticator { private static final String TAG = "BluetoothPbapAuthenticator"; private static final String TAG = "PbapAuthenticator"; private boolean mChallenged; private boolean mAuthCancelled; private String mSessionKey; private PbapStateMachine mPbapStateMachine; private Handler mCallback; public BluetoothPbapAuthenticator(final Handler callback) { mCallback = callback; BluetoothPbapAuthenticator(final PbapStateMachine stateMachine) { mPbapStateMachine = stateMachine; mChallenged = false; mAuthCancelled = false; mSessionKey = null; } public final synchronized void setChallenged(final boolean bool) { final synchronized void setChallenged(final boolean bool) { mChallenged = bool; } public final synchronized void setCancelled(final boolean bool) { final synchronized void setCancelled(final boolean bool) { mAuthCancelled = bool; } public final synchronized void setSessionKey(final String string) { final synchronized void setSessionKey(final String string) { mSessionKey = string; } private void waitUserConfirmation() { Message msg = Message.obtain(mCallback); msg.what = BluetoothPbapService.MSG_OBEX_AUTH_CHALL; msg.sendToTarget(); mPbapStateMachine.sendMessage(PbapStateMachine.CREATE_NOTIFICATION); mPbapStateMachine.sendMessageDelayed(PbapStateMachine.REMOVE_NOTIFICATION, BluetoothPbapService.USER_CONFIRM_TIMEOUT_VALUE); synchronized (this) { while (!mChallenged && !mAuthCancelled) { try { Loading @@ -93,8 +88,7 @@ public class BluetoothPbapAuthenticator implements Authenticator { final boolean isUserIdRequired, final boolean isFullAccess) { waitUserConfirmation(); if (mSessionKey.trim().length() != 0) { PasswordAuthentication pa = new PasswordAuthentication(null, mSessionKey.getBytes()); return pa; return new PasswordAuthentication(null, mSessionKey.getBytes()); } return null; } Loading android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java +8 −19 Original line number Diff line number Diff line Loading @@ -171,8 +171,6 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private boolean mVcardSelector = false; private int mMissedCallSize = 0; // record current path the client are browsing private String mCurrentPath = ""; Loading @@ -180,8 +178,6 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private Context mContext; private BluetoothPbapService mService; private BluetoothPbapVcardManager mVcardManager; private int mOrderBy = ORDER_BY_INDEXED; Loading @@ -204,6 +200,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private AppParamValue mConnAppParamValue; private PbapStateMachine mStateMachine; public static class ContentType { public static final int PHONEBOOK = 1; Loading @@ -216,12 +214,13 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { public static final int COMBINED_CALL_HISTORY = 5; } public BluetoothPbapObexServer(Handler callback, BluetoothPbapService service) { public BluetoothPbapObexServer(Handler callback, Context context, PbapStateMachine stateMachine) { super(); mCallback = callback; mService = service; mContext = service.getApplicationContext(); mContext = context; mVcardManager = new BluetoothPbapVcardManager(mContext); mStateMachine = stateMachine; } @Override Loading Loading @@ -284,9 +283,6 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { Log.v(TAG, "onConnect(): uuid is ok, will send out " + "MSG_SESSION_ESTABLISHED msg."); } Message msg = Message.obtain(mCallback); msg.what = BluetoothPbapService.MSG_SESSION_ESTABLISHED; msg.sendToTarget(); return ResponseCodes.OBEX_HTTP_OK; } Loading Loading @@ -383,14 +379,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { @Override public void onClose() { if (mCallback != null) { Message msg = Message.obtain(mCallback); msg.what = BluetoothPbapService.MSG_SERVERSESSION_CLOSE; msg.sendToTarget(); if (D) { Log.d(TAG, "onClose(): msg MSG_SERVERSESSION_CLOSE sent out."); } } mStateMachine.sendMessage(PbapStateMachine.DISCONNECT); } @Override Loading Loading @@ -1439,7 +1428,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private byte[] getDatabaseIdentifier() { mDatabaseIdentifierHigh = 0; mDatabaseIdentifierLow = mService.getDbIdentifier(); mDatabaseIdentifierLow = BluetoothPbapUtils.sDbIdentifier.get(); if (mDatabaseIdentifierLow != INVALID_VALUE_PARAMETER && mDatabaseIdentifierHigh != INVALID_VALUE_PARAMETER) { ByteBuffer ret = ByteBuffer.allocate(16); Loading android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java +104 −355 File changed.Preview size limit exceeded, changes collapsed. Show changes android/app/src/com/android/bluetooth/pbap/PbapStateMachine.java 0 → 100644 +353 −0 Original line number Diff line number Diff line /* * Copyright 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth.pbap; import android.annotation.NonNull; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import com.android.bluetooth.BluetoothObexTransport; import com.android.bluetooth.IObexConnectionHandler; import com.android.bluetooth.ObexRejectServer; import com.android.bluetooth.R; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import java.io.IOException; import javax.obex.ResponseCodes; import javax.obex.ServerSession; /** * Bluetooth PBAP StateMachine * (New connection socket) * WAITING FOR AUTH * | * | (request permission from Settings UI) * | * (Accept) / \ (Reject) * / \ * v v * CONNECTED -----> FINISHED * (OBEX Server done) */ class PbapStateMachine extends StateMachine { private static final String TAG = "PbapStateMachine"; private static final boolean DEBUG = true; private static final boolean VERBOSE = true; private static final String PBAP_OBEX_NOTIFICATION_CHANNEL = "pbap_obex_notification_channel"; private static final int NOTIFICATION_ID_AUTH = -1000002; // TODO: set a notification channel for each sm static final int AUTHORIZED = 1; static final int REJECTED = 2; static final int DISCONNECT = 3; static final int REQUEST_PERMISSION = 4; static final int CREATE_NOTIFICATION = 5; static final int REMOVE_NOTIFICATION = 6; static final int AUTH_KEY_INPUT = 7; static final int AUTH_CANCELLED = 8; BluetoothPbapService mService; IObexConnectionHandler mIObexConnectionHandler; private final WaitingForAuth mWaitingForAuth = new WaitingForAuth(); private final Finished mFinished = new Finished(); private final Connected mConnected = new Connected(); private BluetoothDevice mRemoteDevice; private Handler mServiceHandler; private BluetoothSocket mConnSocket; private BluetoothPbapObexServer mPbapServer; private BluetoothPbapAuthenticator mObexAuth; private ServerSession mServerSession; private PbapStateMachine(@NonNull BluetoothPbapService service, Looper looper, @NonNull BluetoothDevice device, @NonNull BluetoothSocket connSocket, IObexConnectionHandler obexConnectionHandler, Handler pbapHandler) { super(TAG, looper); mService = service; mIObexConnectionHandler = obexConnectionHandler; mRemoteDevice = device; mServiceHandler = pbapHandler; mConnSocket = connSocket; addState(mFinished); addState(mWaitingForAuth); addState(mConnected); setInitialState(mWaitingForAuth); } static PbapStateMachine make(BluetoothPbapService service, Looper looper, BluetoothDevice device, BluetoothSocket connSocket, IObexConnectionHandler obexConnectionHandler, Handler pbapHandler) { PbapStateMachine stateMachine = new PbapStateMachine(service, looper, device, connSocket, obexConnectionHandler, pbapHandler); stateMachine.start(); return stateMachine; } BluetoothDevice getRemoteDevice() { return mRemoteDevice; } private abstract class PbapStateBase extends State { /** * Get a state value from {@link BluetoothProfile} that represents the connection state of * this headset state * * @return a value in {@link BluetoothProfile#STATE_DISCONNECTED}, * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED}, or * {@link BluetoothProfile#STATE_DISCONNECTING} */ abstract int getConnectionStateInt(); } class WaitingForAuth extends PbapStateBase { @Override int getConnectionStateInt() { return BluetoothProfile.STATE_CONNECTING; } @Override public void enter() { mService.checkOrGetPhonebookPermission(PbapStateMachine.this); } @Override public boolean processMessage(Message message) { switch (message.what) { case AUTHORIZED: transitionTo(mConnected); break; case REJECTED: rejectConnection(); transitionTo(mFinished); break; case DISCONNECT: mServiceHandler.removeMessages(BluetoothPbapService.USER_TIMEOUT); Message msg = mServiceHandler.obtainMessage( BluetoothPbapService.USER_TIMEOUT); msg.obj = PbapStateMachine.this; msg.sendToTarget(); transitionTo(mFinished); break; } return HANDLED; } private void rejectConnection() { mPbapServer = new BluetoothPbapObexServer(mServiceHandler, mService, PbapStateMachine.this); BluetoothObexTransport transport = new BluetoothObexTransport(mConnSocket); ObexRejectServer server = new ObexRejectServer(ResponseCodes.OBEX_HTTP_UNAVAILABLE, mConnSocket); try { mServerSession = new ServerSession(transport, server, null); } catch (IOException ex) { Log.e(TAG, "Caught exception starting OBEX reject server session" + ex.toString()); } } } class Finished extends PbapStateBase { @Override int getConnectionStateInt() { return BluetoothProfile.STATE_DISCONNECTED; } @Override public void enter() { // Close OBEX server session if (mServerSession != null) { mServerSession.close(); mServerSession = null; } // Close connection socket try { mConnSocket.close(); mConnSocket = null; } catch (IOException e) { Log.e(TAG, "Close Connection Socket error: " + e.toString()); } mServiceHandler.obtainMessage(BluetoothPbapService.MSG_STATE_MACHINE_DONE) .sendToTarget(); } } class Connected extends PbapStateBase { @Override int getConnectionStateInt() { return BluetoothProfile.STATE_CONNECTED; } @Override public void enter() { try { startObexServerSession(); } catch (IOException ex) { Log.e(TAG, "Caught exception starting OBEX server session" + ex.toString()); } } @Override public void exit() { } @Override public boolean processMessage(Message message) { switch (message.what) { case DISCONNECT: stopObexServerSession(); break; case CREATE_NOTIFICATION: createPbapNotification(); break; case REMOVE_NOTIFICATION: Intent i = new Intent(BluetoothPbapService.USER_CONFIRM_TIMEOUT_ACTION); mService.sendBroadcast(i); notifyAuthCancelled(); removePbapNotification(NOTIFICATION_ID_AUTH); break; case AUTH_KEY_INPUT: String key = (String) message.obj; notifyAuthKeyInput(key); break; case AUTH_CANCELLED: notifyAuthCancelled(); break; } return HANDLED; } private void startObexServerSession() throws IOException { if (VERBOSE) { Log.v(TAG, "Pbap Service startObexServerSession"); } // acquire the wakeLock before start Obex transaction thread mServiceHandler.sendMessage( mServiceHandler.obtainMessage(BluetoothPbapService.MSG_ACQUIRE_WAKE_LOCK)); mPbapServer = new BluetoothPbapObexServer(mServiceHandler, mService, PbapStateMachine.this); synchronized (this) { mObexAuth = new BluetoothPbapAuthenticator(PbapStateMachine.this); mObexAuth.setChallenged(false); mObexAuth.setCancelled(false); } BluetoothObexTransport transport = new BluetoothObexTransport(mConnSocket); mServerSession = new ServerSession(transport, mPbapServer, mObexAuth); // It's ok to just use one wake lock // Message MSG_ACQUIRE_WAKE_LOCK is always surrounded by RELEASE. safe. } private void stopObexServerSession() { if (VERBOSE) { Log.v(TAG, "Pbap Service stopObexServerSession"); } transitionTo(mFinished); } private void createPbapNotification() { NotificationManager nm = (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE); NotificationChannel notificationChannel = new NotificationChannel( PBAP_OBEX_NOTIFICATION_CHANNEL, mService.getString(R.string.pbap_notification_group), NotificationManager.IMPORTANCE_HIGH); nm.createNotificationChannel(notificationChannel); // Create an intent triggered by clicking on the status icon. Intent clickIntent = new Intent(); clickIntent.setClass(mService, BluetoothPbapActivity.class); clickIntent.putExtra(BluetoothPbapService.EXTRA_DEVICE, mRemoteDevice); clickIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); clickIntent.setAction(BluetoothPbapService.AUTH_CHALL_ACTION); // Create an intent triggered by clicking on the // "Clear All Notifications" button Intent deleteIntent = new Intent(); deleteIntent.setClass(mService, BluetoothPbapService.class); deleteIntent.setAction(BluetoothPbapService.AUTH_CANCELLED_ACTION); String name = mRemoteDevice.getName(); Notification notification = new Notification.Builder(mService, PBAP_OBEX_NOTIFICATION_CHANNEL) .setWhen(System.currentTimeMillis()) .setContentTitle(mService.getString(R.string.auth_notif_title)) .setContentText(mService.getString(R.string.auth_notif_message, name)) .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth) .setTicker(mService.getString(R.string.auth_notif_ticker)) .setColor(mService.getResources().getColor( com.android.internal.R.color.system_notification_accent_color, mService.getTheme())) .setFlag(Notification.FLAG_AUTO_CANCEL, true) .setFlag(Notification.FLAG_ONLY_ALERT_ONCE, true) .setContentIntent(PendingIntent.getActivity(mService, 0, clickIntent, 0)) .setDeleteIntent(PendingIntent.getBroadcast(mService, 0, deleteIntent, 0)) .setLocalOnly(true) .build(); nm.notify(NOTIFICATION_ID_AUTH, notification); } private void removePbapNotification(int id) { NotificationManager nm = (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE); nm.cancel(id); } private void notifyAuthCancelled() { synchronized (this) { mObexAuth.setCancelled(true); mObexAuth.notify(); } } private void notifyAuthKeyInput(final String key) { synchronized (this) { if (key != null) { mObexAuth.setSessionKey(key); } mObexAuth.setChallenged(true); mObexAuth.notify(); } } } synchronized int getConnectionState() { return ((PbapStateBase) getCurrentState()).getConnectionStateInt(); } } Loading
android/app/src/com/android/bluetooth/pbap/BluetoothPbapActivity.java +7 −19 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ package com.android.bluetooth.pbap; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; Loading @@ -47,7 +48,6 @@ import android.text.TextWatcher; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.TextView; Loading Loading @@ -85,16 +85,14 @@ public class BluetoothPbapActivity extends AlertActivity private Button mOkButton; private CheckBox mAlwaysAllowed; private boolean mTimeout = false; private boolean mAlwaysAllowedValue = true; private static final int DISMISS_TIMEOUT_DIALOG = 0; private static final int DISMISS_TIMEOUT_DIALOG_VALUE = 2000; private BluetoothDevice mDevice; private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -110,6 +108,7 @@ public class BluetoothPbapActivity extends AlertActivity super.onCreate(savedInstanceState); Intent i = getIntent(); String action = i.getAction(); mDevice = i.getParcelableExtra(BluetoothPbapService.EXTRA_DEVICE); if (action.equals(BluetoothPbapService.AUTH_CHALL_ACTION)) { showPbapDialog(DIALOG_YES_NO_AUTH); mCurrentDialog = DIALOG_YES_NO_AUTH; Loading Loading @@ -142,10 +141,9 @@ public class BluetoothPbapActivity extends AlertActivity } private String createDisplayText(final int id) { String mRemoteName = BluetoothPbapService.getRemoteDeviceName(); switch (id) { case DIALOG_YES_NO_AUTH: String mMessage2 = getString(R.string.pbap_session_key_dialog_title, mRemoteName); String mMessage2 = getString(R.string.pbap_session_key_dialog_title, mDevice); return mMessage2; default: return null; Loading Loading @@ -193,16 +191,7 @@ public class BluetoothPbapActivity extends AlertActivity final String extraValue) { Intent intent = new Intent(intentName); intent.setPackage(BluetoothPbapService.THIS_PACKAGE_NAME); if (extraName != null) { intent.putExtra(extraName, extraValue); } sendBroadcast(intent); } private void sendIntentToReceiver(final String intentName, final String extraName, final boolean extraValue) { Intent intent = new Intent(intentName); intent.setPackage(BluetoothPbapService.THIS_PACKAGE_NAME); intent.putExtra(BluetoothPbapService.EXTRA_DEVICE, mDevice); if (extraName != null) { intent.putExtra(extraName, extraValue); } Loading Loading @@ -230,8 +219,7 @@ public class BluetoothPbapActivity extends AlertActivity private void onTimeout() { mTimeout = true; if (mCurrentDialog == DIALOG_YES_NO_AUTH) { mMessageView.setText(getString(R.string.pbap_authentication_timeout_message, BluetoothPbapService.getRemoteDeviceName())); mMessageView.setText(getString(R.string.pbap_authentication_timeout_message, mDevice)); mKeyView.setVisibility(View.GONE); mKeyView.clearFocus(); mKeyView.removeTextChangedListener(this); Loading
android/app/src/com/android/bluetooth/pbap/BluetoothPbapAuthenticator.java +11 −17 Original line number Diff line number Diff line Loading @@ -32,8 +32,6 @@ package com.android.bluetooth.pbap; import android.os.Handler; import android.os.Message; import android.util.Log; import javax.obex.Authenticator; Loading @@ -44,39 +42,36 @@ import javax.obex.PasswordAuthentication; * authentication procedure. */ public class BluetoothPbapAuthenticator implements Authenticator { private static final String TAG = "BluetoothPbapAuthenticator"; private static final String TAG = "PbapAuthenticator"; private boolean mChallenged; private boolean mAuthCancelled; private String mSessionKey; private PbapStateMachine mPbapStateMachine; private Handler mCallback; public BluetoothPbapAuthenticator(final Handler callback) { mCallback = callback; BluetoothPbapAuthenticator(final PbapStateMachine stateMachine) { mPbapStateMachine = stateMachine; mChallenged = false; mAuthCancelled = false; mSessionKey = null; } public final synchronized void setChallenged(final boolean bool) { final synchronized void setChallenged(final boolean bool) { mChallenged = bool; } public final synchronized void setCancelled(final boolean bool) { final synchronized void setCancelled(final boolean bool) { mAuthCancelled = bool; } public final synchronized void setSessionKey(final String string) { final synchronized void setSessionKey(final String string) { mSessionKey = string; } private void waitUserConfirmation() { Message msg = Message.obtain(mCallback); msg.what = BluetoothPbapService.MSG_OBEX_AUTH_CHALL; msg.sendToTarget(); mPbapStateMachine.sendMessage(PbapStateMachine.CREATE_NOTIFICATION); mPbapStateMachine.sendMessageDelayed(PbapStateMachine.REMOVE_NOTIFICATION, BluetoothPbapService.USER_CONFIRM_TIMEOUT_VALUE); synchronized (this) { while (!mChallenged && !mAuthCancelled) { try { Loading @@ -93,8 +88,7 @@ public class BluetoothPbapAuthenticator implements Authenticator { final boolean isUserIdRequired, final boolean isFullAccess) { waitUserConfirmation(); if (mSessionKey.trim().length() != 0) { PasswordAuthentication pa = new PasswordAuthentication(null, mSessionKey.getBytes()); return pa; return new PasswordAuthentication(null, mSessionKey.getBytes()); } return null; } Loading
android/app/src/com/android/bluetooth/pbap/BluetoothPbapObexServer.java +8 −19 Original line number Diff line number Diff line Loading @@ -171,8 +171,6 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private boolean mVcardSelector = false; private int mMissedCallSize = 0; // record current path the client are browsing private String mCurrentPath = ""; Loading @@ -180,8 +178,6 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private Context mContext; private BluetoothPbapService mService; private BluetoothPbapVcardManager mVcardManager; private int mOrderBy = ORDER_BY_INDEXED; Loading @@ -204,6 +200,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private AppParamValue mConnAppParamValue; private PbapStateMachine mStateMachine; public static class ContentType { public static final int PHONEBOOK = 1; Loading @@ -216,12 +214,13 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { public static final int COMBINED_CALL_HISTORY = 5; } public BluetoothPbapObexServer(Handler callback, BluetoothPbapService service) { public BluetoothPbapObexServer(Handler callback, Context context, PbapStateMachine stateMachine) { super(); mCallback = callback; mService = service; mContext = service.getApplicationContext(); mContext = context; mVcardManager = new BluetoothPbapVcardManager(mContext); mStateMachine = stateMachine; } @Override Loading Loading @@ -284,9 +283,6 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { Log.v(TAG, "onConnect(): uuid is ok, will send out " + "MSG_SESSION_ESTABLISHED msg."); } Message msg = Message.obtain(mCallback); msg.what = BluetoothPbapService.MSG_SESSION_ESTABLISHED; msg.sendToTarget(); return ResponseCodes.OBEX_HTTP_OK; } Loading Loading @@ -383,14 +379,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { @Override public void onClose() { if (mCallback != null) { Message msg = Message.obtain(mCallback); msg.what = BluetoothPbapService.MSG_SERVERSESSION_CLOSE; msg.sendToTarget(); if (D) { Log.d(TAG, "onClose(): msg MSG_SERVERSESSION_CLOSE sent out."); } } mStateMachine.sendMessage(PbapStateMachine.DISCONNECT); } @Override Loading Loading @@ -1439,7 +1428,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler { private byte[] getDatabaseIdentifier() { mDatabaseIdentifierHigh = 0; mDatabaseIdentifierLow = mService.getDbIdentifier(); mDatabaseIdentifierLow = BluetoothPbapUtils.sDbIdentifier.get(); if (mDatabaseIdentifierLow != INVALID_VALUE_PARAMETER && mDatabaseIdentifierHigh != INVALID_VALUE_PARAMETER) { ByteBuffer ret = ByteBuffer.allocate(16); Loading
android/app/src/com/android/bluetooth/pbap/BluetoothPbapService.java +104 −355 File changed.Preview size limit exceeded, changes collapsed. Show changes
android/app/src/com/android/bluetooth/pbap/PbapStateMachine.java 0 → 100644 +353 −0 Original line number Diff line number Diff line /* * Copyright 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth.pbap; import android.annotation.NonNull; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import com.android.bluetooth.BluetoothObexTransport; import com.android.bluetooth.IObexConnectionHandler; import com.android.bluetooth.ObexRejectServer; import com.android.bluetooth.R; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import java.io.IOException; import javax.obex.ResponseCodes; import javax.obex.ServerSession; /** * Bluetooth PBAP StateMachine * (New connection socket) * WAITING FOR AUTH * | * | (request permission from Settings UI) * | * (Accept) / \ (Reject) * / \ * v v * CONNECTED -----> FINISHED * (OBEX Server done) */ class PbapStateMachine extends StateMachine { private static final String TAG = "PbapStateMachine"; private static final boolean DEBUG = true; private static final boolean VERBOSE = true; private static final String PBAP_OBEX_NOTIFICATION_CHANNEL = "pbap_obex_notification_channel"; private static final int NOTIFICATION_ID_AUTH = -1000002; // TODO: set a notification channel for each sm static final int AUTHORIZED = 1; static final int REJECTED = 2; static final int DISCONNECT = 3; static final int REQUEST_PERMISSION = 4; static final int CREATE_NOTIFICATION = 5; static final int REMOVE_NOTIFICATION = 6; static final int AUTH_KEY_INPUT = 7; static final int AUTH_CANCELLED = 8; BluetoothPbapService mService; IObexConnectionHandler mIObexConnectionHandler; private final WaitingForAuth mWaitingForAuth = new WaitingForAuth(); private final Finished mFinished = new Finished(); private final Connected mConnected = new Connected(); private BluetoothDevice mRemoteDevice; private Handler mServiceHandler; private BluetoothSocket mConnSocket; private BluetoothPbapObexServer mPbapServer; private BluetoothPbapAuthenticator mObexAuth; private ServerSession mServerSession; private PbapStateMachine(@NonNull BluetoothPbapService service, Looper looper, @NonNull BluetoothDevice device, @NonNull BluetoothSocket connSocket, IObexConnectionHandler obexConnectionHandler, Handler pbapHandler) { super(TAG, looper); mService = service; mIObexConnectionHandler = obexConnectionHandler; mRemoteDevice = device; mServiceHandler = pbapHandler; mConnSocket = connSocket; addState(mFinished); addState(mWaitingForAuth); addState(mConnected); setInitialState(mWaitingForAuth); } static PbapStateMachine make(BluetoothPbapService service, Looper looper, BluetoothDevice device, BluetoothSocket connSocket, IObexConnectionHandler obexConnectionHandler, Handler pbapHandler) { PbapStateMachine stateMachine = new PbapStateMachine(service, looper, device, connSocket, obexConnectionHandler, pbapHandler); stateMachine.start(); return stateMachine; } BluetoothDevice getRemoteDevice() { return mRemoteDevice; } private abstract class PbapStateBase extends State { /** * Get a state value from {@link BluetoothProfile} that represents the connection state of * this headset state * * @return a value in {@link BluetoothProfile#STATE_DISCONNECTED}, * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED}, or * {@link BluetoothProfile#STATE_DISCONNECTING} */ abstract int getConnectionStateInt(); } class WaitingForAuth extends PbapStateBase { @Override int getConnectionStateInt() { return BluetoothProfile.STATE_CONNECTING; } @Override public void enter() { mService.checkOrGetPhonebookPermission(PbapStateMachine.this); } @Override public boolean processMessage(Message message) { switch (message.what) { case AUTHORIZED: transitionTo(mConnected); break; case REJECTED: rejectConnection(); transitionTo(mFinished); break; case DISCONNECT: mServiceHandler.removeMessages(BluetoothPbapService.USER_TIMEOUT); Message msg = mServiceHandler.obtainMessage( BluetoothPbapService.USER_TIMEOUT); msg.obj = PbapStateMachine.this; msg.sendToTarget(); transitionTo(mFinished); break; } return HANDLED; } private void rejectConnection() { mPbapServer = new BluetoothPbapObexServer(mServiceHandler, mService, PbapStateMachine.this); BluetoothObexTransport transport = new BluetoothObexTransport(mConnSocket); ObexRejectServer server = new ObexRejectServer(ResponseCodes.OBEX_HTTP_UNAVAILABLE, mConnSocket); try { mServerSession = new ServerSession(transport, server, null); } catch (IOException ex) { Log.e(TAG, "Caught exception starting OBEX reject server session" + ex.toString()); } } } class Finished extends PbapStateBase { @Override int getConnectionStateInt() { return BluetoothProfile.STATE_DISCONNECTED; } @Override public void enter() { // Close OBEX server session if (mServerSession != null) { mServerSession.close(); mServerSession = null; } // Close connection socket try { mConnSocket.close(); mConnSocket = null; } catch (IOException e) { Log.e(TAG, "Close Connection Socket error: " + e.toString()); } mServiceHandler.obtainMessage(BluetoothPbapService.MSG_STATE_MACHINE_DONE) .sendToTarget(); } } class Connected extends PbapStateBase { @Override int getConnectionStateInt() { return BluetoothProfile.STATE_CONNECTED; } @Override public void enter() { try { startObexServerSession(); } catch (IOException ex) { Log.e(TAG, "Caught exception starting OBEX server session" + ex.toString()); } } @Override public void exit() { } @Override public boolean processMessage(Message message) { switch (message.what) { case DISCONNECT: stopObexServerSession(); break; case CREATE_NOTIFICATION: createPbapNotification(); break; case REMOVE_NOTIFICATION: Intent i = new Intent(BluetoothPbapService.USER_CONFIRM_TIMEOUT_ACTION); mService.sendBroadcast(i); notifyAuthCancelled(); removePbapNotification(NOTIFICATION_ID_AUTH); break; case AUTH_KEY_INPUT: String key = (String) message.obj; notifyAuthKeyInput(key); break; case AUTH_CANCELLED: notifyAuthCancelled(); break; } return HANDLED; } private void startObexServerSession() throws IOException { if (VERBOSE) { Log.v(TAG, "Pbap Service startObexServerSession"); } // acquire the wakeLock before start Obex transaction thread mServiceHandler.sendMessage( mServiceHandler.obtainMessage(BluetoothPbapService.MSG_ACQUIRE_WAKE_LOCK)); mPbapServer = new BluetoothPbapObexServer(mServiceHandler, mService, PbapStateMachine.this); synchronized (this) { mObexAuth = new BluetoothPbapAuthenticator(PbapStateMachine.this); mObexAuth.setChallenged(false); mObexAuth.setCancelled(false); } BluetoothObexTransport transport = new BluetoothObexTransport(mConnSocket); mServerSession = new ServerSession(transport, mPbapServer, mObexAuth); // It's ok to just use one wake lock // Message MSG_ACQUIRE_WAKE_LOCK is always surrounded by RELEASE. safe. } private void stopObexServerSession() { if (VERBOSE) { Log.v(TAG, "Pbap Service stopObexServerSession"); } transitionTo(mFinished); } private void createPbapNotification() { NotificationManager nm = (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE); NotificationChannel notificationChannel = new NotificationChannel( PBAP_OBEX_NOTIFICATION_CHANNEL, mService.getString(R.string.pbap_notification_group), NotificationManager.IMPORTANCE_HIGH); nm.createNotificationChannel(notificationChannel); // Create an intent triggered by clicking on the status icon. Intent clickIntent = new Intent(); clickIntent.setClass(mService, BluetoothPbapActivity.class); clickIntent.putExtra(BluetoothPbapService.EXTRA_DEVICE, mRemoteDevice); clickIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); clickIntent.setAction(BluetoothPbapService.AUTH_CHALL_ACTION); // Create an intent triggered by clicking on the // "Clear All Notifications" button Intent deleteIntent = new Intent(); deleteIntent.setClass(mService, BluetoothPbapService.class); deleteIntent.setAction(BluetoothPbapService.AUTH_CANCELLED_ACTION); String name = mRemoteDevice.getName(); Notification notification = new Notification.Builder(mService, PBAP_OBEX_NOTIFICATION_CHANNEL) .setWhen(System.currentTimeMillis()) .setContentTitle(mService.getString(R.string.auth_notif_title)) .setContentText(mService.getString(R.string.auth_notif_message, name)) .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth) .setTicker(mService.getString(R.string.auth_notif_ticker)) .setColor(mService.getResources().getColor( com.android.internal.R.color.system_notification_accent_color, mService.getTheme())) .setFlag(Notification.FLAG_AUTO_CANCEL, true) .setFlag(Notification.FLAG_ONLY_ALERT_ONCE, true) .setContentIntent(PendingIntent.getActivity(mService, 0, clickIntent, 0)) .setDeleteIntent(PendingIntent.getBroadcast(mService, 0, deleteIntent, 0)) .setLocalOnly(true) .build(); nm.notify(NOTIFICATION_ID_AUTH, notification); } private void removePbapNotification(int id) { NotificationManager nm = (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE); nm.cancel(id); } private void notifyAuthCancelled() { synchronized (this) { mObexAuth.setCancelled(true); mObexAuth.notify(); } } private void notifyAuthKeyInput(final String key) { synchronized (this) { if (key != null) { mObexAuth.setSessionKey(key); } mObexAuth.setChallenged(true); mObexAuth.notify(); } } } synchronized int getConnectionState() { return ((PbapStateBase) getCurrentState()).getConnectionStateInt(); } }