Merge "Accessibility node provider getting invalid virtual view id." into lmp-dev
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index b9507d7..68926d0 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -633,7 +633,11 @@
@Override
public void onDrained() {
if (VERBOSE) Log.v(TAG, mIdString + "onIdleDrained");
- synchronized (CameraCaptureSessionImpl.this) {
+
+ // Take device lock before session lock so that we can call back into device
+ // without causing a deadlock
+ synchronized (mDeviceImpl.mInterfaceLock) {
+ synchronized (CameraCaptureSessionImpl.this) {
/*
* The device is now IDLE, and has settled. It will not transition to
* ACTIVE or BUSY again by itself.
@@ -642,28 +646,31 @@
*
* This operation is idempotent; a session will not be closed twice.
*/
- if (VERBOSE) Log.v(TAG, mIdString + "Session drain complete, skip unconfigure: " +
- mSkipUnconfigure);
+ if (VERBOSE)
+ Log.v(TAG, mIdString + "Session drain complete, skip unconfigure: " +
+ mSkipUnconfigure);
- // Fast path: A new capture session has replaced this one; don't unconfigure.
- if (mSkipUnconfigure) {
- mStateCallback.onClosed(CameraCaptureSessionImpl.this);
- return;
+ // Fast path: A new capture session has replaced this one; don't unconfigure.
+ if (mSkipUnconfigure) {
+ mStateCallback.onClosed(CameraCaptureSessionImpl.this);
+ return;
+ }
+
+ // Slow path: #close was called explicitly on this session; unconfigure first
+
+ try {
+ mUnconfigureDrainer.taskStarted();
+ mDeviceImpl
+ .configureOutputsChecked(null); // begin transition to unconfigured
+ } catch (CameraAccessException e) {
+ // OK: do not throw checked exceptions.
+ Log.e(TAG, mIdString + "Exception while configuring outputs: ", e);
+
+ // TODO: call onError instead of onClosed if this happens
+ }
+
+ mUnconfigureDrainer.beginDrain();
}
-
- // Slow path: #close was called explicitly on this session; unconfigure first
-
- try {
- mUnconfigureDrainer.taskStarted();
- mDeviceImpl.configureOutputsChecked(null); // begin transition to unconfigured
- } catch (CameraAccessException e) {
- // OK: do not throw checked exceptions.
- Log.e(TAG, mIdString + "Exception while configuring outputs: ", e);
-
- // TODO: call onError instead of onClosed if this happens
- }
-
- mUnconfigureDrainer.beginDrain();
}
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 2578093..ec450bd1 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -60,7 +60,7 @@
private ICameraDeviceUser mRemoteDevice;
// Lock to synchronize cross-thread access to device public interface
- private final Object mInterfaceLock = new Object();
+ final Object mInterfaceLock = new Object(); // access from this class and Session only!
private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
private final StateCallback mDeviceCallback;
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index e96c15f7..89e2d98 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -73,6 +73,7 @@
void onError(int errorCode, RequestHolder holder);
void onConfiguring();
void onIdle();
+ void onBusy();
void onCaptureStarted(RequestHolder holder, long timestamp);
void onCaptureResult(CameraMetadataNative result, RequestHolder holder);
}
@@ -217,6 +218,20 @@
}
Log.i(TAG, "Legacy camera service transitioning to state " + stateName);
}
+
+ // If we transitioned into a non-IDLE/non-ERROR state then mark the device as busy
+ if(newState != STATE_ERROR && newState != STATE_IDLE) {
+ if (mCurrentState != newState && mCurrentHandler != null &&
+ mCurrentListener != null) {
+ mCurrentHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCurrentListener.onBusy();
+ }
+ });
+ }
+ }
+
switch(newState) {
case STATE_ERROR:
if (mCurrentState != STATE_ERROR && mCurrentHandler != null &&
diff --git a/core/java/android/hardware/camera2/legacy/GLThreadManager.java b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
index c8e0147..64c532b 100644
--- a/core/java/android/hardware/camera2/legacy/GLThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
@@ -113,6 +113,9 @@
case MSG_ALLOW_FRAMES:
mDroppingFrames = false;
break;
+ case RequestHandlerThread.MSG_POKE_IDLE_HANDLER:
+ // OK: Ignore message.
+ break;
default:
Log.e(TAG, "Unhandled message " + msg.what + " on GLThread.");
break;
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 4587c6f..3a976ba 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -21,6 +21,7 @@
import android.hardware.Camera;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.impl.CameraDeviceImpl;
import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.params.StreamConfiguration;
@@ -95,7 +96,25 @@
new CameraDeviceState.CameraDeviceStateListener() {
@Override
public void onError(final int errorCode, final RequestHolder holder) {
- mIdle.open();
+ if (DEBUG) {
+ Log.d(TAG, "onError called, errorCode = " + errorCode);
+ }
+ switch (errorCode) {
+ /*
+ * Only be considered idle if we hit a fatal error
+ * and no further requests can be processed.
+ */
+ case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DISCONNECTED:
+ case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_SERVICE:
+ case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE: {
+ mIdle.open();
+
+ if (DEBUG) {
+ Log.d(TAG, "onError - opening idle");
+ }
+ }
+ }
+
final CaptureResultExtras extras = getExtrasFromRequest(holder);
mResultHandler.post(new Runnable() {
@Override
@@ -124,6 +143,10 @@
@Override
public void onIdle() {
+ if (DEBUG) {
+ Log.d(TAG, "onIdle called");
+ }
+
mIdle.open();
mResultHandler.post(new Runnable() {
@@ -143,6 +166,15 @@
}
@Override
+ public void onBusy() {
+ mIdle.close();
+
+ if (DEBUG) {
+ Log.d(TAG, "onBusy called");
+ }
+ }
+
+ @Override
public void onCaptureStarted(final RequestHolder holder, final long timestamp) {
final CaptureResultExtras extras = getExtrasFromRequest(holder);
diff --git a/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java b/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
index 36cd907..0699ffb 100644
--- a/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
+++ b/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
@@ -23,6 +23,15 @@
import android.os.MessageQueue;
public class RequestHandlerThread extends HandlerThread {
+
+ /**
+ * Ensure that the MessageQueue's idle handler gets run by poking the message queue;
+ * normally if the message queue is already idle, the idle handler won't get invoked.
+ *
+ * <p>Users of this handler thread should ignore this message.</p>
+ */
+ public final static int MSG_POKE_IDLE_HANDLER = -1;
+
private final ConditionVariable mStarted = new ConditionVariable(false);
private final ConditionVariable mIdle = new ConditionVariable(true);
private Handler.Callback mCallback;
@@ -86,12 +95,15 @@
// Blocks until thread is idling
public void waitUntilIdle() {
- Looper looper = waitAndGetHandler().getLooper();
+ Handler handler = waitAndGetHandler();
+ Looper looper = handler.getLooper();
if (looper.isIdling()) {
return;
}
mIdle.close();
looper.getQueue().addIdleHandler(mIdleHandler);
+ // Ensure that the idle handler gets run even if the looper already went idle
+ handler.sendEmptyMessage(MSG_POKE_IDLE_HANDLER);
if (looper.isIdling()) {
return;
}
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index a7ea89c..17ce248 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -864,6 +864,9 @@
}
resetJpegSurfaceFormats(mCallbackOutputs);
break;
+ case RequestHandlerThread.MSG_POKE_IDLE_HANDLER:
+ // OK: Ignore message.
+ break;
default:
throw new AssertionError("Unhandled message " + msg.what +
" on RequestThread.");
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 4cdafe1..2785ee8 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -665,4 +665,12 @@
public static final int CRYPT_TYPE_PATTERN = 2;
/** @hide */
public static final int CRYPT_TYPE_PIN = 3;
+
+ // Constants for the data available via MountService.getField.
+ /** @hide */
+ public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
+ /** @hide */
+ public static final String OWNER_INFO_KEY = "OwnerInfo";
+ /** @hide */
+ public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 85b58aa..16fa88e 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -604,7 +604,7 @@
IMountService mountService = IMountService.Stub.asInterface(service);
try {
Log.d(TAG, "Setting owner info");
- mountService.setField("OwnerInfo", ownerInfo);
+ mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
} catch (RemoteException e) {
Log.e(TAG, "Error changing user info", e);
}
@@ -1144,7 +1144,7 @@
IMountService mountService = IMountService.Stub.asInterface(service);
try {
- mountService.setField("PatternVisible", enabled ? "1" : "0");
+ mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
} catch (RemoteException e) {
Log.e(TAG, "Error changing pattern visible state", e);
}
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 95c2d61..bb59e5b 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -38,4 +38,7 @@
// This is for the system volume UI only
void setRemoteVolumeController(in IRemoteVolumeController rvc);
+
+ // For PhoneWindowManager to precheck media keys
+ boolean isGlobalPriorityActive();
}
\ No newline at end of file
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 5ce7f9f..b37ee6e 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -232,6 +232,10 @@
}
}
+ public boolean isGlobalPriorityActive() {
+ return mSessionManager.isGlobalPriorityActive();
+ }
+
public void addRccListener(PendingIntent pi, MediaSession.Callback listener) {
if (pi == null) {
Log.w(TAG, "Pending intent was null, can't add rcc listener.");
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 185c6d8..b4fff8f 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -296,6 +296,21 @@
}
/**
+ * Check if the global priority session is currently active. This can be
+ * used to decide if media keys should be sent to the session or to the app.
+ *
+ * @hide
+ */
+ public boolean isGlobalPriorityActive() {
+ try {
+ return mService.isGlobalPriorityActive();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to check if the global priority is active.", e);
+ }
+ return false;
+ }
+
+ /**
* Listens for changes to the list of active sessions. This can be added
* using {@link #addOnActiveSessionsChangedListener}.
*/
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 6ea4497..f7ed364 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -4248,8 +4248,8 @@
boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
|| event.isWakeKey();
if (interactive || (isInjected && !isWakeKey)) {
- // When the device is interactive or the key is injected pass the key to the
- // application.
+ // When the device is interactive or the key is injected pass the
+ // key to the application.
result = ACTION_PASS_TO_USER;
isWakeKey = false;
} else if (!interactive && shouldDispatchInputWhenNonInteractive()) {
@@ -4449,16 +4449,6 @@
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- if (down) {
- TelecomManager telecomManager = getTelecommService();
- if (telecomManager != null) {
- if (telecomManager.isInCall()) {
- // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
- // to avoid music playback.
- break;
- }
- }
- }
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_MEDIA_STOP:
@@ -4468,6 +4458,11 @@
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+ if (MediaSessionLegacyHelper.getHelper(mContext).isGlobalPriorityActive()) {
+ // If the global session is active pass all media keys to it
+ // instead of the active window.
+ result &= ~ACTION_PASS_TO_USER;
+ }
if ((result & ACTION_PASS_TO_USER) == 0) {
// Only do this if we would otherwise not pass it to the user. In that
// case, the PhoneWindow class will do the same thing, except it will
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index ea24d7c..7f24d07 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.Manifest;
+import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -28,6 +29,7 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
import android.content.res.ObbInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -94,6 +96,7 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
@@ -821,6 +824,10 @@
*/
mConnectedSignal.countDown();
+ // On an encrypted device we can't see system properties yet, so pull
+ // the system locale out of the mount service.
+ copyLocaleFromMountService();
+
// Let package manager load internal ASECs.
mPms.scanAvailableAsecs();
@@ -830,6 +837,28 @@
}.start();
}
+ private void copyLocaleFromMountService() {
+ String systemLocale;
+ try {
+ systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
+ } catch (RemoteException e) {
+ return;
+ }
+ if (TextUtils.isEmpty(systemLocale)) {
+ return;
+ }
+
+ Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
+ Locale locale = Locale.forLanguageTag(systemLocale);
+ Configuration config = new Configuration();
+ config.setLocale(locale);
+ try {
+ ActivityManagerNative.getDefault().updateConfiguration(config);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error setting system locale from mount service", e);
+ }
+ }
+
/**
* Callback from NativeDaemonConnector
*/
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a30775b..d0463b7 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -48,6 +48,8 @@
import android.graphics.Rect;
import android.os.BatteryStats;
import android.os.PersistableBundle;
+import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1192,6 +1194,7 @@
static final int ENTER_ANIMATION_COMPLETE_MSG = 44;
static final int ENABLE_SCREEN_AFTER_BOOT_MSG = 45;
static final int START_USER_SWITCH_MSG = 46;
+ static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1878,6 +1881,18 @@
enableScreenAfterBoot();
break;
}
+ case SEND_LOCALE_TO_MOUNT_DAEMON_MSG: {
+ try {
+ Locale l = (Locale) msg.obj;
+ IBinder service = ServiceManager.getService("mount");
+ IMountService mountService = IMountService.Stub.asInterface(service);
+ Log.d(TAG, "Storing locale " + l.toLanguageTag() + " for decryption UI");
+ mountService.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error storing locale for decryption UI", e);
+ }
+ break;
+ }
}
}
};
@@ -16258,6 +16273,8 @@
SystemProperties.set("persist.sys.language", l.getLanguage());
SystemProperties.set("persist.sys.country", l.getCountry());
SystemProperties.set("persist.sys.localevar", l.getVariant());
+
+ mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG, l));
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index aaa29fc..02c9fcb5 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -743,6 +743,11 @@
}
@Override
+ public boolean isGlobalPriorityActive() {
+ return mPriorityStack.isGlobalPriorityActive();
+ }
+
+ @Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index e464be7..c48a075 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -217,6 +217,10 @@
return null;
}
+ public boolean isGlobalPriorityActive() {
+ return mGlobalPrioritySession == null ? false : mGlobalPrioritySession.isActive();
+ }
+
public void dump(PrintWriter pw, String prefix) {
ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0,
UserHandle.USER_ALL);