resolve merge conflicts of 9cc7ebe to stage-aosp-master
Change-Id: Ia1cdf49d77a574c38ed5cc33c31d5cf930103484
This commit is contained in:
@@ -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;
|
||||
@@ -271,6 +272,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>
|
||||
@@ -656,30 +680,7 @@ public final class BluetoothAdapter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs action based on user action to turn BT ON
|
||||
* or OFF if BT is in BLE_ON state
|
||||
*/
|
||||
private void notifyUserAction(boolean enable) {
|
||||
try {
|
||||
mServiceLock.readLock().lock();
|
||||
if (mService == null) {
|
||||
Log.e(TAG, "mService is null");
|
||||
return;
|
||||
}
|
||||
if (enable) {
|
||||
mService.onLeServiceUp(); //NA:TODO implementation pending
|
||||
} else {
|
||||
mService.onBrEdrDown(); //NA:TODO implementation pending
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
} finally {
|
||||
mServiceLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns off Bluetooth LE which was earlier turned on by calling EnableBLE().
|
||||
* Turns off Bluetooth LE which was earlier turned on by calling enableBLE().
|
||||
*
|
||||
* <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition
|
||||
* to STATE_OFF and completely shut-down Bluetooth
|
||||
@@ -709,61 +710,50 @@ public final class BluetoothAdapter {
|
||||
if (!isBleScanAlwaysAvailable()) return false;
|
||||
|
||||
int state = getLeState();
|
||||
if (state == BluetoothAdapter.STATE_ON) {
|
||||
if (DBG) Log.d (TAG, "STATE_ON: shouldn't disable");
|
||||
if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_BLE_ON) {
|
||||
String packageName = ActivityThread.currentPackageName();
|
||||
if (DBG) Log.d (TAG, "disableBLE(): de-registering " + packageName);
|
||||
try {
|
||||
mManagerService.updateBleAppCount(mToken, false);
|
||||
mManagerService.updateBleAppCount(mToken, false, packageName);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if (state == BluetoothAdapter.STATE_BLE_ON) {
|
||||
if (DBG) Log.d (TAG, "STATE_BLE_ON");
|
||||
int bleAppCnt = 0;
|
||||
try {
|
||||
bleAppCnt = mManagerService.updateBleAppCount(mToken, false);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
if (bleAppCnt == 0) {
|
||||
// Disable only if there are no other clients
|
||||
notifyUserAction(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DBG) Log.d (TAG, "STATE_OFF: Already disabled");
|
||||
if (DBG) Log.d (TAG, "disableBLE(): Already disabled");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Special Applications who want to only turn on Bluetooth Low Energy (BLE) would
|
||||
* EnableBLE, EnableBLE brings-up Bluetooth so that application can access
|
||||
* only LE related feature (Bluetooth GATT layers interfaces using the respective class)
|
||||
* EnableBLE in turn registers the existance of a special App which wants to
|
||||
* turn on Bluetooth Low enrgy part without making it visible at the settings UI
|
||||
* as Bluetooth ON.
|
||||
* <p>Invoking EnableBLE when Bluetooth is already in ON state, would just registers
|
||||
* the existance of special Application and doesn't do anything to current BT state.
|
||||
* when user turn OFF Bluetooth from UI, if there is an existance of special app, Bluetooth
|
||||
* would stay in BLE_ON state so that LE features are still acessible to the special
|
||||
* Applications.
|
||||
* Applications who want to only use Bluetooth Low Energy (BLE) can call enableBLE.
|
||||
*
|
||||
* <p>This is an asynchronous call: it will return immediately, and
|
||||
* enableBLE registers the existence of an app using only LE functions.
|
||||
*
|
||||
* enableBLE may enable Bluetooth to an LE only mode so that an app can use
|
||||
* LE related features (BluetoothGatt or BluetoothGattServer classes)
|
||||
*
|
||||
* If the user disables Bluetooth while an app is registered to use LE only features,
|
||||
* Bluetooth will remain on in LE only mode for the app.
|
||||
*
|
||||
* When Bluetooth is in LE only mode, it is not shown as ON to the UI.
|
||||
*
|
||||
* <p>This is an asynchronous call: it returns immediately, and
|
||||
* clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
|
||||
* to be notified of subsequent adapter state changes. If this call returns
|
||||
* true, then the adapter state will immediately transition from {@link
|
||||
* #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, and some time
|
||||
* later transition to either {@link #STATE_OFF} or {@link
|
||||
* #STATE_BLE_ON}. If this call returns false then there was an
|
||||
* immediate problem that will prevent the adapter from being turned on -
|
||||
* such as Airplane mode, or the adapter is already turned on.
|
||||
* (@link #ACTION_BLE_STATE_CHANGED) returns the Bluetooth Adapter's various
|
||||
* to be notified of adapter state changes.
|
||||
*
|
||||
* If this call returns * true, then the adapter state is either in a mode where
|
||||
* LE is available, or will transition from {@link #STATE_OFF} to {@link #STATE_BLE_TURNING_ON},
|
||||
* and some time later transition to either {@link #STATE_OFF} or {@link #STATE_BLE_ON}.
|
||||
*
|
||||
* If this call returns false then there was an immediate problem that prevents the
|
||||
* adapter from being turned on - such as Airplane mode.
|
||||
*
|
||||
* {@link #ACTION_BLE_STATE_CHANGED} returns the Bluetooth Adapter's various
|
||||
* states, It includes all the classic Bluetooth Adapter states along with
|
||||
* internal BLE only states
|
||||
*
|
||||
* @return true to indicate Bluetooth LE start-up has begun, or false on
|
||||
* @return true to indicate Bluetooth LE will be available, or false on
|
||||
* immediate error
|
||||
* @hide
|
||||
*/
|
||||
@@ -772,13 +762,14 @@ public final class BluetoothAdapter {
|
||||
if (!isBleScanAlwaysAvailable()) return false;
|
||||
|
||||
try {
|
||||
mManagerService.updateBleAppCount(mToken, true);
|
||||
String packageName = ActivityThread.currentPackageName();
|
||||
mManagerService.updateBleAppCount(mToken, true, packageName);
|
||||
if (isLeEnabled()) {
|
||||
if (DBG) Log.d(TAG, "enableBLE(): Bluetooth already enabled");
|
||||
return true;
|
||||
}
|
||||
if (DBG) Log.d(TAG, "enableBLE(): Calling enable");
|
||||
return mManagerService.enable();
|
||||
return mManagerService.enable(packageName);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
}
|
||||
@@ -905,7 +896,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;
|
||||
}
|
||||
@@ -937,7 +928,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;
|
||||
}
|
||||
@@ -955,7 +946,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;
|
||||
}
|
||||
@@ -1916,9 +1907,6 @@ public final class BluetoothAdapter {
|
||||
} else if (profile == BluetoothProfile.MAP_CLIENT) {
|
||||
BluetoothMapClient mapClient = new BluetoothMapClient(context, listener);
|
||||
return true;
|
||||
} else if (profile == BluetoothProfile.INPUT_HOST) {
|
||||
BluetoothInputHost iHost = new BluetoothInputHost(context, listener);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -1995,10 +1983,6 @@ public final class BluetoothAdapter {
|
||||
BluetoothMapClient mapClient = (BluetoothMapClient)proxy;
|
||||
mapClient.close();
|
||||
break;
|
||||
case BluetoothProfile.INPUT_HOST:
|
||||
BluetoothInputHost iHost = (BluetoothInputHost) proxy;
|
||||
iHost.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2070,7 +2054,7 @@ public final class BluetoothAdapter {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
return mManagerService.enableNoAutoConnect();
|
||||
return mManagerService.enableNoAutoConnect(ActivityThread.currentPackageName());
|
||||
} catch (RemoteException e) {Log.e(TAG, "", e);}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -34,9 +34,9 @@ interface IBluetoothManager
|
||||
void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
|
||||
void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
|
||||
boolean isEnabled();
|
||||
boolean enable();
|
||||
boolean enableNoAutoConnect();
|
||||
boolean disable(boolean persist);
|
||||
boolean enable(String packageName);
|
||||
boolean enableNoAutoConnect(String packageName);
|
||||
boolean disable(String packageName, boolean persist);
|
||||
int getState();
|
||||
IBluetoothGatt getBluetoothGatt();
|
||||
|
||||
@@ -47,6 +47,6 @@ interface IBluetoothManager
|
||||
String getName();
|
||||
|
||||
boolean isBleScanAlwaysAvailable();
|
||||
int updateBleAppCount(IBinder b, boolean enable);
|
||||
int updateBleAppCount(IBinder b, boolean enable, String packageName);
|
||||
boolean isBleAppPresent();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -55,14 +57,16 @@ import android.os.UserManagerInternal.UserRestrictionsListener;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.SettingNotFoundException;
|
||||
import android.util.Slog;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
private static final String TAG = "BluetoothManagerService";
|
||||
private static final boolean DBG = true;
|
||||
@@ -135,16 +139,46 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
new ReentrantReadWriteLock();
|
||||
private boolean mBinding;
|
||||
private boolean mUnbinding;
|
||||
|
||||
// used inside handler thread
|
||||
private boolean mQuietEnable = false;
|
||||
// configuarion from external IBinder call which is used to
|
||||
private boolean mEnable;
|
||||
|
||||
/**
|
||||
* Used for tracking apps that enabled / disabled Bluetooth.
|
||||
*/
|
||||
private class ActiveLog {
|
||||
private String mPackageName;
|
||||
private boolean mEnable;
|
||||
private long mTimestamp;
|
||||
|
||||
public ActiveLog(String packageName, boolean enable, long timestamp) {
|
||||
mPackageName = packageName;
|
||||
mEnable = enable;
|
||||
mTimestamp = timestamp;
|
||||
}
|
||||
|
||||
public long getTime() {
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return android.text.format.DateFormat.format("MM-dd hh:mm:ss ", mTimestamp) +
|
||||
(mEnable ? " Enabled " : " Disabled ") + " by " + mPackageName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private LinkedList<ActiveLog> mActiveLogs;
|
||||
|
||||
// configuration from external IBinder call which is used to
|
||||
// synchronize with broadcast receiver.
|
||||
private boolean mQuietEnableExternal;
|
||||
// configuarion from external IBinder call which is used to
|
||||
// synchronize with broadcast receiver.
|
||||
private boolean mEnableExternal;
|
||||
// used inside handler thread
|
||||
private boolean mEnable;
|
||||
|
||||
// Map of apps registered to keep BLE scanning on.
|
||||
private Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>();
|
||||
|
||||
private int mState;
|
||||
private final BluetoothHandler mHandler;
|
||||
private int mErrorRecoveryRetryCounter;
|
||||
@@ -155,6 +189,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,
|
||||
@@ -168,7 +204,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
|
||||
private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
|
||||
@Override
|
||||
public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
|
||||
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
|
||||
@@ -184,7 +220,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.
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -242,12 +283,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
} else if (st == BluetoothAdapter.STATE_ON){
|
||||
// disable without persisting the setting
|
||||
Slog.d(TAG, "Calling disable");
|
||||
sendDisableMsg();
|
||||
sendDisableMsg("airplane mode");
|
||||
}
|
||||
} else if (mEnableExternal) {
|
||||
// enable without persisting the setting
|
||||
Slog.d(TAG, "Calling enable");
|
||||
sendEnableMsg(mQuietEnableExternal);
|
||||
sendEnableMsg(mQuietEnableExternal, "airplane mode");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,6 +299,12 @@ 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);
|
||||
|
||||
mActiveLogs = new LinkedList<ActiveLog>();
|
||||
mBluetooth = null;
|
||||
mBluetoothBinder = null;
|
||||
mBluetoothGatt = null;
|
||||
@@ -284,15 +331,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
mEnableExternal = true;
|
||||
}
|
||||
|
||||
int sysUiUid = -1;
|
||||
int systemUiUid = -1;
|
||||
try {
|
||||
sysUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui",
|
||||
systemUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui",
|
||||
PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// Some platforms, such as wearables do not have a system ui.
|
||||
Slog.w(TAG, "Unable to resolve SystemUI's UID.", e);
|
||||
}
|
||||
mSystemUiUid = sysUiUid;
|
||||
mSystemUiUid = systemUiUid;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -470,8 +517,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
}
|
||||
|
||||
class ClientDeathRecipient implements IBinder.DeathRecipient {
|
||||
private String mPackageName;
|
||||
|
||||
public ClientDeathRecipient(String packageName) {
|
||||
mPackageName = packageName;
|
||||
}
|
||||
|
||||
public void binderDied() {
|
||||
if (DBG) Slog.d(TAG, "Binder is dead - unregister Ble App");
|
||||
if (DBG) Slog.d(TAG, "Binder is dead - unregister " + mPackageName);
|
||||
if (isBleAppPresent()) {
|
||||
// Nothing to do, another app is here.
|
||||
return;
|
||||
@@ -490,10 +543,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
mBluetoothLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Internal death rec list */
|
||||
Map<IBinder, ClientDeathRecipient> mBleApps = new ConcurrentHashMap<IBinder, ClientDeathRecipient>();
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBleScanAlwaysAvailable() {
|
||||
@@ -551,28 +605,22 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public int updateBleAppCount(IBinder token, boolean enable) {
|
||||
if (enable) {
|
||||
ClientDeathRecipient r = mBleApps.get(token);
|
||||
if (r == null) {
|
||||
ClientDeathRecipient deathRec = new ClientDeathRecipient();
|
||||
try {
|
||||
token.linkToDeath(deathRec, 0);
|
||||
} catch (RemoteException ex) {
|
||||
throw new IllegalArgumentException("Wake lock is already dead.");
|
||||
}
|
||||
mBleApps.put(token, deathRec);
|
||||
if (DBG) Slog.d(TAG, "Registered for death Notification");
|
||||
}
|
||||
|
||||
} else {
|
||||
ClientDeathRecipient r = mBleApps.get(token);
|
||||
if (r != null) {
|
||||
// Unregister death recipient as the app goes away.
|
||||
token.unlinkToDeath(r, 0);
|
||||
mBleApps.remove(token);
|
||||
if (DBG) Slog.d(TAG, "Unregistered for death Notification");
|
||||
public int updateBleAppCount(IBinder token, boolean enable, String packageName) {
|
||||
ClientDeathRecipient r = mBleApps.get(token);
|
||||
if (r == null && enable) {
|
||||
ClientDeathRecipient deathRec = new ClientDeathRecipient(packageName);
|
||||
try {
|
||||
token.linkToDeath(deathRec, 0);
|
||||
} catch (RemoteException ex) {
|
||||
throw new IllegalArgumentException("BLE app (" + packageName + ") already dead!");
|
||||
}
|
||||
mBleApps.put(token, deathRec);
|
||||
if (DBG) Slog.d(TAG, "Registered for death of " + packageName);
|
||||
} else if (!enable && r != null) {
|
||||
// Unregister death recipient as the app goes away.
|
||||
token.unlinkToDeath(r, 0);
|
||||
mBleApps.remove(token);
|
||||
if (DBG) Slog.d(TAG, "Unregistered for death of " + packageName);
|
||||
}
|
||||
int appCount = mBleApps.size();
|
||||
if (DBG) Slog.d(TAG, appCount + " registered Ble Apps");
|
||||
@@ -587,7 +635,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
mBleApps.clear();
|
||||
}
|
||||
|
||||
/** @hide*/
|
||||
/** @hide */
|
||||
public boolean isBleAppPresent() {
|
||||
if (DBG) Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size());
|
||||
return mBleApps.size() > 0;
|
||||
@@ -653,7 +701,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean enableNoAutoConnect()
|
||||
public boolean enableNoAutoConnect(String packageName)
|
||||
{
|
||||
if (isBluetoothDisallowed()) {
|
||||
if (DBG) {
|
||||
@@ -678,12 +726,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
synchronized(mReceiver) {
|
||||
mQuietEnableExternal = true;
|
||||
mEnableExternal = true;
|
||||
sendEnableMsg(true);
|
||||
sendEnableMsg(true, packageName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean enable() {
|
||||
public boolean enable(String packageName) throws RemoteException {
|
||||
if (isBluetoothDisallowed()) {
|
||||
if (DBG) {
|
||||
Slog.d(TAG,"enable(): not enabling - bluetooth disallowed");
|
||||
@@ -691,16 +739,27 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
|
||||
(!checkIfCallerIsForegroundUser())) {
|
||||
Slog.w(TAG,"enable(): not allowed for non-active and non system user");
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
|
||||
"Need BLUETOOTH ADMIN permission");
|
||||
if (DBG) {
|
||||
Slog.d(TAG,"enable(): mBluetooth =" + mBluetooth +
|
||||
Slog.d(TAG,"enable(" + packageName + "): mBluetooth =" + mBluetooth +
|
||||
" mBinding = " + mBinding + " mState = " +
|
||||
BluetoothAdapter.nameForState(mState));
|
||||
}
|
||||
@@ -709,20 +768,30 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
mQuietEnableExternal = false;
|
||||
mEnableExternal = true;
|
||||
// waive WRITE_SECURE_SETTINGS permission check
|
||||
sendEnableMsg(false);
|
||||
sendEnableMsg(false, packageName);
|
||||
}
|
||||
if (DBG) Slog.d(TAG, "enable returning");
|
||||
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())) {
|
||||
Slog.w(TAG,"disable(): not allowed for non-active and non system user");
|
||||
return false;
|
||||
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) {
|
||||
@@ -735,11 +804,36 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
persistBluetoothSetting(BLUETOOTH_OFF);
|
||||
}
|
||||
mEnableExternal = false;
|
||||
sendDisableMsg();
|
||||
sendDisableMsg(packageName);
|
||||
}
|
||||
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 +
|
||||
@@ -855,7 +949,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
}
|
||||
if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
|
||||
if (DBG) Slog.d(TAG, "Auto-enabling Bluetooth.");
|
||||
sendEnableMsg(mQuietEnableExternal);
|
||||
sendEnableMsg(mQuietEnableExternal, "system boot");
|
||||
} else if (!isNameAndAddressSet()) {
|
||||
if (DBG) Slog.d(TAG, "Getting adapter name and address");
|
||||
Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
|
||||
@@ -1823,13 +1917,24 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void sendDisableMsg() {
|
||||
private void sendDisableMsg(String packageName) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
|
||||
addActiveLog(packageName, false);
|
||||
}
|
||||
|
||||
private void sendEnableMsg(boolean quietMode) {
|
||||
private void sendEnableMsg(boolean quietMode, String packageName) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
|
||||
quietMode ? 1 : 0, 0));
|
||||
addActiveLog(packageName, true);
|
||||
}
|
||||
|
||||
private void addActiveLog(String packageName, boolean enable) {
|
||||
synchronized (mActiveLogs) {
|
||||
if (mActiveLogs.size() > 10) {
|
||||
mActiveLogs.remove();
|
||||
}
|
||||
mActiveLogs.add(new ActiveLog(packageName, enable, System.currentTimeMillis()));
|
||||
}
|
||||
}
|
||||
|
||||
private void recoverBluetoothServiceFromError(boolean clearBle) {
|
||||
@@ -1900,19 +2005,50 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
||||
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
|
||||
String errorMsg = null;
|
||||
|
||||
boolean protoOut = (args.length > 0) && args[0].startsWith("--proto");
|
||||
|
||||
if (!protoOut) {
|
||||
writer.println("Bluetooth Status");
|
||||
writer.println(" enabled: " + isEnabled());
|
||||
writer.println(" state: " + BluetoothAdapter.nameForState(mState));
|
||||
writer.println(" address: " + mAddress);
|
||||
writer.println(" name: " + mName);
|
||||
if (mEnable) {
|
||||
long onDuration = System.currentTimeMillis() - mActiveLogs.getLast().getTime();
|
||||
String onDurationString = String.format("%02d:%02d:%02d.%03d",
|
||||
(int)(onDuration / (1000 * 60 * 60)),
|
||||
(int)((onDuration / (1000 * 60)) % 60),
|
||||
(int)((onDuration / 1000) % 60),
|
||||
(int)(onDuration % 1000));
|
||||
writer.println(" time since enabled: " + onDurationString + "\n");
|
||||
}
|
||||
|
||||
writer.println("Enable log:");
|
||||
for (ActiveLog log : mActiveLogs) {
|
||||
writer.println(log);
|
||||
}
|
||||
|
||||
writer.println("\n" + mBleApps.size() + " BLE Apps registered:");
|
||||
for (ClientDeathRecipient app : mBleApps.values()) {
|
||||
writer.println(app.getPackageName());
|
||||
}
|
||||
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
if (mBluetoothBinder == null) {
|
||||
errorMsg = "Bluetooth Service not connected";
|
||||
} else {
|
||||
try {
|
||||
mBluetoothBinder.dump(fd, args);
|
||||
} catch (RemoteException re) {
|
||||
errorMsg = "RemoteException while calling Bluetooth Service";
|
||||
errorMsg = "RemoteException while dumping Bluetooth Service";
|
||||
}
|
||||
}
|
||||
if (errorMsg != null) {
|
||||
// Silently return if we are extracting metrics in Protobuf format
|
||||
if ((args.length > 0) && args[0].startsWith("--proto"))
|
||||
return;
|
||||
if (protoOut) return;
|
||||
writer.println(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,7 +547,7 @@ public final class ShutdownThread extends Thread {
|
||||
bluetooth.getState() == BluetoothAdapter.STATE_OFF;
|
||||
if (!bluetoothOff) {
|
||||
Log.w(TAG, "Disabling Bluetooth...");
|
||||
bluetooth.disable(false); // disable but don't persist new state
|
||||
bluetooth.disable(mContext.getPackageName(), false); // disable but don't persist new state
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
|
||||
|
||||
Reference in New Issue
Block a user