Merge "Limit broadcast by user" into sc-v2-dev
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 64a9c44..9e23b5f 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -438,7 +438,7 @@
void requestInteractiveBugReport();
void requestFullBugReport();
- void requestRemoteBugReport();
+ void requestRemoteBugReport(long nonce);
boolean launchBugReportHandlerApp();
List<String> getBugreportWhitelistedPackages();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a37979a..ff072c2 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -497,6 +497,14 @@
"android.intent.extra.REMOTE_BUGREPORT_HASH";
/**
+ * Extra for shared bugreport's nonce in long integer type.
+ *
+ * @hide
+ */
+ public static final String EXTRA_REMOTE_BUGREPORT_NONCE =
+ "android.intent.extra.REMOTE_BUGREPORT_NONCE";
+
+ /**
* Extra for remote bugreport notification shown type.
*
* @hide
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index e58419f..338ad24 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -513,6 +513,13 @@
public static final String NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT = "window_manager_native_boot";
/**
+ * Definitions for voice interaction related functions.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_VOICE_INTERACTION = "voice_interaction";
+
+ /**
* List of namespaces which can be read without READ_DEVICE_CONFIG permission
*
* @hide
diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java
index 7ed733c..9d648a6 100644
--- a/core/java/android/service/gatekeeper/GateKeeperResponse.java
+++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java
@@ -105,7 +105,7 @@
dest.writeInt(mTimeout);
} else if (mResponseCode == RESPONSE_OK) {
dest.writeInt(mShouldReEnroll ? 1 : 0);
- if (mPayload != null) {
+ if (mPayload != null && mPayload.length > 0) {
dest.writeInt(mPayload.length);
dest.writeByteArray(mPayload);
} else {
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index efffa2b..aba79d5 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -171,8 +171,9 @@
public void setSystemBarsAppearance(int appearance, int mask) {
mViewRoot.mWindowAttributes.privateFlags |= PRIVATE_FLAG_APPEARANCE_CONTROLLED;
final InsetsFlags insetsFlags = mViewRoot.mWindowAttributes.insetsFlags;
- if (insetsFlags.appearance != appearance) {
- insetsFlags.appearance = (insetsFlags.appearance & ~mask) | (appearance & mask);
+ final int newAppearance = (insetsFlags.appearance & ~mask) | (appearance & mask);
+ if (insetsFlags.appearance != newAppearance) {
+ insetsFlags.appearance = newAppearance;
mViewRoot.mWindowAttributesChanged = true;
mViewRoot.scheduleTraversals();
}
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 8c70112..4183c08 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -157,6 +157,7 @@
static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
+ static final String EXTRA_BUGREPORT_NONCE = "android.intent.extra.BUGREPORT_NONCE";
static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
static final String EXTRA_ID = "android.intent.extra.ID";
static final String EXTRA_NAME = "android.intent.extra.NAME";
@@ -415,7 +416,7 @@
final String bugreportFilePath = mInfo.bugreportFile.getAbsolutePath();
if (mInfo.type == BugreportParams.BUGREPORT_MODE_REMOTE) {
sendRemoteBugreportFinishedBroadcast(mContext, bugreportFilePath,
- mInfo.bugreportFile);
+ mInfo.bugreportFile, mInfo.nonce);
} else {
cleanupOldFiles(MIN_KEEP_COUNT, MIN_KEEP_AGE, mBugreportsDir);
final Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
@@ -428,7 +429,7 @@
}
private static void sendRemoteBugreportFinishedBroadcast(Context context,
- String bugreportFileName, File bugreportFile) {
+ String bugreportFileName, File bugreportFile, long nonce) {
cleanupOldFiles(REMOTE_BUGREPORT_FILES_AMOUNT, REMOTE_MIN_KEEP_AGE,
bugreportFile.getParentFile());
final Intent intent = new Intent(DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH);
@@ -439,6 +440,7 @@
}
intent.setDataAndType(bugreportUri, BUGREPORT_MIMETYPE);
intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
+ intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_NONCE, nonce);
intent.putExtra(EXTRA_BUGREPORT, bugreportFileName);
context.sendBroadcastAsUser(intent, UserHandle.SYSTEM,
android.Manifest.permission.DUMP);
@@ -613,11 +615,12 @@
String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
int bugreportType = intent.getIntExtra(EXTRA_BUGREPORT_TYPE,
BugreportParams.BUGREPORT_MODE_INTERACTIVE);
+ long nonce = intent.getLongExtra(EXTRA_BUGREPORT_NONCE, 0);
String baseName = getBugreportBaseName(bugreportType);
String name = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
BugreportInfo info = new BugreportInfo(mContext, baseName, name,
- shareTitle, shareDescription, bugreportType, mBugreportsDir);
+ shareTitle, shareDescription, bugreportType, mBugreportsDir, nonce);
synchronized (mLock) {
if (info.bugreportFile.exists()) {
Log.e(TAG, "Failed to start bugreport generation, the requested bugreport file "
@@ -1915,6 +1918,11 @@
*/
final int type;
+ /**
+ * Nonce of the bugreport
+ */
+ final long nonce;
+
private final Object mLock = new Object();
/**
@@ -1922,12 +1930,13 @@
*/
BugreportInfo(Context context, String baseName, String name,
@Nullable String shareTitle, @Nullable String shareDescription,
- @BugreportParams.BugreportMode int type, File bugreportsDir) {
+ @BugreportParams.BugreportMode int type, File bugreportsDir, long nonce) {
this.context = context;
this.name = this.initialName = name;
this.shareTitle = shareTitle == null ? "" : shareTitle;
this.shareDescription = shareDescription == null ? "" : shareDescription;
this.type = type;
+ this.nonce = nonce;
this.baseName = baseName;
this.bugreportFile = new File(bugreportsDir, getFileName(this, ".zip"));
}
@@ -2167,6 +2176,7 @@
screenshotCounter = in.readInt();
shareDescription = in.readString();
type = in.readInt();
+ nonce = in.readLong();
}
@Override
@@ -2195,6 +2205,7 @@
dest.writeInt(screenshotCounter);
dest.writeString(shareDescription);
dest.writeInt(type);
+ dest.writeLong(nonce);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 8d9fbca..b7916f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -210,7 +210,6 @@
private static final int KEYGUARD_DONE_PENDING_TIMEOUT = 13;
private static final int NOTIFY_STARTED_WAKING_UP = 14;
private static final int NOTIFY_SCREEN_TURNED_ON = 15;
- private static final int NOTIFY_SCREEN_TURNED_OFF = 16;
private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 17;
private static final int SYSTEM_READY = 18;
private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19;
@@ -441,7 +440,6 @@
private boolean mInGestureNavigationMode;
private boolean mWakeAndUnlocking;
- private IKeyguardDrawnCallback mDrawnCallback;
private CharSequence mCustomMessage;
/**
@@ -1264,7 +1262,6 @@
}
public void onScreenTurnedOff() {
- notifyScreenTurnedOff();
mUpdateMonitor.dispatchScreenTurnedOff();
}
@@ -1668,12 +1665,6 @@
mHandler.sendMessage(msg);
}
- private void notifyScreenTurnedOff() {
- if (DEBUG) Log.d(TAG, "notifyScreenTurnedOff");
- Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_TURNED_OFF);
- mHandler.sendMessage(msg);
- }
-
/**
* Send message to keyguard telling it to show itself
* @see #handleShow
@@ -1861,9 +1852,6 @@
handleNotifyScreenTurnedOn();
Trace.endSection();
break;
- case NOTIFY_SCREEN_TURNED_OFF:
- handleNotifyScreenTurnedOff();
- break;
case NOTIFY_STARTED_WAKING_UP:
Trace.beginSection(
"KeyguardViewMediator#handleMessage NOTIFY_STARTED_WAKING_UP");
@@ -2245,16 +2233,6 @@
IRemoteAnimationRunner runner = mKeyguardExitAnimationRunner;
mKeyguardExitAnimationRunner = null;
- if (mWakeAndUnlocking && mDrawnCallback != null) {
-
- // Hack level over 9000: To speed up wake-and-unlock sequence, force it to report
- // the next draw from here so we don't have to wait for window manager to signal
- // this to our ViewRootImpl.
- mKeyguardViewControllerLazy.get().getViewRootImpl().setReportNextDraw();
- notifyDrawn(mDrawnCallback);
- mDrawnCallback = null;
- }
-
LatencyTracker.getInstance(mContext)
.onActionEnd(LatencyTracker.ACTION_LOCKSCREEN_UNLOCK);
@@ -2610,11 +2588,7 @@
mKeyguardViewControllerLazy.get().onScreenTurningOn();
if (callback != null) {
- if (mWakeAndUnlocking) {
- mDrawnCallback = callback;
- } else {
- notifyDrawn(callback);
- }
+ notifyDrawn(callback);
}
}
Trace.endSection();
@@ -2629,13 +2603,6 @@
Trace.endSection();
}
- private void handleNotifyScreenTurnedOff() {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOff");
- mDrawnCallback = null;
- }
- }
-
private void notifyDrawn(final IKeyguardDrawnCallback callback) {
Trace.beginSection("KeyguardViewMediator#notifyDrawn");
if (mPendingDrawnTasks.decrementAndGet() == 0) {
@@ -2804,7 +2771,6 @@
pw.print(" mPendingLock: "); pw.println(mPendingLock);
pw.print(" mPendingDrawnTasks: "); pw.println(mPendingDrawnTasks.get());
pw.print(" mWakeAndUnlocking: "); pw.println(mWakeAndUnlocking);
- pw.print(" mDrawnCallback: "); pw.println(mDrawnCallback);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index f6a1184..70f89e4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -835,7 +835,8 @@
uid,
interactedSubcardRank,
interactedSubcardCardinality,
- receivedLatencyMillis
+ receivedLatencyMillis,
+ null // Media cards cannot have subcards.
)
/* ktlint-disable max-line-length */
if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 98b5dcc..2df56bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -405,7 +405,6 @@
// During wake and unlock, we need to draw black before waking up to avoid abrupt
// brightness changes due to display state transitions.
boolean alwaysOnEnabled = mDozeParameters.getAlwaysOn();
- boolean delayWakeUp = mode == MODE_WAKE_AND_UNLOCK && alwaysOnEnabled && mWakeUpDelay > 0;
Runnable wakeUp = ()-> {
if (!wasDeviceInteractive) {
if (DEBUG_BIO_WAKELOCK) {
@@ -414,15 +413,12 @@
mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
"android.policy:BIOMETRIC");
}
- if (delayWakeUp) {
- mKeyguardViewMediator.onWakeAndUnlocking();
- }
Trace.beginSection("release wake-and-unlock");
releaseBiometricWakeLock();
Trace.endSection();
};
- if (!delayWakeUp && mMode != MODE_NONE) {
+ if (mMode != MODE_NONE) {
wakeUp.run();
}
switch (mMode) {
@@ -472,11 +468,7 @@
mUpdateMonitor.awakenFromDream();
}
mNotificationShadeWindowController.setNotificationShadeFocusable(false);
- if (delayWakeUp) {
- mHandler.postDelayed(wakeUp, mWakeUpDelay);
- } else {
- mKeyguardViewMediator.onWakeAndUnlocking();
- }
+ mKeyguardViewMediator.onWakeAndUnlocking();
Trace.endSection();
break;
case MODE_ONLY_WAKE:
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index ff24c6f..7ff693c 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -193,6 +193,7 @@
// used inside handler thread
private boolean mQuietEnable = false;
private boolean mEnable;
+ private boolean mShutdownInProgress = false;
private static CharSequence timeToLog(long timestamp) {
return android.text.format.DateFormat.format("MM-dd HH:mm:ss", timestamp);
@@ -462,6 +463,23 @@
Slog.i(TAG, "Device disconnected, reactivating pending flag changes");
onInitFlagsChanged();
}
+ } else if (action.equals(Intent.ACTION_SHUTDOWN)) {
+ Slog.i(TAG, "Device is shutting down.");
+ mShutdownInProgress = true;
+ mBluetoothLock.readLock().lock();
+ try {
+ mEnable = false;
+ mEnableExternal = false;
+ if (mBluetooth != null && (mState == BluetoothAdapter.STATE_BLE_ON)) {
+ mBluetooth.onBrEdrDown(mContext.getAttributionSource());
+ } else if (mBluetooth != null && (mState == BluetoothAdapter.STATE_ON)) {
+ mBluetooth.disable(mContext.getAttributionSource());
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to shutdown Bluetooth", e);
+ } finally {
+ mBluetoothLock.readLock().unlock();
+ }
}
}
};
@@ -515,6 +533,7 @@
filter.addAction(Intent.ACTION_SETTING_RESTORED);
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_SHUTDOWN);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(mReceiver, filter);
@@ -1850,6 +1869,11 @@
case MESSAGE_ENABLE:
int quietEnable = msg.arg1;
int isBle = msg.arg2;
+ if (mShutdownInProgress) {
+ Slog.i(TAG, "Skip Bluetooth Enable in device shutdown process");
+ break;
+ }
+
if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED)
|| mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
// We are handling enable or disable right now, wait for it.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ed74481..f5103df 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -544,6 +544,7 @@
static final String EXTRA_TITLE = "android.intent.extra.TITLE";
static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
+ static final String EXTRA_BUGREPORT_NONCE = "android.intent.extra.BUGREPORT_NONCE";
/**
* The maximum number of bytes that {@link #setProcessStateSummary} accepts.
@@ -6591,7 +6592,7 @@
*/
@Override
public void requestBugReport(@BugreportParams.BugreportMode int bugreportType) {
- requestBugReportWithDescription(null, null, bugreportType);
+ requestBugReportWithDescription(null, null, bugreportType, 0L);
}
/**
@@ -6601,6 +6602,15 @@
@Override
public void requestBugReportWithDescription(@Nullable String shareTitle,
@Nullable String shareDescription, int bugreportType) {
+ requestBugReportWithDescription(shareTitle, shareDescription, bugreportType, /*nonce*/ 0L);
+ }
+
+ /**
+ * Takes a bugreport using bug report API ({@code BugreportManager}) which gets
+ * triggered by sending a broadcast to Shell.
+ */
+ public void requestBugReportWithDescription(@Nullable String shareTitle,
+ @Nullable String shareDescription, int bugreportType, long nonce) {
String type = null;
switch (bugreportType) {
case BugreportParams.BUGREPORT_MODE_FULL:
@@ -6651,6 +6661,7 @@
triggerShellBugreport.setAction(INTENT_BUGREPORT_REQUESTED);
triggerShellBugreport.setPackage(SHELL_APP_PACKAGE);
triggerShellBugreport.putExtra(EXTRA_BUGREPORT_TYPE, bugreportType);
+ triggerShellBugreport.putExtra(EXTRA_BUGREPORT_NONCE, nonce);
triggerShellBugreport.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
triggerShellBugreport.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
if (shareTitle != null) {
@@ -6717,8 +6728,8 @@
* Takes a bugreport remotely
*/
@Override
- public void requestRemoteBugReport() {
- requestBugReportWithDescription(null, null, BugreportParams.BUGREPORT_MODE_REMOTE);
+ public void requestRemoteBugReport(long nonce) {
+ requestBugReportWithDescription(null, null, BugreportParams.BUGREPORT_MODE_REMOTE, nonce);
}
/**
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index f053e94..b1e6248 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -252,8 +252,8 @@
return;
}
}
- setCommunicationRouteForClient(
- cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource);
+ postSetCommunicationRouteForClient(new CommunicationClientInfo(
+ cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource));
}
}
}
@@ -283,8 +283,8 @@
return false;
}
}
- setCommunicationRouteForClient(
- cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource);
+ postSetCommunicationRouteForClient(new CommunicationClientInfo(
+ cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource));
}
}
return true;
@@ -348,26 +348,35 @@
}
/**
- * Returns the device currently requested for communication use case.
- * If the current audio mode owner is in the communication route client list,
- * use this preference.
- * Otherwise use first client's preference (first client corresponds to latest request).
- * null is returned if no client is in the list.
- * @return AudioDeviceAttributes the requested device for communication.
+ * Returns the communication client with the highest priority:
+ * - 1) the client which is currently also controlling the audio mode
+ * - 2) the first client in the stack if there is no audio mode owner
+ * - 3) no client otherwise
+ * @return CommunicationRouteClient the client driving the communication use case routing.
*/
-
@GuardedBy("mDeviceStateLock")
- private AudioDeviceAttributes requestedCommunicationDevice() {
- AudioDeviceAttributes device = null;
- for (CommunicationRouteClient cl : mCommunicationRouteClients) {
- if (cl.getPid() == mModeOwnerPid) {
- device = cl.getDevice();
+ private CommunicationRouteClient topCommunicationRouteClient() {
+ for (CommunicationRouteClient crc : mCommunicationRouteClients) {
+ if (crc.getPid() == mModeOwnerPid) {
+ return crc;
}
}
if (!mCommunicationRouteClients.isEmpty() && mModeOwnerPid == 0) {
- device = mCommunicationRouteClients.get(0).getDevice();
+ return mCommunicationRouteClients.get(0);
}
+ return null;
+ }
+ /**
+ * Returns the device currently requested for communication use case.
+ * Use the device requested by the communication route client selected by
+ * {@link #topCommunicationRouteClient()} if any or none otherwise.
+ * @return AudioDeviceAttributes the requested device for communication.
+ */
+ @GuardedBy("mDeviceStateLock")
+ private AudioDeviceAttributes requestedCommunicationDevice() {
+ CommunicationRouteClient crc = topCommunicationRouteClient();
+ AudioDeviceAttributes device = crc != null ? crc.getDevice() : null;
if (AudioService.DEBUG_COMM_RTE) {
Log.v(TAG, "requestedCommunicationDevice, device: "
+ device + " mode owner pid: " + mModeOwnerPid);
@@ -644,7 +653,7 @@
}
synchronized (mDeviceStateLock) {
mBluetoothScoOn = on;
- sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource);
+ postUpdateCommunicationRouteClient(eventSource);
}
}
@@ -699,7 +708,9 @@
synchronized (mDeviceStateLock) {
AudioDeviceAttributes device =
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
- setCommunicationRouteForClient(cb, pid, device, scoAudioMode, eventSource);
+
+ postSetCommunicationRouteForClient(new CommunicationClientInfo(
+ cb, pid, device, scoAudioMode, eventSource));
}
}
}
@@ -717,8 +728,8 @@
if (client == null || !client.requestsBluetoothSco()) {
return;
}
- setCommunicationRouteForClient(
- cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource);
+ postSetCommunicationRouteForClient(new CommunicationClientInfo(
+ cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource));
}
}
}
@@ -960,6 +971,61 @@
MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset);
}
+ /*package*/ void postUpdateCommunicationRouteClient(String eventSource) {
+ sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE, eventSource);
+ }
+
+ /*package*/ void postSetCommunicationRouteForClient(CommunicationClientInfo info) {
+ sendLMsgNoDelay(MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT, SENDMSG_QUEUE, info);
+ }
+
+ /*package*/ void postScoAudioStateChanged(int state) {
+ sendIMsgNoDelay(MSG_I_SCO_AUDIO_STATE_CHANGED, SENDMSG_QUEUE, state);
+ }
+
+ /*package*/ static final class CommunicationClientInfo {
+ final @NonNull IBinder mCb;
+ final int mPid;
+ final @NonNull AudioDeviceAttributes mDevice;
+ final int mScoAudioMode;
+ final @NonNull String mEventSource;
+
+ CommunicationClientInfo(@NonNull IBinder cb, int pid, @NonNull AudioDeviceAttributes device,
+ int scoAudioMode, @NonNull String eventSource) {
+ mCb = cb;
+ mPid = pid;
+ mDevice = device;
+ mScoAudioMode = scoAudioMode;
+ mEventSource = eventSource;
+ }
+
+ // redefine equality op so we can match messages intended for this client
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) {
+ return false;
+ }
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof CommunicationClientInfo)) {
+ return false;
+ }
+
+ return mCb.equals(((CommunicationClientInfo) o).mCb)
+ && mPid == ((CommunicationClientInfo) o).mPid;
+ }
+
+ @Override
+ public String toString() {
+ return "CommunicationClientInfo mCb=" + mCb.toString()
+ +"mPid=" + mPid
+ +"mDevice=" + mDevice.toString()
+ +"mScoAudioMode=" + mScoAudioMode
+ +"mEventSource=" + mEventSource;
+ }
+ }
+
//---------------------------------------------------------------------
// Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
// only call from a "handle"* method or "on"* method
@@ -1270,18 +1336,30 @@
synchronized (mDeviceStateLock) {
mModeOwnerPid = msg.arg1;
if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
- onUpdateCommunicationRoute("setNewModeOwner");
+ onUpdateCommunicationRouteClient("setNewModeOwner");
}
}
}
break;
- case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED:
+
+ case MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
- onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj);
+ CommunicationClientInfo info = (CommunicationClientInfo) msg.obj;
+ setCommunicationRouteForClient(info.mCb, info.mPid, info.mDevice,
+ info.mScoAudioMode, info.mEventSource);
}
}
break;
+
+ case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT:
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ onUpdateCommunicationRouteClient((String) msg.obj);
+ }
+ }
+ break;
+
case MSG_L_UPDATE_COMMUNICATION_ROUTE:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
@@ -1289,6 +1367,23 @@
}
}
break;
+
+ case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED:
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj);
+ }
+ }
+ break;
+
+ case MSG_I_SCO_AUDIO_STATE_CHANGED:
+ synchronized (mSetModeLock) {
+ synchronized (mDeviceStateLock) {
+ mBtHelper.onScoAudioStateChanged(msg.arg1);
+ }
+ }
+ break;
+
case MSG_TOGGLE_HDMI:
synchronized (mDeviceStateLock) {
mDeviceInventory.onToggleHdmi();
@@ -1495,6 +1590,9 @@
private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39;
private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
+ private static final int MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT = 42;
+ private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
+ private static final int MSG_I_SCO_AUDIO_STATE_CHANGED = 44;
private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) {
@@ -1720,9 +1818,8 @@
return;
}
Log.w(TAG, "Communication client died");
- setCommunicationRouteForClient(
- client.getBinder(), client.getPid(), null, BtHelper.SCO_MODE_UNDEFINED,
- "onCommunicationRouteClientDied");
+ removeCommunicationRouteClient(client.getBinder(), true);
+ onUpdateCommunicationRouteClient("onCommunicationRouteClientDied");
}
/**
@@ -1776,11 +1873,31 @@
AudioSystem.setParameters("BT_SCO=on");
}
if (preferredCommunicationDevice == null) {
- postRemovePreferredDevicesForStrategy(mCommunicationStrategyId);
+ removePreferredDevicesForStrategySync(mCommunicationStrategyId);
} else {
- postSetPreferredDevicesForStrategy(
+ setPreferredDevicesForStrategySync(
mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
}
+ onUpdatePhoneStrategyDevice(preferredCommunicationDevice);
+ }
+
+ /**
+ * Select new communication device from communication route client at the top of the stack
+ * and restore communication route including restarting SCO audio if needed.
+ */
+ // @GuardedBy("mSetModeLock")
+ @GuardedBy("mDeviceStateLock")
+ private void onUpdateCommunicationRouteClient(String eventSource) {
+ onUpdateCommunicationRoute(eventSource);
+ CommunicationRouteClient crc = topCommunicationRouteClient();
+ if (AudioService.DEBUG_COMM_RTE) {
+ Log.v(TAG, "onUpdateCommunicationRouteClient, crc: "
+ + crc + " eventSource: " + eventSource);
+ }
+ if (crc != null) {
+ setCommunicationRouteForClient(crc.getBinder(), crc.getPid(), crc.getDevice(),
+ BtHelper.SCO_MODE_UNDEFINED, eventSource);
+ }
}
private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) {
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 52e8edf..a9a8d10 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -99,9 +99,9 @@
// SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
/*package*/ static final int SCO_MODE_VIRTUAL_CALL = 0;
// SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
- private static final int SCO_MODE_RAW = 1;
+ private static final int SCO_MODE_RAW = 1;
// SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
- private static final int SCO_MODE_VR = 2;
+ private static final int SCO_MODE_VR = 2;
// max valid SCO audio mode values
private static final int SCO_MODE_MAX = 2;
@@ -300,69 +300,77 @@
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
setBtScoActiveDevice(btDevice);
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
- boolean broadcast = false;
- int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
- Log.i(TAG, "receiveBtEvent ACTION_AUDIO_STATE_CHANGED: " + btState);
- switch (btState) {
- case BluetoothHeadset.STATE_AUDIO_CONNECTED:
- scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
- if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
- && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
- mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
- } else if (mDeviceBroker.isBluetoothScoRequested()) {
- // broadcast intent if the connection was initated by AudioService
- broadcast = true;
- }
- mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent");
- break;
- case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
- mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
- scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
- // There are two cases where we want to immediately reconnect audio:
- // 1) If a new start request was received while disconnecting: this was
- // notified by requestScoState() setting state to SCO_STATE_ACTIVATE_REQ.
- // 2) If audio was connected then disconnected via Bluetooth APIs and
- // we still have pending activation requests by apps: this is indicated by
- // state SCO_STATE_ACTIVE_EXTERNAL and BT SCO is requested.
- if (mScoAudioState == SCO_STATE_ACTIVATE_REQ
- || (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL
- && mDeviceBroker.isBluetoothScoRequested())) {
- if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
- && connectBluetoothScoAudioHelper(mBluetoothHeadset,
- mBluetoothHeadsetDevice, mScoAudioMode)) {
- mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
- scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTING;
- broadcast = true;
- break;
- }
- }
- if (mScoAudioState != SCO_STATE_ACTIVE_EXTERNAL) {
- broadcast = true;
- }
- mScoAudioState = SCO_STATE_INACTIVE;
- break;
- case BluetoothHeadset.STATE_AUDIO_CONNECTING:
- if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
- && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
- mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
- }
- break;
- default:
- break;
- }
- if (broadcast) {
- broadcastScoConnectionState(scoAudioState);
- //FIXME: this is to maintain compatibility with deprecated intent
- // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
- Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
- newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
- sendStickyBroadcastToAll(newIntent);
- }
+ Log.i(TAG,"receiveBtEvent ACTION_AUDIO_STATE_CHANGED: "+btState);
+ mDeviceBroker.postScoAudioStateChanged(btState);
}
}
/**
+ * Exclusively called from AudioDeviceBroker when handling MSG_I_SCO_AUDIO_STATE_CHANGED
+ * as part of the serialization of the communication route selection
+ */
+ // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+ @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ void onScoAudioStateChanged(int state) {
+ boolean broadcast = false;
+ int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
+ switch (state) {
+ case BluetoothHeadset.STATE_AUDIO_CONNECTED:
+ scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
+ if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
+ && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
+ mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+ } else if (mDeviceBroker.isBluetoothScoRequested()) {
+ // broadcast intent if the connection was initated by AudioService
+ broadcast = true;
+ }
+ mDeviceBroker.setBluetoothScoOn(true, "BtHelper.receiveBtEvent");
+ break;
+ case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
+ mDeviceBroker.setBluetoothScoOn(false, "BtHelper.receiveBtEvent");
+ scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
+ // There are two cases where we want to immediately reconnect audio:
+ // 1) If a new start request was received while disconnecting: this was
+ // notified by requestScoState() setting state to SCO_STATE_ACTIVATE_REQ.
+ // 2) If audio was connected then disconnected via Bluetooth APIs and
+ // we still have pending activation requests by apps: this is indicated by
+ // state SCO_STATE_ACTIVE_EXTERNAL and BT SCO is requested.
+ if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
+ if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
+ && connectBluetoothScoAudioHelper(mBluetoothHeadset,
+ mBluetoothHeadsetDevice, mScoAudioMode)) {
+ mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+ scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTING;
+ broadcast = true;
+ break;
+ }
+ }
+ if (mScoAudioState != SCO_STATE_ACTIVE_EXTERNAL) {
+ broadcast = true;
+ }
+ mScoAudioState = SCO_STATE_INACTIVE;
+ break;
+ case BluetoothHeadset.STATE_AUDIO_CONNECTING:
+ if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
+ && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
+ mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
+ }
+ break;
+ default:
+ break;
+ }
+ if(broadcast) {
+ broadcastScoConnectionState(scoAudioState);
+ //FIXME: this is to maintain compatibility with deprecated intent
+ // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
+ Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
+ newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
+ sendStickyBroadcastToAll(newIntent);
+ }
+
+ }
+ /**
*
* @return false if SCO isn't connected
*/
@@ -752,6 +760,15 @@
case SCO_STATE_ACTIVE_INTERNAL:
Log.w(TAG, "requestScoState: already in ACTIVE mode, simply return");
break;
+ case SCO_STATE_ACTIVE_EXTERNAL:
+ /* Confirm SCO Audio connection to requesting app as it is already connected
+ * externally (i.e. through SCO APIs by Telecom service).
+ * Once SCO Audio is disconnected by the external owner, we will reconnect it
+ * automatically on behalf of the requesting app and the state will move to
+ * SCO_STATE_ACTIVE_INTERNAL.
+ */
+ broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
+ break;
default:
Log.w(TAG, "requestScoState: failed to connect in state "
+ mScoAudioState + ", scoAudioMode=" + scoAudioMode);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 42c6dd43..b184d5c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4193,17 +4193,17 @@
*/
@VisibleForTesting
SurfaceControl computeImeParent() {
+ if (mImeLayeringTarget != null && mImeInputTarget != null
+ && mImeLayeringTarget.mActivityRecord != mImeInputTarget.mActivityRecord) {
+ // Do not change parent if the window hasn't requested IME.
+ return null;
+ }
// Attach it to app if the target is part of an app and such app is covering the entire
// screen. If it's not covering the entire screen the IME might extend beyond the apps
// bounds.
if (shouldImeAttachedToApp()) {
- if (mImeLayeringTarget.mActivityRecord != mImeInputTarget.mActivityRecord) {
- // Do not change parent if the window hasn't requested IME.
- return null;
- }
return mImeLayeringTarget.mActivityRecord.getSurfaceControl();
}
-
// Otherwise, we just attach it to where the display area policy put it.
return mImeWindowsContainer.getParent() != null
? mImeWindowsContainer.getParent().getSurfaceControl() : null;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 1ff2ebe..d54a388 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -967,6 +967,26 @@
break;
}
+ if (LayoutParams.isSystemAlertWindowType(attrs.type)) {
+ float maxOpacity = mService.mMaximumObscuringOpacityForTouch;
+ if (attrs.alpha > maxOpacity
+ && (attrs.flags & FLAG_NOT_TOUCHABLE) != 0
+ && (attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) == 0) {
+ // The app is posting a SAW with the intent of letting touches pass through, but
+ // they are going to be deemed untrusted and will be blocked. Try to honor the
+ // intent of letting touches pass through at the cost of 0.2 opacity for app
+ // compatibility reasons. More details on b/218777508.
+ Slog.w(TAG, String.format(
+ "App %s has a system alert window (type = %d) with FLAG_NOT_TOUCHABLE and "
+ + "LayoutParams.alpha = %.2f > %.2f, setting alpha to %.2f to "
+ + "let touches pass through (if this is isn't desirable, remove "
+ + "flag FLAG_NOT_TOUCHABLE).",
+ attrs.packageName, attrs.type, attrs.alpha, maxOpacity, maxOpacity));
+ attrs.alpha = maxOpacity;
+ win.mWinAnimator.mAlpha = maxOpacity;
+ }
+ }
+
// Check if alternate bars positions were updated.
if (mStatusBarAlt == win) {
mStatusBarAltPosition = getAltBarPosition(attrs);
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 10ae152..5124841 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -265,14 +265,12 @@
return state;
}
} else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
- // During switching tasks with gestural navigation, if the IME is attached to
- // one app window on that time, even the next app window is behind the IME window,
- // conceptually the window should not receive the IME insets if the next window is
- // not eligible IME requester and ready to show IME on top of it.
- final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp();
+ // During switching tasks with gestural navigation, before the next IME input target
+ // starts the input, we should adjust and freeze the last IME visibility of the window
+ // in case delivering obsoleted IME insets state during transitioning.
final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
- if (shouldImeAttachedToApp && originalImeSource != null) {
+ if (originalImeSource != null) {
final boolean imeVisibility =
w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME);
final InsetsState state = copyState ? new InsetsState(originalState)
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 575ae691..8839fba 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -769,6 +769,9 @@
private final DisplayHashController mDisplayHashController;
+ volatile float mMaximumObscuringOpacityForTouch =
+ InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
+
@VisibleForTesting
final WindowContextListenerController mWindowContextListenerController =
new WindowContextListenerController();
@@ -801,6 +804,8 @@
DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR);
private final Uri mDisplaySettingsPathUri = Settings.Global.getUriFor(
DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
+ private final Uri mMaximumObscuringOpacityForTouchUri = Settings.Global.getUriFor(
+ Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
public SettingsObserver() {
super(new Handler());
@@ -827,6 +832,8 @@
UserHandle.USER_ALL);
resolver.registerContentObserver(mDisplaySettingsPathUri, false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(mMaximumObscuringOpacityForTouchUri, false, this,
+ UserHandle.USER_ALL);
}
@Override
@@ -875,6 +882,11 @@
return;
}
+ if (mMaximumObscuringOpacityForTouchUri.equals(uri)) {
+ updateMaximumObscuringOpacityForTouch();
+ return;
+ }
+
@UpdateAnimationScaleMode
final int mode;
if (mWindowAnimationScaleUri.equals(uri)) {
@@ -894,6 +906,14 @@
void loadSettings() {
updateSystemUiSettings(false /* handleChange */);
updatePointerLocation();
+ updateMaximumObscuringOpacityForTouch();
+ }
+
+ void updateMaximumObscuringOpacityForTouch() {
+ ContentResolver resolver = mContext.getContentResolver();
+ mMaximumObscuringOpacityForTouch = Settings.Global.getFloat(resolver,
+ Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH,
+ InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
}
void updateSystemUiSettings(boolean handleChange) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
index d7cbd9b..346e859 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
@@ -31,6 +31,7 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -54,7 +55,9 @@
import java.io.FileNotFoundException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.security.SecureRandom;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Class managing bugreport collection upon device owner's request.
@@ -78,6 +81,9 @@
private final DevicePolicyManagerService mService;
private final DevicePolicyManagerService.Injector mInjector;
+ private final SecureRandom mRng = new SecureRandom();
+
+ private final AtomicLong mRemoteBugreportNonce = new AtomicLong();
private final AtomicBoolean mRemoteBugreportServiceIsActive = new AtomicBoolean();
private final AtomicBoolean mRemoteBugreportSharingAccepted = new AtomicBoolean();
private final Context mContext;
@@ -197,8 +203,13 @@
final long callingIdentity = mInjector.binderClearCallingIdentity();
try {
- mInjector.getIActivityManager().requestRemoteBugReport();
+ long nonce;
+ do {
+ nonce = mRng.nextLong();
+ } while (nonce == 0);
+ mInjector.getIActivityManager().requestRemoteBugReport(nonce);
+ mRemoteBugreportNonce.set(nonce);
mRemoteBugreportServiceIsActive.set(true);
mRemoteBugreportSharingAccepted.set(false);
registerRemoteBugreportReceivers();
@@ -231,6 +242,11 @@
}
private void onBugreportFinished(Intent intent) {
+ long nonce = intent.getLongExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_NONCE, 0);
+ if (nonce == 0 || mRemoteBugreportNonce.get() != nonce) {
+ Slogf.w(LOG_TAG, "Invalid nonce provided, ignoring " + nonce);
+ return;
+ }
mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
mRemoteBugreportServiceIsActive.set(false);
final Uri bugreportUri = intent.getData();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index b770b3e..32cee44 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -3065,11 +3065,11 @@
// Simulate app re-start input or turning screen off/on then unlocked by un-secure
// keyguard to back to the app, expect IME insets is not frozen
+ mDisplayContent.updateImeInputAndControlTarget(app);
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
imeSource.setFrame(new Rect(100, 400, 500, 500));
app.getInsetsState().addSource(imeSource);
app.getInsetsState().setSourceVisible(ITYPE_IME, true);
- mDisplayContent.updateImeInputAndControlTarget(app);
- assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
// Verify when IME is visible and the app can receive the right IME insets from policy.
makeWindowVisibleAndDrawn(app, mImeWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index f3c1ec5..9c0c213c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1075,6 +1075,21 @@
assertEquals(dc.getImeContainer().getParentSurfaceControl(), dc.computeImeParent());
}
+ @UseTestDisplay(addWindows = W_ACTIVITY)
+ @Test
+ public void testComputeImeParent_inputTargetNotUpdate() throws Exception {
+ WindowState app1 = createWindow(null, TYPE_BASE_APPLICATION, "app1");
+ WindowState app2 = createWindow(null, TYPE_BASE_APPLICATION, "app2");
+ doReturn(true).when(mDisplayContent).shouldImeAttachedToApp();
+ mDisplayContent.setImeLayeringTarget(app1);
+ mDisplayContent.setImeInputTarget(app1);
+ assertEquals(app1.mActivityRecord.getSurfaceControl(), mDisplayContent.computeImeParent());
+ mDisplayContent.setImeLayeringTarget(app2);
+ // Expect null means no change IME parent when the IME layering target not yet
+ // request IME to be the input target.
+ assertNull(mDisplayContent.computeImeParent());
+ }
+
@Test
public void testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved() throws Exception {
final DisplayContent dc = createNewDisplay();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 7d50135..03b8188 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -931,6 +931,47 @@
@UseTestDisplay(addWindows = { W_ACTIVITY })
@Test
+ public void testAdjustImeInsetsVisibilityWhenSwitchingApps_toAppInMultiWindowMode() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ final WindowState app2 = createWindow(null, WINDOWING_MODE_MULTI_WINDOW,
+ ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app2");
+ final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+ spyOn(imeWindow);
+ doReturn(true).when(imeWindow).isVisible();
+ mDisplayContent.mInputMethodWindow = imeWindow;
+
+ final InsetsStateController controller = mDisplayContent.getInsetsStateController();
+ controller.getImeSourceProvider().setWindow(imeWindow, null, null);
+
+ // Simulate app2 in multi-window mode is going to background to switch to the fullscreen
+ // app which requests IME with updating all windows Insets State when IME is above app.
+ app2.mActivityRecord.mImeInsetsFrozenUntilStartInput = true;
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+ assertTrue(mDisplayContent.shouldImeAttachedToApp());
+ controller.getImeSourceProvider().scheduleShowImePostLayout(app);
+ controller.getImeSourceProvider().getSource().setVisible(true);
+ controller.updateAboveInsetsState(imeWindow, false);
+
+ // Expect app windows behind IME can receive IME insets visible,
+ // but not for app2 in background.
+ assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+ assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+
+ // Simulate app plays closing transition to app2.
+ // And app2 is now IME layering target but not yet to be the IME input target.
+ mDisplayContent.setImeLayeringTarget(app2);
+ app.mActivityRecord.commitVisibility(false, false);
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Verify the IME insets is still visible on app, but not for app2 during task switching.
+ assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+ assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+ }
+
+ @UseTestDisplay(addWindows = {W_ACTIVITY})
+ @Test
public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
WindowState app = createWindow(null, TYPE_BASE_APPLICATION,
mAppWindow.mToken, "app");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index d7a5f0a..fd3b18a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -67,6 +67,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SharedMemory;
+import android.provider.DeviceConfig;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordDetectionService;
import android.service.voice.HotwordRejectedResult;
@@ -109,12 +110,20 @@
private static final String TAG = "HotwordDetectionConnection";
static final boolean DEBUG = false;
+ private static final String KEY_RESTART_PERIOD_IN_SECONDS = "restart_period_in_seconds";
// TODO: These constants need to be refined.
private static final long VALIDATION_TIMEOUT_MILLIS = 4000;
private static final long MAX_UPDATE_TIMEOUT_MILLIS = 6000;
private static final Duration MAX_UPDATE_TIMEOUT_DURATION =
Duration.ofMillis(MAX_UPDATE_TIMEOUT_MILLIS);
private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
+ /**
+ * Time after which each HotwordDetectionService process is stopped and replaced by a new one.
+ * 0 indicates no restarts.
+ */
+ private static final int RESTART_PERIOD_SECONDS =
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_VOICE_INTERACTION,
+ KEY_RESTART_PERIOD_IN_SECONDS, 3600); // 60 minutes by default
private static final int MAX_ISOLATED_PROCESS_NUMBER = 10;
// Hotword metrics
@@ -133,6 +142,7 @@
// TODO: This may need to be a Handler(looper)
private final ScheduledExecutorService mScheduledExecutorService =
Executors.newSingleThreadScheduledExecutor();
+ @Nullable private final ScheduledFuture<?> mCancellationTaskFuture;
private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false);
private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied;
private final @NonNull ServiceConnectionFactory mServiceConnectionFactory;
@@ -148,7 +158,6 @@
private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback;
private Instant mLastRestartInstant;
- private ScheduledFuture<?> mCancellationTaskFuture;
private ScheduledFuture<?> mCancellationKeyPhraseDetectionFuture;
private ScheduledFuture<?> mDebugHotwordLoggingTimeoutFuture = null;
@@ -194,16 +203,20 @@
mLastRestartInstant = Instant.now();
updateStateAfterProcessStart(options, sharedMemory);
- // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait
- // until the current session is closed.
- mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> {
- Slog.v(TAG, "Time to restart the process, TTL has passed");
- synchronized (mLock) {
- restartProcessLocked();
- HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType,
- HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE);
- }
- }, 30, 30, TimeUnit.MINUTES);
+ if (RESTART_PERIOD_SECONDS <= 0) {
+ mCancellationTaskFuture = null;
+ } else {
+ // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait
+ // until the current session is closed.
+ mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> {
+ Slog.v(TAG, "Time to restart the process, TTL has passed");
+ synchronized (mLock) {
+ restartProcessLocked();
+ HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType,
+ HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE);
+ }
+ }, RESTART_PERIOD_SECONDS, RESTART_PERIOD_SECONDS, TimeUnit.SECONDS);
+ }
}
private void initAudioFlingerLocked() {
@@ -341,7 +354,9 @@
.setHotwordDetectionServiceProvider(null);
mIdentity = null;
updateServiceUidForAudioPolicy(Process.INVALID_UID);
- mCancellationTaskFuture.cancel(/* may interrupt */ true);
+ if (mCancellationTaskFuture != null) {
+ mCancellationTaskFuture.cancel(/* may interrupt */ true);
+ }
if (mAudioFlinger != null) {
mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0);
}
@@ -759,6 +774,7 @@
}
public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("RESTART_PERIOD_SECONDS="); pw.println(RESTART_PERIOD_SECONDS);
pw.print(prefix);
pw.print("mBound=" + mRemoteHotwordDetectionService.isBound());
pw.print(", mValidatingDspTrigger=" + mValidatingDspTrigger);