Merge "use mskp extension to differentiate multi frame files."
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index c30a6f4..eb53b7c 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -121,8 +121,6 @@
Landroid/bluetooth/IBluetoothPbap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPbap;
Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;-><init>()V
Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V
-Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelected(Ljava/lang/String;ILjava/lang/String;)V
-Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelectionCancel()V
Landroid/content/IClipboard$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -194,7 +192,6 @@
Landroid/content/UndoManager;-><init>()V
Landroid/database/IContentObserver$Stub;-><init>()V
Landroid/database/IContentObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/database/IContentObserver;
-Landroid/database/IContentObserver;->onChange(ZLandroid/net/Uri;I)V
Landroid/database/sqlite/SQLiteConnectionPool;->$assertionsDisabled:Z
Landroid/database/sqlite/SQLiteDatabase;->$assertionsDisabled:Z
Landroid/hardware/display/IDisplayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/display/IDisplayManager;
@@ -723,9 +720,6 @@
Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z
Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
Lcom/android/internal/location/ILocationProvider$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProvider;
-Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)V
-Lcom/android/internal/location/ILocationProvider;->setLocationProviderManager(Lcom/android/internal/location/ILocationProviderManager;)V
-Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V
Lcom/android/internal/location/ILocationProviderManager$Stub;-><init>()V
Lcom/android/internal/location/ILocationProviderManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProviderManager;
Lcom/android/internal/logging/MetricsLogger;-><init>()V
@@ -736,7 +730,6 @@
Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService;
Lcom/android/internal/policy/IKeyguardService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardService;
Lcom/android/internal/policy/IKeyguardStateCallback$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardStateCallback;
-Lcom/android/internal/preference/YesNoPreference;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
Lcom/android/internal/R$anim;->fade_in:I
Lcom/android/internal/R$array;->config_autoBrightnessLcdBacklightValues:I
Lcom/android/internal/R$array;->config_autoBrightnessLevels:I
diff --git a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
index 5f73e55..c9dc019 100644
--- a/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
+++ b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
@@ -18,6 +18,8 @@
/** @hide */
interface ICompanionDeviceDiscoveryServiceCallback {
+ @UnsupportedAppUsage
oneway void onDeviceSelected(String packageName, int userId, String deviceAddress);
+ @UnsupportedAppUsage
oneway void onDeviceSelectionCancel();
}
diff --git a/core/java/android/database/IContentObserver.aidl b/core/java/android/database/IContentObserver.aidl
index 22dc9fe..6235566 100644
--- a/core/java/android/database/IContentObserver.aidl
+++ b/core/java/android/database/IContentObserver.aidl
@@ -29,5 +29,6 @@
* observed. selfUpdate is true if the update was caused by a call to
* commit on the cursor that is being observed.
*/
+ @UnsupportedAppUsage
oneway void onChange(boolean selfUpdate, in Uri uri, int userId);
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index cc8c182..68857da9 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -2337,6 +2337,12 @@
final CaptureCallbackHolder holder =
CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
+ if (holder == null) {
+ Log.e(TAG, String.format("Receive capture error on unknown request ID %d",
+ requestId));
+ return;
+ }
+
final CaptureRequest request = holder.getRequest(subsequenceId);
Runnable failureDispatch = null;
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index b377e8d..6165146 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -123,6 +123,7 @@
IBinder binder = callback.asBinder();
try {
Callback cb = new Callback(callback, cookie);
+ unregister(callback);
binder.linkToDeath(cb, 0);
mCallbacks.put(binder, cb);
return true;
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index a46580d..18d4d69 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -464,7 +464,9 @@
* Note that the feature will continue to be supported on older versions of
* Android as before.
*
- * This function does not have any effect.
+ * @deprecated In Android O and afterwards, this function does not have
+ * any effect, the form data will be saved to platform's autofill service
+ * if applicable.
*/
@Deprecated
public abstract void setSaveFormData(boolean save);
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 5091eea..ad35633 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -42,6 +42,8 @@
import android.view.animation.LinearInterpolator;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
+
import java.lang.ref.WeakReference;
@RemoteView
@@ -1241,14 +1243,40 @@
info.setScrollable(getChildCount() > 1);
if (isEnabled()) {
if (getDisplayedChild() < getChildCount() - 1) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
+ if (mStackMode == ITEMS_SLIDE_UP) {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_DOWN);
+ } else {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_UP);
+ }
}
if (getDisplayedChild() > 0) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
+ if (mStackMode == ITEMS_SLIDE_UP) {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_UP);
+ } else {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_DOWN);
+ }
}
}
}
+ private boolean goForward() {
+ if (getDisplayedChild() < getChildCount() - 1) {
+ showNext();
+ return true;
+ }
+ return false;
+ }
+
+ private boolean goBackward() {
+ if (getDisplayedChild() > 0) {
+ showPrevious();
+ return true;
+ }
+ return false;
+ }
+
/** @hide */
@Override
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
@@ -1260,17 +1288,25 @@
}
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
- if (getDisplayedChild() < getChildCount() - 1) {
- showNext();
- return true;
- }
- } return false;
+ return goForward();
+ }
case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
- if (getDisplayedChild() > 0) {
- showPrevious();
- return true;
+ return goBackward();
+ }
+ case R.id.accessibilityActionPageUp: {
+ if (mStackMode == ITEMS_SLIDE_UP) {
+ return goBackward();
+ } else {
+ return goForward();
}
- } return false;
+ }
+ case R.id.accessibilityActionPageDown: {
+ if (mStackMode == ITEMS_SLIDE_UP) {
+ return goForward();
+ } else {
+ return goBackward();
+ }
+ }
}
return false;
}
diff --git a/core/java/com/android/internal/preference/YesNoPreference.java b/core/java/com/android/internal/preference/YesNoPreference.java
index 7abf416..46d14a1 100644
--- a/core/java/com/android/internal/preference/YesNoPreference.java
+++ b/core/java/com/android/internal/preference/YesNoPreference.java
@@ -16,6 +16,7 @@
package com.android.internal.preference;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Parcel;
@@ -40,6 +41,7 @@
this(context, attrs, defStyleAttr, 0);
}
+ @UnsupportedAppUsage
public YesNoPreference(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.yesNoPreferenceStyle);
}
diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
index 3361fa2..1d294d5 100644
--- a/graphics/java/android/graphics/RectF.java
+++ b/graphics/java/android/graphics/RectF.java
@@ -27,7 +27,7 @@
/**
* RectF holds four float coordinates for a rectangle. The rectangle is
- * represented by the coordinates of its 4 edges (left, top, right bottom).
+ * represented by the coordinates of its 4 edges (left, top, right, bottom).
* These fields can be accessed directly. Use width() and height() to retrieve
* the rectangle's width and height. Note: most methods do not check to see that
* the coordinates are sorted correctly (i.e. left <= right and top <= bottom).
diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl
index a571630..8ae972b 100644
--- a/location/java/com/android/internal/location/ILocationProvider.aidl
+++ b/location/java/com/android/internal/location/ILocationProvider.aidl
@@ -29,10 +29,13 @@
*/
interface ILocationProvider {
+ @UnsupportedAppUsage
oneway void setLocationProviderManager(in ILocationProviderManager manager);
+ @UnsupportedAppUsage
oneway void setRequest(in ProviderRequest request, in WorkSource ws);
+ @UnsupportedAppUsage
oneway void sendExtraCommand(String command, in Bundle extras);
// --- deprecated and will be removed the future ---
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index c0a1b12..1d4d0bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -103,10 +103,11 @@
final boolean userSwitcherEnabled = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.USER_SWITCHER_ENABLED, 0) != 0;
- if (!UserManager.supportsMultipleUsers()
- || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)
+ // TODO(b/138661450) Move IPC calls to background
+ if (!userSwitcherEnabled
+ || !UserManager.supportsMultipleUsers()
|| UserManager.isDeviceInDemoMode(mContext)
- || !userSwitcherEnabled) {
+ || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)) {
return false;
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index cb6cf74..6010b1dc 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -15,9 +15,6 @@
*/
package com.android.server.audio;
-import static com.android.server.audio.AudioService.CONNECTION_STATE_CONNECTED;
-import static com.android.server.audio.AudioService.CONNECTION_STATE_DISCONNECTED;
-
import android.annotation.NonNull;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
@@ -95,13 +92,28 @@
/*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) {
mContext = context;
mAudioService = service;
- setupMessaging(context);
mBtHelper = new BtHelper(this);
mDeviceInventory = new AudioDeviceInventory(this);
+ init();
+ }
+
+ /** for test purposes only, inject AudioDeviceInventory */
+ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service,
+ @NonNull AudioDeviceInventory mockDeviceInventory) {
+ mContext = context;
+ mAudioService = service;
+ mBtHelper = new BtHelper(this);
+ mDeviceInventory = mockDeviceInventory;
+
+ init();
+ }
+
+ private void init() {
+ setupMessaging(mContext);
+
mForcedUseForComm = AudioSystem.FORCE_NONE;
mForcedUseForCommExt = mForcedUseForComm;
-
}
/*package*/ Context getContext() {
@@ -232,17 +244,42 @@
mSupprNoisy = suppressNoisyIntent;
mVolume = vol;
}
+
+ // redefine equality op so we can match messages intended for this device
+ @Override
+ public boolean equals(Object o) {
+ return mDevice.equals(o);
+ }
}
+
/*package*/ void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
@NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
int profile, boolean suppressNoisyIntent, int a2dpVolume) {
final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
suppressNoisyIntent, a2dpVolume);
- // TODO add a check to try to remove unprocessed messages for the same device (the old
- // check didn't work), and make sure it doesn't conflict with config change message
- sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
+ // when receiving a request to change the connection state of a device, this last request
+ // is the source of truth, so cancel all previous requests
+ removeAllA2dpConnectionEvents(device);
+
+ sendLMsgNoDelay(
+ state == BluetoothProfile.STATE_CONNECTED
+ ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION
+ : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
+ SENDMSG_QUEUE, info);
+ }
+
+ /** remove all previously scheduled connection and disconnection events for the given device */
+ private void removeAllA2dpConnectionEvents(@NonNull BluetoothDevice device) {
+ mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION,
+ device);
+ mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION,
+ device);
+ mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED,
+ device);
+ mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
+ device);
}
private static final class HearingAidDeviceConnectionInfo {
@@ -430,13 +467,16 @@
sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE);
}
- /*package*/ void postA2dpSinkConnection(int state,
+ /*package*/ void postA2dpSinkConnection(@AudioService.BtProfileConnectionState int state,
@NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
- sendILMsg(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE, SENDMSG_QUEUE,
+ sendILMsg(state == BluetoothA2dp.STATE_CONNECTED
+ ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED
+ : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
+ SENDMSG_QUEUE,
state, btDeviceInfo, delay);
}
- /*package*/ void postA2dpSourceConnection(int state,
+ /*package*/ void postA2dpSourceConnection(@AudioService.BtProfileConnectionState int state,
@NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) {
sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE,
state, btDeviceInfo, delay);
@@ -522,25 +562,6 @@
}
}
- @GuardedBy("mDeviceStateLock")
- /*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state,
- @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
- final int intState = (state == BluetoothA2dp.STATE_CONNECTED)
- ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED;
- final int delay = mDeviceInventory.checkSendBecomingNoisyIntent(
- AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
- AudioSystem.DEVICE_NONE);
- final String addr = btDeviceInfo == null ? "null" : btDeviceInfo.getBtDevice().getAddress();
-
- if (AudioService.DEBUG_DEVICES) {
- Log.d(TAG, "handleSetA2dpSinkConnectionState btDevice= " + btDeviceInfo
- + " state= " + state
- + " is dock: " + btDeviceInfo.getBtDevice().isBluetoothDock());
- }
- sendILMsg(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE, SENDMSG_QUEUE,
- state, btDeviceInfo, delay);
- }
-
/*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
@NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
@@ -575,8 +596,10 @@
// must be called synchronized on mConnectedDevices
/*package*/ boolean hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice) {
- return mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE,
- new BtHelper.BluetoothA2dpDeviceInfo(btDevice));
+ return (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED,
+ new BtHelper.BluetoothA2dpDeviceInfo(btDevice))
+ || mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED,
+ new BtHelper.BluetoothA2dpDeviceInfo(btDevice)));
}
/*package*/ void setA2dpDockTimeout(String address, int a2dpCodec, int delayMs) {
@@ -711,7 +734,8 @@
mDeviceInventory.onReportNewRoutes();
}
break;
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE:
+ case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
+ case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
synchronized (mDeviceStateLock) {
mDeviceInventory.onSetA2dpSinkConnectionState(
(BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1);
@@ -836,7 +860,8 @@
}
}
break;
- case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: {
+ case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
+ case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: {
final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj;
AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
"setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent "
@@ -887,7 +912,7 @@
private static final int MSG_I_BROADCAST_BT_CONNECTION_STATE = 3;
private static final int MSG_IIL_SET_FORCE_USE = 4;
private static final int MSG_IIL_SET_FORCE_BT_A2DP_USE = 5;
- private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE = 6;
+ private static final int MSG_TOGGLE_HDMI = 6;
private static final int MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE = 7;
private static final int MSG_IL_SET_HEARING_AID_CONNECTION_STATE = 8;
private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
@@ -898,7 +923,6 @@
private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
private static final int MSG_I_DISCONNECT_BT_SCO = 16;
- private static final int MSG_TOGGLE_HDMI = 17;
private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18;
private static final int MSG_DISCONNECT_A2DP = 19;
private static final int MSG_DISCONNECT_A2DP_SINK = 20;
@@ -908,25 +932,30 @@
private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24;
private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25;
private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26;
+ private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED = 27;
+ private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED = 28;
// process external command to (dis)connect an A2DP device
- private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT = 27;
+ private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION = 29;
+ private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION = 30;
// process external command to (dis)connect a hearing aid device
- private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 28;
+ private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31;
// a ScoClient died in BtHelper
- private static final int MSG_L_SCOCLIENT_DIED = 29;
+ private static final int MSG_L_SCOCLIENT_DIED = 32;
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE:
+ case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
+ case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
case MSG_IL_BTA2DP_DOCK_TIMEOUT:
case MSG_L_A2DP_DEVICE_CONFIG_CHANGE:
case MSG_TOGGLE_HDMI:
case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
- case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT:
+ case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION:
+ case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION:
case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
return true;
default:
@@ -1007,7 +1036,8 @@
switch (msg) {
case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE:
- case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE:
+ case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED:
+ case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED:
case MSG_IL_SET_HEARING_AID_CONNECTION_STATE:
case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE:
case MSG_IL_BTA2DP_DOCK_TIMEOUT:
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index a9a8ef2..90973a8 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -41,14 +41,16 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
/**
* Class to manage the inventory of all connected devices.
* This class is thread-safe.
+ * (non final for mocking/spying)
*/
-public final class AudioDeviceInventory {
+public class AudioDeviceInventory {
private static final String TAG = "AS.AudioDeviceInventory";
@@ -56,11 +58,7 @@
// Key for map created from DeviceInfo.makeDeviceListKey()
private final ArrayMap<String, DeviceInfo> mConnectedDevices = new ArrayMap<>();
- private final @NonNull AudioDeviceBroker mDeviceBroker;
-
- AudioDeviceInventory(@NonNull AudioDeviceBroker broker) {
- mDeviceBroker = broker;
- }
+ private @NonNull AudioDeviceBroker mDeviceBroker;
// cache of the address of the last dock the device was connected to
private String mDockAddress;
@@ -70,6 +68,20 @@
final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers =
new RemoteCallbackList<IAudioRoutesObserver>();
+ /*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) {
+ mDeviceBroker = broker;
+ }
+
+ //-----------------------------------------------------------
+ /** for mocking only */
+ /*package*/ AudioDeviceInventory() {
+ mDeviceBroker = null;
+ }
+
+ /*package*/ void setDeviceBroker(@NonNull AudioDeviceBroker broker) {
+ mDeviceBroker = broker;
+ }
+
//------------------------------------------------------------
/**
* Class to store info about connected devices.
@@ -146,8 +158,10 @@
}
}
+ // only public for mocking/spying
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- /*package*/ void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo,
+ @VisibleForTesting
+ public void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo,
@AudioService.BtProfileConnectionState int state) {
final BluetoothDevice btDevice = btInfo.getBtDevice();
int a2dpVolume = btInfo.getVolume();
@@ -159,30 +173,40 @@
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
address = "";
}
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "A2DP sink connected: device addr=" + address + " state=" + state
- + " vol=" + a2dpVolume));
final int a2dpCodec = btInfo.getCodec();
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+ "A2DP sink connected: device addr=" + address + " state=" + state
+ + " codec=" + a2dpCodec
+ + " vol=" + a2dpVolume));
+
synchronized (mConnectedDevices) {
final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
btDevice.getAddress());
final DeviceInfo di = mConnectedDevices.get(key);
boolean isConnected = di != null;
- if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
- if (btDevice.isBluetoothDock()) {
- if (state == BluetoothProfile.STATE_DISCONNECTED) {
- // introduction of a delay for transient disconnections of docks when
- // power is rapidly turned off/on, this message will be canceled if
- // we reconnect the dock under a preset delay
- makeA2dpDeviceUnavailableLater(address,
- AudioDeviceBroker.BTA2DP_DOCK_TIMEOUT_MS);
- // the next time isConnected is evaluated, it will be false for the dock
+ if (isConnected) {
+ if (state == BluetoothProfile.STATE_CONNECTED) {
+ // device is already connected, but we are receiving a connection again,
+ // it could be for a codec change
+ if (a2dpCodec != di.mDeviceCodecFormat) {
+ mDeviceBroker.postBluetoothA2dpDeviceConfigChange(btDevice);
}
} else {
- makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
+ if (btDevice.isBluetoothDock()) {
+ if (state == BluetoothProfile.STATE_DISCONNECTED) {
+ // introduction of a delay for transient disconnections of docks when
+ // power is rapidly turned off/on, this message will be canceled if
+ // we reconnect the dock under a preset delay
+ makeA2dpDeviceUnavailableLater(address,
+ AudioDeviceBroker.BTA2DP_DOCK_TIMEOUT_MS);
+ // the next time isConnected is evaluated, it will be false for the dock
+ }
+ } else {
+ makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat);
+ }
}
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
if (btDevice.isBluetoothDock()) {
@@ -282,11 +306,9 @@
+ " event=" + BtHelper.a2dpDeviceEventToString(event)));
synchronized (mConnectedDevices) {
- //TODO original CL is not consistent between BluetoothDevice and BluetoothA2dpDeviceInfo
- // for this type of message
if (mDeviceBroker.hasScheduledA2dpSinkConnectionState(btDevice)) {
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
- "A2dp config change ignored"));
+ "A2dp config change ignored (scheduled connection change)"));
return;
}
final String key = DeviceInfo.makeDeviceListKey(
@@ -534,8 +556,10 @@
return mCurAudioRoutes;
}
+ // only public for mocking/spying
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
- /*package*/ void setBluetoothA2dpDeviceConnectionState(
+ @VisibleForTesting
+ public void setBluetoothA2dpDeviceConnectionState(
@NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state,
int profile, boolean suppressNoisyIntent, int musicDevice, int a2dpVolume) {
int delay;
@@ -544,9 +568,12 @@
}
synchronized (mConnectedDevices) {
if (profile == BluetoothProfile.A2DP && !suppressNoisyIntent) {
- int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
+ @AudioService.ConnectionState int asState =
+ (state == BluetoothA2dp.STATE_CONNECTED)
+ ? AudioService.CONNECTION_STATE_CONNECTED
+ : AudioService.CONNECTION_STATE_DISCONNECTED;
delay = checkSendBecomingNoisyIntentInt(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- intState, musicDevice);
+ asState, musicDevice);
} else {
delay = 0;
}
@@ -785,7 +812,7 @@
return 0;
}
mDeviceBroker.postBroadcastBecomingNoisy();
- delay = 1000;
+ delay = AudioService.BECOMING_NOISY_DELAY_MS;
}
return delay;
@@ -943,4 +970,21 @@
intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
}
}
+
+ //----------------------------------------------------------
+ // For tests only
+
+ /**
+ * Check if device is in the list of connected devices
+ * @param device
+ * @return true if connected
+ */
+ @VisibleForTesting
+ public boolean isA2dpDeviceConnected(@NonNull BluetoothDevice device) {
+ final String key = DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ device.getAddress());
+ synchronized (mConnectedDevices) {
+ return (mConnectedDevices.get(key) != null);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 7458bee..5bc2261 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -128,6 +128,7 @@
import android.widget.Toast;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.EventLogTags;
@@ -190,6 +191,13 @@
private static final int UNMUTE_STREAM_DELAY = 350;
/**
+ * Delay before disconnecting a device that would cause BECOMING_NOISY intent to be sent,
+ * to give a chance to applications to pause.
+ */
+ @VisibleForTesting
+ public static final int BECOMING_NOISY_DELAY_MS = 1000;
+
+ /**
* Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
*/
private static final int FLAG_ADJUST_VOLUME = 1;
@@ -3950,7 +3958,9 @@
|| adjust == AudioManager.ADJUST_TOGGLE_MUTE;
}
- /*package*/ boolean isInCommunication() {
+ /** only public for mocking/spying, do not call outside of AudioService */
+ @VisibleForTesting
+ public boolean isInCommunication() {
boolean IsInCall = false;
TelecomManager telecomManager =
@@ -4119,7 +4129,9 @@
return false;
}
- /*package*/ int getDeviceForStream(int stream) {
+ /** only public for mocking/spying, do not call outside of AudioService */
+ @VisibleForTesting
+ public int getDeviceForStream(int stream) {
int device = getDevicesForStream(stream);
if ((device & (device - 1)) != 0) {
// Multiple device selection is either:
@@ -4164,7 +4176,9 @@
}
}
- /*package*/ void postObserveDevicesForAllStreams() {
+ /** only public for mocking/spying, do not call outside of AudioService */
+ @VisibleForTesting
+ public void postObserveDevicesForAllStreams() {
sendMsg(mAudioHandler,
MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS,
SENDMSG_QUEUE, 0 /*arg1*/, 0 /*arg2*/, null /*obj*/,
@@ -4275,7 +4289,9 @@
AudioSystem.DEVICE_OUT_ALL_USB |
AudioSystem.DEVICE_OUT_HDMI;
- /*package*/ void postAccessoryPlugMediaUnmute(int newDevice) {
+ /** only public for mocking/spying, do not call outside of AudioService */
+ @VisibleForTesting
+ public void postAccessoryPlugMediaUnmute(int newDevice) {
sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
newDevice, 0, null, 0);
}
@@ -4825,7 +4841,9 @@
}
}
- /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device,
+ /** only public for mocking/spying, do not call outside of AudioService */
+ @VisibleForTesting
+ public void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device,
String caller) {
sendMsg(mAudioHandler,
MSG_SET_DEVICE_STREAM_VOLUME,
@@ -5183,7 +5201,9 @@
* @return true if there is currently a registered dynamic mixing policy that affects media
* and is not a render + loopback policy
*/
- /*package*/ boolean hasMediaDynamicPolicy() {
+ // only public for mocking/spying
+ @VisibleForTesting
+ public boolean hasMediaDynamicPolicy() {
synchronized (mAudioPolicies) {
if (mAudioPolicies.isEmpty()) {
return false;
@@ -5516,7 +5536,9 @@
return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr);
}
- /*package*/ boolean hasAudioFocusUsers() {
+ /** only public for mocking/spying, do not call outside of AudioService */
+ @VisibleForTesting
+ public boolean hasAudioFocusUsers() {
return mMediaFocusControl.hasAudioFocusUsers();
}
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 1a63f8f..9f1a6bd 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -139,6 +139,12 @@
public int getCodec() {
return mCodec;
}
+
+ // redefine equality op so we can match messages intended for this device
+ @Override
+ public boolean equals(Object o) {
+ return mBtDevice.equals(o);
+ }
}
// A2DP device events
@@ -441,9 +447,9 @@
return;
}
final BluetoothDevice btDevice = deviceList.get(0);
- final @BluetoothProfile.BtProfileState int state = mA2dp.getConnectionState(btDevice);
- mDeviceBroker.handleSetA2dpSinkConnectionState(
- state, new BluetoothA2dpDeviceInfo(btDevice));
+ // the device is guaranteed CONNECTED
+ mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(btDevice,
+ BluetoothA2dp.STATE_CONNECTED, BluetoothProfile.A2DP_SINK, true, -1);
}
/*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 4957eed..73d160d 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -772,7 +772,6 @@
case WifiManager.WIFI_AP_STATE_FAILED:
default:
disableWifiIpServingLocked(ifname, curState);
- mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
break;
}
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 984f22f..c712431 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -281,20 +281,7 @@
mAbortIdleOptimization.set(false);
long lowStorageThreshold = getLowStorageThreshold(context);
- // Optimize primary apks.
- int result = optimizePackages(pm, pkgs, lowStorageThreshold,
- /*isForPrimaryDex=*/ true);
- if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
- return result;
- }
- if (supportSecondaryDex()) {
- result = reconcileSecondaryDexFiles(pm.getDexManager());
- if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
- return result;
- }
- result = optimizePackages(pm, pkgs, lowStorageThreshold,
- /*isForPrimaryDex=*/ false);
- }
+ int result = idleOptimizePackages(pm, pkgs, lowStorageThreshold);
return result;
}
@@ -342,11 +329,20 @@
return 0;
}
- private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
- long lowStorageThreshold, boolean isForPrimaryDex) {
+ private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+ long lowStorageThreshold) {
ArraySet<String> updatedPackages = new ArraySet<>();
try {
+ final boolean supportSecondaryDex = supportSecondaryDex();
+
+ if (supportSecondaryDex) {
+ int result = reconcileSecondaryDexFiles(pm.getDexManager());
+ if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
+ return result;
+ }
+ }
+
// Only downgrade apps when space is low on device.
// Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
// up disk before user hits the actual lowStorageThreshold.
@@ -359,43 +355,61 @@
pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
- for (String pkg : unusedPackages) {
- int abortCode = abortIdleOptimizations(/*lowStorageThreshold*/ -1);
- if (abortCode != OPTIMIZE_CONTINUE) {
- // Should be aborted by the scheduler.
- return abortCode;
- }
- if (downgradePackage(pm, pkg, isForPrimaryDex)) {
- updatedPackages.add(pkg);
- }
- }
-
if (!unusedPackages.isEmpty()) {
+ for (String pkg : unusedPackages) {
+ int abortCode = abortIdleOptimizations(/*lowStorageThreshold*/ -1);
+ if (abortCode != OPTIMIZE_CONTINUE) {
+ // Should be aborted by the scheduler.
+ return abortCode;
+ }
+ if (downgradePackage(pm, pkg, /*isForPrimaryDex*/ true)) {
+ updatedPackages.add(pkg);
+ }
+ if (supportSecondaryDex) {
+ downgradePackage(pm, pkg, /*isForPrimaryDex*/ false);
+ }
+ }
+
pkgs = new ArraySet<>(pkgs);
pkgs.removeAll(unusedPackages);
}
}
- for (String pkg : pkgs) {
- int abortCode = abortIdleOptimizations(lowStorageThreshold);
- if (abortCode != OPTIMIZE_CONTINUE) {
- // Either aborted by the scheduler or no space left.
- return abortCode;
- }
-
- boolean dexOptPerformed = optimizePackage(pm, pkg, isForPrimaryDex);
- if (dexOptPerformed) {
- updatedPackages.add(pkg);
- }
+ int primaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
+ /*isForPrimaryDex*/ true, updatedPackages);
+ if (primaryResult != OPTIMIZE_PROCESSED) {
+ return primaryResult;
}
- return OPTIMIZE_PROCESSED;
+ if (!supportSecondaryDex) {
+ return OPTIMIZE_PROCESSED;
+ }
+
+ int secondaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
+ /*isForPrimaryDex*/ false, updatedPackages);
+ return secondaryResult;
} finally {
// Always let the pinner service know about changes.
notifyPinService(updatedPackages);
}
}
+ private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+ long lowStorageThreshold, boolean isForPrimaryDex, ArraySet<String> updatedPackages) {
+ for (String pkg : pkgs) {
+ int abortCode = abortIdleOptimizations(lowStorageThreshold);
+ if (abortCode != OPTIMIZE_CONTINUE) {
+ // Either aborted by the scheduler or no space left.
+ return abortCode;
+ }
+
+ boolean dexOptPerformed = optimizePackage(pm, pkg, isForPrimaryDex);
+ if (dexOptPerformed) {
+ updatedPackages.add(pkg);
+ }
+ }
+ return OPTIMIZE_PROCESSED;
+ }
/**
* Try to downgrade the package to a smaller compilation filter.
diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java
index a374e14..231168e 100644
--- a/services/core/java/com/android/server/pm/ProtectedPackages.java
+++ b/services/core/java/com/android/server/pm/ProtectedPackages.java
@@ -92,6 +92,9 @@
if (mDeviceOwnerUserId == userId) {
return mDeviceOwnerPackage;
}
+ if (mProfileOwnerPackages == null) {
+ return null;
+ }
return mProfileOwnerPackages.get(userId);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 421fd28..8fb23a4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2006,6 +2006,7 @@
int attrChanges = 0;
int flagChanges = 0;
+ int privateFlagChanges = 0;
if (attrs != null) {
displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
// if they don't have the permission, mask out the status bar bits
@@ -2034,6 +2035,7 @@
}
flagChanges = win.mAttrs.flags ^ attrs.flags;
+ privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags;
attrChanges = win.mAttrs.copyFrom(attrs);
if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED
| WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
@@ -2050,7 +2052,7 @@
win.getDisplayContent().getDisplayId());
}
- if ((flagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
+ if ((privateFlagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
updateNonSystemOverlayWindowsVisibilityIfNeeded(
win, win.mWinAnimator.getShown());
}
@@ -7543,7 +7545,7 @@
return;
}
final boolean systemAlertWindowsHidden = !mHidingNonSystemOverlayWindows.isEmpty();
- if (surfaceShown) {
+ if (surfaceShown && win.hideNonSystemOverlayWindowsWhenVisible()) {
if (!mHidingNonSystemOverlayWindows.contains(win)) {
mHidingNonSystemOverlayWindows.add(win);
}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 01f2f6b..c1bbb30 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -69,6 +69,7 @@
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.HARDWARE_TEST"/>
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
new file mode 100644
index 0000000..5c2ad94
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2019 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.server.audio;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AudioDeviceBrokerTest {
+
+ private static final String TAG = "AudioDeviceBrokerTest";
+ private static final int MAX_MESSAGE_HANDLING_DELAY_MS = 100;
+
+ private Context mContext;
+ // the actual class under test
+ private AudioDeviceBroker mAudioDeviceBroker;
+
+ @Mock private AudioService mMockAudioService;
+ @Spy private AudioDeviceInventory mSpyDevInventory;
+
+ private BluetoothDevice mFakeBtDevice;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+
+ mMockAudioService = mock(AudioService.class);
+ mSpyDevInventory = spy(new AudioDeviceInventory());
+ mAudioDeviceBroker = new AudioDeviceBroker(mContext, mMockAudioService, mSpyDevInventory);
+ mSpyDevInventory.setDeviceBroker(mAudioDeviceBroker);
+
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ mFakeBtDevice = adapter.getRemoteDevice("00:01:02:03:04:05");
+ Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
+ }
+
+ @After
+ public void tearDown() throws Exception { }
+
+ @Test
+ public void testSetUpAndTearDown() { }
+
+ /**
+ * Verify call to postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent() for connection
+ * calls into AudioDeviceInventory with the right params
+ * @throws Exception
+ */
+ @Test
+ public void testPostA2dpDeviceConnectionChange() throws Exception {
+ Log.i(TAG, "testPostA2dpDeviceConnectionChange");
+ Assert.assertNotNull("invalid null BT device", mFakeBtDevice);
+
+ mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1);
+ Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
+ verify(mSpyDevInventory, times(1)).setBluetoothA2dpDeviceConnectionState(
+ any(BluetoothDevice.class),
+ ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED) /*state*/,
+ ArgumentMatchers.eq(BluetoothProfile.A2DP) /*profile*/,
+ ArgumentMatchers.eq(true) /*suppressNoisyIntent*/, anyInt() /*musicDevice*/,
+ ArgumentMatchers.eq(1) /*a2dpVolume*/
+ );
+ }
+
+ /**
+ * Verify call to postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent() for
+ * connection > pause > disconnection > connection
+ * keeps the device connected
+ * @throws Exception
+ */
+ @Test
+ public void testA2dpDeviceConnectionDisconnectionConnectionChange() throws Exception {
+ Log.i(TAG, "testA2dpDeviceConnectionDisconnectionConnectionChange");
+
+ doTestConnectionDisconnectionReconnection(0);
+ }
+
+ /**
+ * Verify device disconnection and reconnection within the BECOMING_NOISY window
+ * @throws Exception
+ */
+ @Test
+ public void testA2dpDeviceReconnectionWithinBecomingNoisyDelay() throws Exception {
+ Log.i(TAG, "testA2dpDeviceReconnectionWithinBecomingNoisyDelay");
+
+ doTestConnectionDisconnectionReconnection(AudioService.BECOMING_NOISY_DELAY_MS / 2);
+ }
+
+ private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection)
+ throws Exception {
+ when(mMockAudioService.getDeviceForStream(AudioManager.STREAM_MUSIC))
+ .thenReturn(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+ when(mMockAudioService.isInCommunication()).thenReturn(false);
+ when(mMockAudioService.hasMediaDynamicPolicy()).thenReturn(false);
+ when(mMockAudioService.hasAudioFocusUsers()).thenReturn(false);
+
+ // first connection
+ mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 1);
+ Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
+
+ // disconnection
+ mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
+ BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP, false, -1);
+ if (delayAfterDisconnection > 0) {
+ Thread.sleep(delayAfterDisconnection);
+ }
+
+ // reconnection
+ mAudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(mFakeBtDevice,
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP, true, 2);
+ Thread.sleep(AudioService.BECOMING_NOISY_DELAY_MS + MAX_MESSAGE_HANDLING_DELAY_MS);
+
+ // Verify disconnection has been cancelled and we're seeing two connections attempts,
+ // with the device connected at the end of the test
+ verify(mSpyDevInventory, times(2)).onSetA2dpSinkConnectionState(
+ any(BtHelper.BluetoothA2dpDeviceInfo.class),
+ ArgumentMatchers.eq(BluetoothProfile.STATE_CONNECTED));
+ Assert.assertTrue("Mock device not connected",
+ mSpyDevInventory.isA2dpDeviceConnected(mFakeBtDevice));
+ }
+}
diff --git a/startop/view_compiler/dex_layout_compiler.cc b/startop/view_compiler/dex_layout_compiler.cc
index c68793d..8febfb7 100644
--- a/startop/view_compiler/dex_layout_compiler.cc
+++ b/startop/view_compiler/dex_layout_compiler.cc
@@ -23,25 +23,6 @@
using android::base::StringPrintf;
-void LayoutValidationVisitor::VisitStartTag(const std::u16string& name) {
- if (0 == name.compare(u"merge")) {
- message_ = "Merge tags are not supported";
- can_compile_ = false;
- }
- if (0 == name.compare(u"include")) {
- message_ = "Include tags are not supported";
- can_compile_ = false;
- }
- if (0 == name.compare(u"view")) {
- message_ = "View tags are not supported";
- can_compile_ = false;
- }
- if (0 == name.compare(u"fragment")) {
- message_ = "Fragment tags are not supported";
- can_compile_ = false;
- }
-}
-
DexViewBuilder::DexViewBuilder(dex::MethodBuilder* method)
: method_{method},
context_{dex::Value::Parameter(0)},
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index cd79f37..ce21112 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2328,6 +2328,13 @@
public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
/**
+ * Indicates if the TTY HCO and VCO options should be hidden in the accessibility menu
+ * if the device is capable of RTT.
+ * @hide
+ */
+ public static final String KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL = "hide_tty_hco_vco_with_rtt";
+
+ /**
* The flag to disable the popup dialog which warns the user of data charges.
* @hide
*/
@@ -3406,6 +3413,7 @@
sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true);
+ sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false);
sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true);
sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index cdf4c93..aa7e21a 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -340,6 +340,19 @@
*/
public static final int MEDIA_TIMEOUT = 77;
+ /**
+ * Indicates that an emergency call cannot be placed over WFC because the service is not
+ * available in the current location.
+ * @hide
+ */
+ public static final int EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 78;
+
+ /**
+ * Indicates that WiFi calling service is not available in the current location.
+ * @hide
+ */
+ public static final int WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 79;
+
//*********************************************************************************************
// When adding a disconnect type:
// 1) Update toString() with the newly added disconnect type.
@@ -510,6 +523,10 @@
return "OTASP_PROVISIONING_IN_PROCESS";
case MEDIA_TIMEOUT:
return "MEDIA_TIMEOUT";
+ case EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE:
+ return "EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE";
+ case WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION:
+ return "WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION";
default:
return "INVALID: " + cause;
}
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index a478606..20aba4d 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -871,6 +871,19 @@
*/
public static final int CODE_REJECT_ONGOING_CS_CALL = 1621;
+ /**
+ * An attempt was made to place an emergency call over WFC when emergency services is not
+ * currently available in the current location.
+ * @hide
+ */
+ public static final int CODE_EMERGENCY_CALL_OVER_WFC_NOT_AVAILABLE = 1622;
+
+ /**
+ * Indicates that WiFi calling service is not available in the current location.
+ * @hide
+ */
+ public static final int CODE_WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION = 1623;
+
/*
* OEM specific error codes. To be used by OEMs when they don't want to reveal error code which
* would be replaced by ERROR_UNSPECIFIED.