Loading framework/java/android/bluetooth/BluetoothAdapter.java +28 −4 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.app.ActivityThread; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; Loading Loading @@ -251,6 +252,29 @@ public final class BluetoothAdapter { public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"; /** * Activity Action: Show a system activity that allows the user to turn off * Bluetooth. This is used only if permission review is enabled which is for * apps targeting API less than 23 require a permission review before any of * the app's components can run. * <p>This system activity will return once Bluetooth has completed turning * off, or the user has decided not to turn Bluetooth off. * <p>Notification of the result of this activity is posted using the * {@link android.app.Activity#onActivityResult} callback. The * <code>resultCode</code> * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been * turned off or {@link android.app.Activity#RESULT_CANCELED} if the user * has rejected the request or an error has occurred. * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED} * for global notification whenever Bluetooth is turned on or off. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} * * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE"; /** * Activity Action: Show a system activity that allows user to enable BLE scans even when * Bluetooth is turned off.<p> Loading Loading @@ -775,7 +799,7 @@ public final class BluetoothAdapter { try { if (DBG) Log.d(TAG, "Calling enableBLE"); mManagerService.updateBleAppCount(mToken, true); return mManagerService.enable(); return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) { Log.e(TAG, "", e); } Loading Loading @@ -902,7 +926,7 @@ public final class BluetoothAdapter { return true; } try { return mManagerService.enable(); return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } Loading Loading @@ -934,7 +958,7 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean disable() { try { return mManagerService.disable(true); return mManagerService.disable(ActivityThread.currentPackageName(), true); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } Loading @@ -952,7 +976,7 @@ public final class BluetoothAdapter { public boolean disable(boolean persist) { try { return mManagerService.disable(persist); return mManagerService.disable(ActivityThread.currentPackageName(), persist); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } Loading framework/java/android/bluetooth/IBluetoothManager.aidl +3 −2 Original line number Diff line number Diff line Loading @@ -34,9 +34,9 @@ interface IBluetoothManager void registerStateChangeCallback(in IBluetoothStateChangeCallback callback); void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback); boolean isEnabled(); boolean enable(); boolean enable(String packageName); boolean enableNoAutoConnect(); boolean disable(boolean persist); boolean disable(String packageName, boolean persist); IBluetoothGatt getBluetoothGatt(); boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); Loading @@ -49,3 +49,4 @@ interface IBluetoothManager int updateBleAppCount(IBinder b, boolean enable); boolean isBleAppPresent(); } service/java/com/android/server/bluetooth/BluetoothManagerService.java +69 −14 Original line number Diff line number Diff line Loading @@ -35,10 +35,12 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; Loading Loading @@ -151,6 +153,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private final Map <Integer, ProfileServiceConnections> mProfileServices = new HashMap <Integer, ProfileServiceConnections>(); private final boolean mPermissionReviewRequired; private void registerForAirplaneMode(IntentFilter filter) { final ContentResolver resolver = mContext.getContentResolver(); final String airplaneModeRadios = Settings.Global.getString(resolver, Loading Loading @@ -243,6 +247,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mHandler = new BluetoothHandler(IoThread.get().getLooper()); mContext = context; mPermissionReviewRequired = Build.PERMISSIONS_REVIEW_REQUIRED || context.getResources().getBoolean( com.android.internal.R.bool.config_permissionReviewRequired); mBluetooth = null; mBluetoothBinder = null; mBluetoothGatt = null; Loading Loading @@ -626,15 +635,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } public boolean enable() { if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { public boolean enable(String packageName) throws RemoteException { final int callingUid = Binder.getCallingUid(); final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; if (!callerSystem) { if (!checkIfCallerIsForegroundUser()) { Slog.w(TAG, "enable(): not allowed for non-active and non system user"); return false; } mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); if (!isEnabled() && mPermissionReviewRequired && startConsentUiIfNeeded(packageName, callingUid, BluetoothAdapter.ACTION_REQUEST_ENABLE)) { return false; } } if (DBG) { Slog.d(TAG,"enable(): mBluetooth =" + mBluetooth + " mBinding = " + mBinding + " mState = " + mState); Loading @@ -650,16 +670,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } public boolean disable(boolean persist) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); public boolean disable(String packageName, boolean persist) throws RemoteException { final int callingUid = Binder.getCallingUid(); final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { if (!callerSystem) { if (!checkIfCallerIsForegroundUser()) { Slog.w(TAG, "disable(): not allowed for non-active and non system user"); return false; } mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); if (isEnabled() && mPermissionReviewRequired && startConsentUiIfNeeded(packageName, callingUid, BluetoothAdapter.ACTION_REQUEST_DISABLE)) { return false; } } if (DBG) { Slog.d(TAG,"disable(): mBluetooth = " + mBluetooth + " mBinding = " + mBinding); Loading @@ -678,6 +708,31 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } private boolean startConsentUiIfNeeded(String packageName, int callingUid, String intentAction) throws RemoteException { try { // Validate the package only if we are going to use it ApplicationInfo applicationInfo = mContext.getPackageManager() .getApplicationInfoAsUser(packageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callingUid)); if (applicationInfo.uid != callingUid) { throw new SecurityException("Package " + callingUid + " not in uid " + callingUid); } // Legacy apps in permission review mode trigger a user prompt if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { Intent intent = new Intent(intentAction); mContext.startActivity(intent); return true; } } catch (PackageManager.NameNotFoundException e) { throw new RemoteException(e.getMessage()); } return false; } public void unbindAndFinish() { if (DBG) { Slog.d(TAG,"unbindAndFinish(): " + mBluetooth + Loading Loading
framework/java/android/bluetooth/BluetoothAdapter.java +28 −4 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.app.ActivityThread; import android.bluetooth.le.BluetoothLeAdvertiser; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; Loading Loading @@ -251,6 +252,29 @@ public final class BluetoothAdapter { public static final String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE"; /** * Activity Action: Show a system activity that allows the user to turn off * Bluetooth. This is used only if permission review is enabled which is for * apps targeting API less than 23 require a permission review before any of * the app's components can run. * <p>This system activity will return once Bluetooth has completed turning * off, or the user has decided not to turn Bluetooth off. * <p>Notification of the result of this activity is posted using the * {@link android.app.Activity#onActivityResult} callback. The * <code>resultCode</code> * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been * turned off or {@link android.app.Activity#RESULT_CANCELED} if the user * has rejected the request or an error has occurred. * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED} * for global notification whenever Bluetooth is turned on or off. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} * * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE"; /** * Activity Action: Show a system activity that allows user to enable BLE scans even when * Bluetooth is turned off.<p> Loading Loading @@ -775,7 +799,7 @@ public final class BluetoothAdapter { try { if (DBG) Log.d(TAG, "Calling enableBLE"); mManagerService.updateBleAppCount(mToken, true); return mManagerService.enable(); return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) { Log.e(TAG, "", e); } Loading Loading @@ -902,7 +926,7 @@ public final class BluetoothAdapter { return true; } try { return mManagerService.enable(); return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } Loading Loading @@ -934,7 +958,7 @@ public final class BluetoothAdapter { @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean disable() { try { return mManagerService.disable(true); return mManagerService.disable(ActivityThread.currentPackageName(), true); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } Loading @@ -952,7 +976,7 @@ public final class BluetoothAdapter { public boolean disable(boolean persist) { try { return mManagerService.disable(persist); return mManagerService.disable(ActivityThread.currentPackageName(), persist); } catch (RemoteException e) {Log.e(TAG, "", e);} return false; } Loading
framework/java/android/bluetooth/IBluetoothManager.aidl +3 −2 Original line number Diff line number Diff line Loading @@ -34,9 +34,9 @@ interface IBluetoothManager void registerStateChangeCallback(in IBluetoothStateChangeCallback callback); void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback); boolean isEnabled(); boolean enable(); boolean enable(String packageName); boolean enableNoAutoConnect(); boolean disable(boolean persist); boolean disable(String packageName, boolean persist); IBluetoothGatt getBluetoothGatt(); boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy); Loading @@ -49,3 +49,4 @@ interface IBluetoothManager int updateBleAppCount(IBinder b, boolean enable); boolean isBleAppPresent(); }
service/java/com/android/server/bluetooth/BluetoothManagerService.java +69 −14 Original line number Diff line number Diff line Loading @@ -35,10 +35,12 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; Loading Loading @@ -151,6 +153,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private final Map <Integer, ProfileServiceConnections> mProfileServices = new HashMap <Integer, ProfileServiceConnections>(); private final boolean mPermissionReviewRequired; private void registerForAirplaneMode(IntentFilter filter) { final ContentResolver resolver = mContext.getContentResolver(); final String airplaneModeRadios = Settings.Global.getString(resolver, Loading Loading @@ -243,6 +247,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mHandler = new BluetoothHandler(IoThread.get().getLooper()); mContext = context; mPermissionReviewRequired = Build.PERMISSIONS_REVIEW_REQUIRED || context.getResources().getBoolean( com.android.internal.R.bool.config_permissionReviewRequired); mBluetooth = null; mBluetoothBinder = null; mBluetoothGatt = null; Loading Loading @@ -626,15 +635,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } public boolean enable() { if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { public boolean enable(String packageName) throws RemoteException { final int callingUid = Binder.getCallingUid(); final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; if (!callerSystem) { if (!checkIfCallerIsForegroundUser()) { Slog.w(TAG, "enable(): not allowed for non-active and non system user"); return false; } mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); if (!isEnabled() && mPermissionReviewRequired && startConsentUiIfNeeded(packageName, callingUid, BluetoothAdapter.ACTION_REQUEST_ENABLE)) { return false; } } if (DBG) { Slog.d(TAG,"enable(): mBluetooth =" + mBluetooth + " mBinding = " + mBinding + " mState = " + mState); Loading @@ -650,16 +670,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } public boolean disable(boolean persist) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permissicacheNameAndAddresson"); public boolean disable(String packageName, boolean persist) throws RemoteException { final int callingUid = Binder.getCallingUid(); final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { if (!callerSystem) { if (!checkIfCallerIsForegroundUser()) { Slog.w(TAG, "disable(): not allowed for non-active and non system user"); return false; } mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); if (isEnabled() && mPermissionReviewRequired && startConsentUiIfNeeded(packageName, callingUid, BluetoothAdapter.ACTION_REQUEST_DISABLE)) { return false; } } if (DBG) { Slog.d(TAG,"disable(): mBluetooth = " + mBluetooth + " mBinding = " + mBinding); Loading @@ -678,6 +708,31 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } private boolean startConsentUiIfNeeded(String packageName, int callingUid, String intentAction) throws RemoteException { try { // Validate the package only if we are going to use it ApplicationInfo applicationInfo = mContext.getPackageManager() .getApplicationInfoAsUser(packageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callingUid)); if (applicationInfo.uid != callingUid) { throw new SecurityException("Package " + callingUid + " not in uid " + callingUid); } // Legacy apps in permission review mode trigger a user prompt if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { Intent intent = new Intent(intentAction); mContext.startActivity(intent); return true; } } catch (PackageManager.NameNotFoundException e) { throw new RemoteException(e.getMessage()); } return false; } public void unbindAndFinish() { if (DBG) { Slog.d(TAG,"unbindAndFinish(): " + mBluetooth + Loading