Loading core/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 @@ -254,6 +255,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 @@ -768,7 +792,7 @@ public final class BluetoothAdapter { return true; } if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); return mManagerService.enable(); return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) { Log.e(TAG, "", e); } Loading Loading @@ -895,7 +919,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 @@ -927,7 +951,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 @@ -945,7 +969,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 core/java/android/bluetooth/IBluetoothManager.aidl +2 −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); int getState(); IBluetoothGatt getBluetoothGatt(); Loading core/res/res/values/symbols.xml +0 −2 Original line number Diff line number Diff line Loading @@ -2716,7 +2716,6 @@ <java-symbol type="bool" name="config_permissionReviewRequired" /> <java-symbol type="drawable" name="ic_restart" /> <java-symbol type="drawable" name="emergency_icon" /> Loading @@ -2731,5 +2730,4 @@ <!-- Network Recommendation --> <java-symbol type="array" name="config_networkRecommendationPackageNames" /> </resources> services/core/java/com/android/server/BluetoothManagerService.java +75 −15 Original line number Diff line number Diff line Loading @@ -35,11 +35,13 @@ 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.Bundle; import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; Loading Loading @@ -154,6 +156,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 @@ -183,7 +187,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { final boolean bluetoothDisallowed = newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH); if ((mEnable || mEnableExternal) && bluetoothDisallowed) { disable(true); try { disable("android.os.UserManagerInternal", true); } catch (RemoteException e) { // Shouldn't happen: startConsentUiIfNeeded not called // when from system. } } } }; Loading Loading @@ -257,6 +266,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 @@ -665,7 +679,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } public boolean enable() { public boolean enable(String packageName) throws RemoteException { if (isBluetoothDisallowed()) { if (DBG) { Slog.d(TAG,"enable(): not enabling - bluetooth disallowed"); Loading @@ -673,14 +687,25 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return false; } if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { 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 @@ -696,16 +721,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 @@ -724,6 +759,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 services/core/java/com/android/server/am/ActiveServices.java +2 −2 Original line number Diff line number Diff line Loading @@ -369,7 +369,7 @@ public final class ActiveServices { // we do not start the service and launch a review activity if the calling app // is in the foreground passing it a pending intent to start the service when // review is completed. if (Build.PERMISSIONS_REVIEW_REQUIRED) { if (mAm.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage, callingUid, service, callerFg, userId)) { return null; Loading Loading @@ -913,7 +913,7 @@ public final class ActiveServices { // we schedule binding to the service but do not start its process, then // we launch a review activity to which is passed a callback to invoke // when done to start the bound service's process to completing the binding. if (Build.PERMISSIONS_REVIEW_REQUIRED) { if (mAm.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired( s.packageName, s.userId)) { Loading Loading
core/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 @@ -254,6 +255,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 @@ -768,7 +792,7 @@ public final class BluetoothAdapter { return true; } if (DBG) Log.d(TAG, "enableBLE(): Calling enable"); return mManagerService.enable(); return mManagerService.enable(ActivityThread.currentPackageName()); } catch (RemoteException e) { Log.e(TAG, "", e); } Loading Loading @@ -895,7 +919,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 @@ -927,7 +951,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 @@ -945,7 +969,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
core/java/android/bluetooth/IBluetoothManager.aidl +2 −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); int getState(); IBluetoothGatt getBluetoothGatt(); Loading
core/res/res/values/symbols.xml +0 −2 Original line number Diff line number Diff line Loading @@ -2716,7 +2716,6 @@ <java-symbol type="bool" name="config_permissionReviewRequired" /> <java-symbol type="drawable" name="ic_restart" /> <java-symbol type="drawable" name="emergency_icon" /> Loading @@ -2731,5 +2730,4 @@ <!-- Network Recommendation --> <java-symbol type="array" name="config_networkRecommendationPackageNames" /> </resources>
services/core/java/com/android/server/BluetoothManagerService.java +75 −15 Original line number Diff line number Diff line Loading @@ -35,11 +35,13 @@ 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.Bundle; import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; Loading Loading @@ -154,6 +156,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 @@ -183,7 +187,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { final boolean bluetoothDisallowed = newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH); if ((mEnable || mEnableExternal) && bluetoothDisallowed) { disable(true); try { disable("android.os.UserManagerInternal", true); } catch (RemoteException e) { // Shouldn't happen: startConsentUiIfNeeded not called // when from system. } } } }; Loading Loading @@ -257,6 +266,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 @@ -665,7 +679,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } public boolean enable() { public boolean enable(String packageName) throws RemoteException { if (isBluetoothDisallowed()) { if (DBG) { Slog.d(TAG,"enable(): not enabling - bluetooth disallowed"); Loading @@ -673,14 +687,25 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return false; } if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) { 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 @@ -696,16 +721,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 @@ -724,6 +759,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
services/core/java/com/android/server/am/ActiveServices.java +2 −2 Original line number Diff line number Diff line Loading @@ -369,7 +369,7 @@ public final class ActiveServices { // we do not start the service and launch a review activity if the calling app // is in the foreground passing it a pending intent to start the service when // review is completed. if (Build.PERMISSIONS_REVIEW_REQUIRED) { if (mAm.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage, callingUid, service, callerFg, userId)) { return null; Loading Loading @@ -913,7 +913,7 @@ public final class ActiveServices { // we schedule binding to the service but do not start its process, then // we launch a review activity to which is passed a callback to invoke // when done to start the bound service's process to completing the binding. if (Build.PERMISSIONS_REVIEW_REQUIRED) { if (mAm.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) { if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired( s.packageName, s.userId)) { Loading