summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java207
-rw-r--r--core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java74
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java193
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java86
-rw-r--r--core/java/android/hardware/camera2/impl/ListenerProxies.java16
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java231
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java3
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java42
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java14
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyResultMapper.java14
-rw-r--r--core/java/android/hardware/camera2/legacy/ParameterUtils.java62
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestThreadManager.java71
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java7
-rw-r--r--core/java/android/os/UserManager.java9
-rw-r--r--core/java/android/widget/AbsListView.java16
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java6
-rw-r--r--core/java/android/widget/TimePickerSpinnerDelegate.java6
-rw-r--r--core/res/res/values/strings.xml4
-rw-r--r--core/res/res/values/symbols.xml6
-rw-r--r--docs/html/tools/support-library/features.jd8
-rw-r--r--graphics/java/android/graphics/drawable/NinePatchDrawable.java19
-rw-r--r--graphics/java/android/graphics/drawable/Ripple.java2
-rw-r--r--graphics/java/android/graphics/drawable/RippleBackground.java2
-rw-r--r--media/java/android/media/tv/ITvInputService.aidl4
-rw-r--r--media/java/android/media/tv/ITvInputServiceCallback.aidl4
-rw-r--r--media/java/android/media/tv/TvContentRating.java3
-rw-r--r--media/java/android/media/tv/TvContract.java1
-rw-r--r--media/java/android/media/tv/TvInputInfo.java34
-rw-r--r--media/java/android/media/tv/TvInputService.java57
-rw-r--r--packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java73
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java9
-rw-r--r--packages/SystemUI/res/layout/keyguard_user_switcher.xml5
-rw-r--r--packages/SystemUI/res/values/strings.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java38
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java6
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java16
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java132
-rw-r--r--services/core/java/com/android/server/DockObserver.java4
-rw-r--r--services/core/java/com/android/server/tv/TvInputHardwareManager.java62
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java26
-rwxr-xr-xtools/layoutlib/rename_font/build_font_single.py207
51 files changed, 1383 insertions, 619 deletions
diff --git a/api/current.txt b/api/current.txt
index 5cafd6c233df..07974ed8e356 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -37498,6 +37498,7 @@ package android.widget {
method public void clearChoices();
method public void clearTextFilter();
method public void deferNotifyDataSetChanged();
+ method public void fling(int);
method public int getCacheColorHint();
method public int getCheckedItemCount();
method public long[] getCheckedItemIds();
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index c4615119dc3b..6a9d56544184 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -130,15 +130,6 @@ public abstract class CameraDevice implements AutoCloseable {
public abstract String getId();
/**
- * <p>Set up a new output set of Surfaces for the camera device.</p>
- *
- * @deprecated Use {@link #createCaptureSession} instead
- * @hide
- */
- @Deprecated
- public abstract void configureOutputs(List<Surface> outputs) throws CameraAccessException;
-
- /**
* <p>Create a new camera capture session by providing the target output set of Surfaces to the
* camera device.</p>
*
@@ -276,68 +267,6 @@ public abstract class CameraDevice implements AutoCloseable {
throws CameraAccessException;
/**
- * <p>Submit a request for an image to be captured by this CameraDevice.</p>
- *
- * @deprecated Use {@link CameraCaptureSession#capture} instead
- * @hide
- */
- @Deprecated
- public abstract int capture(CaptureRequest request, CaptureListener listener, Handler handler)
- throws CameraAccessException;
-
- /**
- * Submit a list of requests to be captured in sequence as a burst.
- *
- * @deprecated Use {@link CameraCaptureSession#captureBurst} instead
- * @hide
- */
- @Deprecated
- public abstract int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
- Handler handler) throws CameraAccessException;
-
- /**
- * Request endlessly repeating capture of images by this CameraDevice.
- *
- * @deprecated Use {@link CameraCaptureSession#setRepeatingRequest} instead
- * @hide
- */
- @Deprecated
- public abstract int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
- Handler handler) throws CameraAccessException;
-
- /**
- * <p>Request endlessly repeating capture of a sequence of images by this
- * CameraDevice.</p>
- *
- * @deprecated Use {@link CameraCaptureSession#setRepeatingBurst} instead
- * @hide
- */
- @Deprecated
- public abstract int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
- Handler handler) throws CameraAccessException;
-
- /**
- * <p>Cancel any ongoing repeating capture set by either
- * {@link #setRepeatingRequest setRepeatingRequest} or
- * {@link #setRepeatingBurst}.
- *
- * @deprecated Use {@link CameraCaptureSession#stopRepeating} instead
- * @hide
- */
- @Deprecated
- public abstract void stopRepeating() throws CameraAccessException;
-
- /**
- * Flush all captures currently pending and in-progress as fast as
- * possible.
- *
- * @deprecated Use {@link CameraCaptureSession#abortCaptures} instead
- * @hide
- */
- @Deprecated
- public abstract void flush() throws CameraAccessException;
-
- /**
* Close the connection to this camera device as quickly as possible.
*
* <p>Immediately after this call, all calls to the camera device or active session interface
@@ -356,96 +285,6 @@ public abstract class CameraDevice implements AutoCloseable {
public abstract void close();
/**
- * <p>A listener for tracking the progress of a {@link CaptureRequest}
- * submitted to the camera device.</p>
- *
- * @deprecated Use {@link CameraCaptureSession.CaptureListener} instead
- * @hide
- */
- @Deprecated
- public static abstract class CaptureListener {
-
- /**
- * This constant is used to indicate that no images were captured for
- * the request.
- *
- * @hide
- */
- public static final int NO_FRAMES_CAPTURED = -1;
-
- /**
- * This method is called when the camera device has started capturing
- * the output image for the request, at the beginning of image exposure.
- *
- * @see android.media.MediaActionSound
- */
- public void onCaptureStarted(CameraDevice camera,
- CaptureRequest request, long timestamp) {
- // default empty implementation
- }
-
- /**
- * This method is called when some results from an image capture are
- * available.
- *
- * @hide
- */
- public void onCapturePartial(CameraDevice camera,
- CaptureRequest request, CaptureResult result) {
- // default empty implementation
- }
-
- /**
- * This method is called when an image capture makes partial forward progress; some
- * (but not all) results from an image capture are available.
- *
- */
- public void onCaptureProgressed(CameraDevice camera,
- CaptureRequest request, CaptureResult partialResult) {
- // default empty implementation
- }
-
- /**
- * This method is called when an image capture has fully completed and all the
- * result metadata is available.
- */
- public void onCaptureCompleted(CameraDevice camera,
- CaptureRequest request, TotalCaptureResult result) {
- // default empty implementation
- }
-
- /**
- * This method is called instead of {@link #onCaptureCompleted} when the
- * camera device failed to produce a {@link CaptureResult} for the
- * request.
- */
- public void onCaptureFailed(CameraDevice camera,
- CaptureRequest request, CaptureFailure failure) {
- // default empty implementation
- }
-
- /**
- * This method is called independently of the others in CaptureListener,
- * when a capture sequence finishes and all {@link CaptureResult}
- * or {@link CaptureFailure} for it have been returned via this listener.
- */
- public void onCaptureSequenceCompleted(CameraDevice camera,
- int sequenceId, long frameNumber) {
- // default empty implementation
- }
-
- /**
- * This method is called independently of the others in CaptureListener,
- * when a capture sequence aborts before any {@link CaptureResult}
- * or {@link CaptureFailure} for it have been returned via this listener.
- */
- public void onCaptureSequenceAborted(CameraDevice camera,
- int sequenceId) {
- // default empty implementation
- }
- }
-
- /**
* A listener for notifications about the state of a camera
* device.
*
@@ -542,40 +381,6 @@ public abstract class CameraDevice implements AutoCloseable {
public abstract void onOpened(CameraDevice camera); // Must implement
/**
- * The method called when a camera device has no outputs configured.
- *
- * @deprecated Use {@link #onOpened} instead.
- * @hide
- */
- @Deprecated
- public void onUnconfigured(CameraDevice camera) {
- // Default empty implementation
- }
-
- /**
- * The method called when a camera device begins processing
- * {@link CaptureRequest capture requests}.
- *
- * @deprecated Use {@link CameraCaptureSession.StateListener#onActive} instead.
- * @hide
- */
- @Deprecated
- public void onActive(CameraDevice camera) {
- // Default empty implementation
- }
-
- /**
- * The method called when a camera device is busy.
- *
- * @deprecated Use {@link CameraCaptureSession.StateListener#onConfigured} instead.
- * @hide
- */
- @Deprecated
- public void onBusy(CameraDevice camera) {
- // Default empty implementation
- }
-
- /**
* The method called when a camera device has been closed with
* {@link CameraDevice#close}.
*
@@ -591,18 +396,6 @@ public abstract class CameraDevice implements AutoCloseable {
}
/**
- * The method called when a camera device has finished processing all
- * submitted capture requests and has reached an idle state.
- *
- * @deprecated Use {@link CameraCaptureSession.StateListener#onReady} instead.
- * @hide
- */
- @Deprecated
- public void onIdle(CameraDevice camera) {
- // Default empty implementation
- }
-
- /**
* The method called when a camera device is no longer available for
* use.
*
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index f829f5eb5d07..a15028c3b141 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -103,7 +103,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* Use the same handler as the device's StateListener for all the internal coming events
*
* This ensures total ordering between CameraDevice.StateListener and
- * CameraDevice.CaptureListener events.
+ * CameraDeviceImpl.CaptureListener events.
*/
mSequenceDrainer = new TaskDrainer<>(mDeviceHandler, new SequenceDrainListener(),
/*name*/"seq");
@@ -141,7 +141,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
checkNotClosed();
checkLegalToCapture();
- handler = checkHandler(handler);
+ handler = checkHandler(handler, listener);
if (VERBOSE) {
Log.v(TAG, "capture - request " + request + ", listener " + listener + " handler" +
@@ -164,7 +164,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
checkNotClosed();
checkLegalToCapture();
- handler = checkHandler(handler);
+ handler = checkHandler(handler, listener);
if (VERBOSE) {
CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]);
@@ -186,7 +186,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
checkNotClosed();
checkLegalToCapture();
- handler = checkHandler(handler);
+ handler = checkHandler(handler, listener);
if (VERBOSE) {
Log.v(TAG, "setRepeatingRequest - request " + request + ", listener " + listener +
@@ -209,7 +209,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
checkNotClosed();
checkLegalToCapture();
- handler = checkHandler(handler);
+ handler = checkHandler(handler, listener);
if (VERBOSE) {
CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]);
@@ -261,9 +261,12 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* <p>The semantics are identical to {@link #close}, except that unconfiguring will be skipped.
* <p>
*
+ * <p>After this call completes, the session will not call any further methods on the camera
+ * device.</p>
+ *
* @see CameraCaptureSession#close
*/
- synchronized void replaceSessionClose(CameraCaptureSession other) {
+ synchronized void replaceSessionClose() {
/*
* In order for creating new sessions to be fast, the new session should be created
* before the old session is closed.
@@ -278,13 +281,17 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
if (VERBOSE) Log.v(TAG, "replaceSessionClose");
- // #close was already called explicitly, keep going the slow route
- if (mClosed) {
- if (VERBOSE) Log.v(TAG, "replaceSessionClose - close was already called");
- return;
- }
-
+ // Set up fast shutdown. Possible alternative paths:
+ // - This session is active, so close() below starts the shutdown drain
+ // - This session is mid-shutdown drain, and hasn't yet reached the idle drain listener.
+ // - This session is already closed and has executed the idle drain listener, and
+ // configureOutputs(null) has already been called.
+ //
+ // Do not call configureOutputs(null) going forward, since it would race with the
+ // configuration for the new session. If it was already called, then we don't care, since it
+ // won't get called again.
mSkipUnconfigure = true;
+
close();
}
@@ -347,7 +354,7 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
/**
* Forward callbacks from
- * CameraDevice.CaptureListener to the CameraCaptureSession.CaptureListener.
+ * CameraDeviceImpl.CaptureListener to the CameraCaptureSession.CaptureListener.
*
* <p>In particular, all calls are automatically split to go both to our own
* internal listener, and to the user-specified listener (by transparently posting
@@ -356,9 +363,9 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* <p>When a capture sequence finishes, update the pending checked sequences set.</p>
*/
@SuppressWarnings("deprecation")
- private CameraDevice.CaptureListener createCaptureListenerProxy(
+ private CameraDeviceImpl.CaptureListener createCaptureListenerProxy(
Handler handler, CaptureListener listener) {
- CameraDevice.CaptureListener localListener = new CameraDevice.CaptureListener() {
+ CameraDeviceImpl.CaptureListener localListener = new CameraDeviceImpl.CaptureListener() {
@Override
public void onCaptureSequenceCompleted(CameraDevice camera,
int sequenceId, long frameNumber) {
@@ -379,27 +386,30 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* - then forward the call to a handler
* - then finally invoke the destination method on the session listener object
*/
- Dispatchable<CaptureListener> userListenerSink;
- if (listener == null) { // OK: API allows the user to not specify a listener
- userListenerSink = new NullDispatcher<>();
- } else {
- userListenerSink = new InvokeDispatcher<>(listener);
+ if (listener == null) {
+ // OK: API allows the user to not specify a listener, and the handler may
+ // also be null in that case. Collapse whole dispatch chain to only call the local
+ // listener
+ return localListener;
}
- InvokeDispatcher<CameraDevice.CaptureListener> localSink =
+ InvokeDispatcher<CameraDeviceImpl.CaptureListener> localSink =
new InvokeDispatcher<>(localListener);
+
+ InvokeDispatcher<CaptureListener> userListenerSink =
+ new InvokeDispatcher<>(listener);
HandlerDispatcher<CaptureListener> handlerPassthrough =
new HandlerDispatcher<>(userListenerSink, handler);
- DuckTypingDispatcher<CameraDevice.CaptureListener, CaptureListener> duckToSession
+ DuckTypingDispatcher<CameraDeviceImpl.CaptureListener, CaptureListener> duckToSession
= new DuckTypingDispatcher<>(handlerPassthrough, CaptureListener.class);
- ArgumentReplacingDispatcher<CameraDevice.CaptureListener, CameraCaptureSessionImpl>
- replaceDeviceWithSession = new ArgumentReplacingDispatcher<>(duckToSession,
- /*argumentIndex*/0, this);
+ ArgumentReplacingDispatcher<CameraDeviceImpl.CaptureListener, CameraCaptureSessionImpl>
+ replaceDeviceWithSession = new ArgumentReplacingDispatcher<>(duckToSession,
+ /*argumentIndex*/0, this);
- BroadcastDispatcher<CameraDevice.CaptureListener> broadcaster =
- new BroadcastDispatcher<CameraDevice.CaptureListener>(
- replaceDeviceWithSession,
- localSink);
+ BroadcastDispatcher<CameraDeviceImpl.CaptureListener> broadcaster =
+ new BroadcastDispatcher<CameraDeviceImpl.CaptureListener>(
+ replaceDeviceWithSession,
+ localSink);
return new ListenerProxies.DeviceCaptureListenerProxy(broadcaster);
}
@@ -415,10 +425,10 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* </ul>
* </p>
* */
- CameraDevice.StateListener getDeviceStateListener() {
+ CameraDeviceImpl.StateListenerKK getDeviceStateListener() {
final CameraCaptureSession session = this;
- return new CameraDevice.StateListener() {
+ return new CameraDeviceImpl.StateListenerKK() {
private boolean mBusy = false;
private boolean mActive = false;
@@ -596,6 +606,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
*
* This operation is idempotent; a session will not be closed twice.
*/
+ if (VERBOSE) Log.v(TAG, "Session drain complete, skip unconfigure: " +
+ mSkipUnconfigure);
// Fast path: A new capture session has replaced this one; don't unconfigure.
if (mSkipUnconfigure) {
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 18b12022ab35..71eb0e9f2883 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -21,8 +21,10 @@ import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.TotalCaptureResult;
@@ -47,7 +49,7 @@ import java.util.TreeSet;
/**
* HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
*/
-public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
+public class CameraDeviceImpl extends CameraDevice {
private final String TAG;
private final boolean DEBUG;
@@ -62,7 +64,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
private final StateListener mDeviceListener;
- private volatile StateListener mSessionStateListener;
+ private volatile StateListenerKK mSessionStateListener;
private final Handler mDeviceHandler;
private volatile boolean mClosing = false;
@@ -103,7 +105,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
private final Runnable mCallOnOpened = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -119,7 +121,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
private final Runnable mCallOnUnconfigured = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -128,14 +130,13 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (sessionListener != null) {
sessionListener.onUnconfigured(CameraDeviceImpl.this);
}
- mDeviceListener.onUnconfigured(CameraDeviceImpl.this);
}
};
private final Runnable mCallOnActive = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -144,14 +145,13 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (sessionListener != null) {
sessionListener.onActive(CameraDeviceImpl.this);
}
- mDeviceListener.onActive(CameraDeviceImpl.this);
}
};
private final Runnable mCallOnBusy = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -160,7 +160,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (sessionListener != null) {
sessionListener.onBusy(CameraDeviceImpl.this);
}
- mDeviceListener.onBusy(CameraDeviceImpl.this);
}
};
@@ -172,7 +171,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (mClosedOnce) {
throw new AssertionError("Don't post #onClosed more than once");
}
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
sessionListener = mSessionStateListener;
}
@@ -187,7 +186,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
private final Runnable mCallOnIdle = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -196,14 +195,13 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
if (sessionListener != null) {
sessionListener.onIdle(CameraDeviceImpl.this);
}
- mDeviceListener.onIdle(CameraDeviceImpl.this);
}
};
private final Runnable mCallOnDisconnected = new Runnable() {
@Override
public void run() {
- StateListener sessionListener = null;
+ StateListenerKK sessionListener = null;
synchronized(mInterfaceLock) {
if (mRemoteDevice == null) return; // Camera already closed
@@ -313,7 +311,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return mCameraId;
}
- @Override
public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
// Treat a null input the same an empty list
if (outputs == null) {
@@ -390,7 +387,11 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
checkIfCameraClosedOrInError();
- // TODO: we must be in UNCONFIGURED mode to begin with, or using another session
+ // Notify current session that it's going away, before starting camera operations
+ // After this call completes, the session is not allowed to call into CameraDeviceImpl
+ if (mCurrentSession != null) {
+ mCurrentSession.replaceSessionClose();
+ }
// TODO: dont block for this
boolean configureSuccess = true;
@@ -410,10 +411,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
new CameraCaptureSessionImpl(outputs, listener, handler, this, mDeviceHandler,
configureSuccess);
- if (mCurrentSession != null) {
- mCurrentSession.replaceSessionClose(newSession);
- }
-
// TODO: wait until current session closes, then create the new session
mCurrentSession = newSession;
@@ -425,6 +422,15 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
+ /**
+ * For use by backwards-compatibility code only.
+ */
+ public void setSessionListener(StateListenerKK sessionListener) {
+ synchronized(mInterfaceLock) {
+ mSessionStateListener = sessionListener;
+ }
+ }
+
@Override
public CaptureRequest.Builder createCaptureRequest(int templateType)
throws CameraAccessException {
@@ -449,7 +455,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
- @Override
public int capture(CaptureRequest request, CaptureListener listener, Handler handler)
throws CameraAccessException {
if (DEBUG) {
@@ -460,7 +465,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return submitCaptureRequest(requestList, listener, handler, /*streaming*/false);
}
- @Override
public int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Handler handler) throws CameraAccessException {
if (requests == null || requests.isEmpty()) {
@@ -543,9 +547,7 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
// Need a valid handler, or current thread needs to have a looper, if
// listener is valid
- if (listener != null) {
- handler = checkHandler(handler);
- }
+ handler = checkHandler(handler, listener);
// Make sure that there all requests have at least 1 surface; all surfaces are non-null
for (CaptureRequest request : requestList) {
@@ -613,7 +615,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
- @Override
public int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Handler handler) throws CameraAccessException {
List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
@@ -621,7 +622,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return submitCaptureRequest(requestList, listener, handler, /*streaming*/true);
}
- @Override
public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
Handler handler) throws CameraAccessException {
if (requests == null || requests.isEmpty()) {
@@ -630,7 +630,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return submitCaptureRequest(requests, listener, handler, /*streaming*/true);
}
- @Override
public void stopRepeating() throws CameraAccessException {
synchronized(mInterfaceLock) {
@@ -681,7 +680,6 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
- @Override
public void flush() throws CameraAccessException {
synchronized(mInterfaceLock) {
checkIfCameraClosedOrInError();
@@ -739,6 +737,133 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
}
}
+ /**
+ * <p>A listener for tracking the progress of a {@link CaptureRequest}
+ * submitted to the camera device.</p>
+ *
+ */
+ public static abstract class CaptureListener {
+
+ /**
+ * This constant is used to indicate that no images were captured for
+ * the request.
+ *
+ * @hide
+ */
+ public static final int NO_FRAMES_CAPTURED = -1;
+
+ /**
+ * This method is called when the camera device has started capturing
+ * the output image for the request, at the beginning of image exposure.
+ *
+ * @see android.media.MediaActionSound
+ */
+ public void onCaptureStarted(CameraDevice camera,
+ CaptureRequest request, long timestamp) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called when some results from an image capture are
+ * available.
+ *
+ * @hide
+ */
+ public void onCapturePartial(CameraDevice camera,
+ CaptureRequest request, CaptureResult result) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called when an image capture makes partial forward progress; some
+ * (but not all) results from an image capture are available.
+ *
+ */
+ public void onCaptureProgressed(CameraDevice camera,
+ CaptureRequest request, CaptureResult partialResult) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called when an image capture has fully completed and all the
+ * result metadata is available.
+ */
+ public void onCaptureCompleted(CameraDevice camera,
+ CaptureRequest request, TotalCaptureResult result) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called instead of {@link #onCaptureCompleted} when the
+ * camera device failed to produce a {@link CaptureResult} for the
+ * request.
+ */
+ public void onCaptureFailed(CameraDevice camera,
+ CaptureRequest request, CaptureFailure failure) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called independently of the others in CaptureListener,
+ * when a capture sequence finishes and all {@link CaptureResult}
+ * or {@link CaptureFailure} for it have been returned via this listener.
+ */
+ public void onCaptureSequenceCompleted(CameraDevice camera,
+ int sequenceId, long frameNumber) {
+ // default empty implementation
+ }
+
+ /**
+ * This method is called independently of the others in CaptureListener,
+ * when a capture sequence aborts before any {@link CaptureResult}
+ * or {@link CaptureFailure} for it have been returned via this listener.
+ */
+ public void onCaptureSequenceAborted(CameraDevice camera,
+ int sequenceId) {
+ // default empty implementation
+ }
+ }
+
+ /**
+ * A listener for notifications about the state of a camera device, adding in the callbacks that
+ * were part of the earlier KK API design, but now only used internally.
+ */
+ public static abstract class StateListenerKK extends StateListener {
+ /**
+ * The method called when a camera device has no outputs configured.
+ *
+ */
+ public void onUnconfigured(CameraDevice camera) {
+ // Default empty implementation
+ }
+
+ /**
+ * The method called when a camera device begins processing
+ * {@link CaptureRequest capture requests}.
+ *
+ */
+ public void onActive(CameraDevice camera) {
+ // Default empty implementation
+ }
+
+ /**
+ * The method called when a camera device is busy.
+ *
+ */
+ public void onBusy(CameraDevice camera) {
+ // Default empty implementation
+ }
+
+ /**
+ * The method called when a camera device has finished processing all
+ * submitted capture requests and has reached an idle state.
+ *
+ */
+ public void onIdle(CameraDevice camera) {
+ // Default empty implementation
+ }
+ }
+
static class CaptureListenerHolder {
private final boolean mRepeating;
@@ -1155,6 +1280,18 @@ public class CameraDeviceImpl extends android.hardware.camera2.CameraDevice {
return handler;
}
+ /**
+ * Default handler management, conditional on there being a listener.
+ *
+ * <p>If the listener isn't null, check the handler, otherwise pass it through.</p>
+ */
+ static <T> Handler checkHandler(Handler handler, T listener) {
+ if (listener != null) {
+ return checkHandler(handler);
+ }
+ return handler;
+ }
+
private void checkIfCameraClosedOrInError() throws CameraAccessException {
if (mInError) {
throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index dc71a060f91e..febb015a7fd0 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -67,6 +67,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
/**
* Implementation of camera metadata marshal/unmarshal across Binder to
@@ -227,6 +228,7 @@ public class CameraMetadataNative implements Parcelable {
private static final String CELLID_PROCESS = "CELLID";
private static final String GPS_PROCESS = "GPS";
+ private static final int FACE_LANDMARK_SIZE = 6;
private static String translateLocationProviderToProcess(final String provider) {
if (provider == null) {
@@ -347,7 +349,7 @@ public class CameraMetadataNative implements Parcelable {
// Check if key has been overridden to use a wrapper class on the java side.
GetCommand g = sGetCommandMap.get(key);
if (g != null) {
- return (T) g.getValue(this, key);
+ return g.getValue(this, key);
}
return getBase(key);
}
@@ -587,9 +589,71 @@ public class CameraMetadataNative implements Parcelable {
return availableFormats;
}
- private Face[] getFaces() {
- final int FACE_LANDMARK_SIZE = 6;
+ private boolean setFaces(Face[] faces) {
+ if (faces == null) {
+ return false;
+ }
+
+ int numFaces = faces.length;
+
+ // Detect if all faces are SIMPLE or not; count # of valid faces
+ boolean fullMode = true;
+ for (Face face : faces) {
+ if (face == null) {
+ numFaces--;
+ Log.w(TAG, "setFaces - null face detected, skipping");
+ continue;
+ }
+
+ if (face.getId() == Face.ID_UNSUPPORTED) {
+ fullMode = false;
+ }
+ }
+
+ Rect[] faceRectangles = new Rect[numFaces];
+ byte[] faceScores = new byte[numFaces];
+ int[] faceIds = null;
+ int[] faceLandmarks = null;
+
+ if (fullMode) {
+ faceIds = new int[numFaces];
+ faceLandmarks = new int[numFaces * FACE_LANDMARK_SIZE];
+ }
+
+ int i = 0;
+ for (Face face : faces) {
+ if (face == null) {
+ continue;
+ }
+
+ faceRectangles[i] = face.getBounds();
+ faceScores[i] = (byte)face.getScore();
+
+ if (fullMode) {
+ faceIds[i] = face.getId();
+ int j = 0;
+
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().x;
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getLeftEyePosition().y;
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().x;
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getRightEyePosition().y;
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().x;
+ faceLandmarks[i * FACE_LANDMARK_SIZE + j++] = face.getMouthPosition().y;
+ }
+
+ i++;
+ }
+
+ set(CaptureResult.STATISTICS_FACE_RECTANGLES, faceRectangles);
+ set(CaptureResult.STATISTICS_FACE_IDS, faceIds);
+ set(CaptureResult.STATISTICS_FACE_LANDMARKS, faceLandmarks);
+ set(CaptureResult.STATISTICS_FACE_SCORES, faceScores);
+
+ return true;
+ }
+
+ private Face[] getFaces() {
Integer faceDetectMode = get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
if (faceDetectMode == null) {
Log.w(TAG, "Face detect mode metadata is null, assuming the mode is SIMPLE");
@@ -653,9 +717,12 @@ public class CameraMetadataNative implements Parcelable {
if (faceScores[i] <= Face.SCORE_MAX &&
faceScores[i] >= Face.SCORE_MIN &&
faceIds[i] >= 0) {
- Point leftEye = new Point(faceLandmarks[i*6], faceLandmarks[i*6+1]);
- Point rightEye = new Point(faceLandmarks[i*6+2], faceLandmarks[i*6+3]);
- Point mouth = new Point(faceLandmarks[i*6+4], faceLandmarks[i*6+5]);
+ Point leftEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE],
+ faceLandmarks[i*FACE_LANDMARK_SIZE+1]);
+ Point rightEye = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+2],
+ faceLandmarks[i*FACE_LANDMARK_SIZE+3]);
+ Point mouth = new Point(faceLandmarks[i*FACE_LANDMARK_SIZE+4],
+ faceLandmarks[i*FACE_LANDMARK_SIZE+5]);
Face face = new Face(faceRectangles[i], faceScores[i], faceIds[i],
leftEye, rightEye, mouth);
faceList.add(face);
@@ -865,6 +932,13 @@ public class CameraMetadataNative implements Parcelable {
metadata.setFaceRectangles((Rect[]) value);
}
});
+ sSetCommandMap.put(CaptureResult.STATISTICS_FACES.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setFaces((Face[])value);
+ }
+ });
sSetCommandMap.put(CaptureRequest.TONEMAP_CURVE.getNativeKey(), new SetCommand() {
@Override
public <T> void setValue(CameraMetadataNative metadata, T value) {
diff --git a/core/java/android/hardware/camera2/impl/ListenerProxies.java b/core/java/android/hardware/camera2/impl/ListenerProxies.java
index ab9a4d5c6292..f44f9ada5249 100644
--- a/core/java/android/hardware/camera2/impl/ListenerProxies.java
+++ b/core/java/android/hardware/camera2/impl/ListenerProxies.java
@@ -36,13 +36,13 @@ public class ListenerProxies {
// TODO: replace with codegen
- public static class DeviceStateListenerProxy extends CameraDevice.StateListener {
- private final MethodNameInvoker<CameraDevice.StateListener> mProxy;
+ public static class DeviceStateListenerProxy extends CameraDeviceImpl.StateListenerKK {
+ private final MethodNameInvoker<CameraDeviceImpl.StateListenerKK> mProxy;
public DeviceStateListenerProxy(
- Dispatchable<CameraDevice.StateListener> dispatchTarget) {
+ Dispatchable<CameraDeviceImpl.StateListenerKK> dispatchTarget) {
dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDevice.StateListener.class);
+ mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.StateListenerKK.class);
}
@Override
@@ -87,13 +87,13 @@ public class ListenerProxies {
}
@SuppressWarnings("deprecation")
- public static class DeviceCaptureListenerProxy extends CameraDevice.CaptureListener {
- private final MethodNameInvoker<CameraDevice.CaptureListener> mProxy;
+ public static class DeviceCaptureListenerProxy extends CameraDeviceImpl.CaptureListener {
+ private final MethodNameInvoker<CameraDeviceImpl.CaptureListener> mProxy;
public DeviceCaptureListenerProxy(
- Dispatchable<CameraDevice.CaptureListener> dispatchTarget) {
+ Dispatchable<CameraDeviceImpl.CaptureListener> dispatchTarget) {
dispatchTarget = checkNotNull(dispatchTarget, "dispatchTarget must not be null");
- mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDevice.CaptureListener.class);
+ mProxy = new MethodNameInvoker<>(dispatchTarget, CameraDeviceImpl.CaptureListener.class);
}
@Override
diff --git a/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java
new file mode 100644
index 000000000000..1470b70b4234
--- /dev/null
+++ b/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2014 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 android.hardware.camera2.legacy;
+
+import android.graphics.Rect;
+import android.hardware.Camera;
+import android.hardware.Camera.FaceDetectionListener;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.legacy.ParameterUtils.ZoomData;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.params.Face;
+import android.hardware.camera2.utils.ListUtils;
+import android.hardware.camera2.utils.ParamsUtils;
+import android.util.Log;
+import android.util.Size;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static android.hardware.camera2.CaptureRequest.*;
+import static com.android.internal.util.Preconditions.*;
+
+/**
+ * Map legacy face detect callbacks into face detection results.
+ */
+@SuppressWarnings("deprecation")
+public class LegacyFaceDetectMapper {
+ private static String TAG = "LegacyFaceDetectMapper";
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+ private final Camera mCamera;
+ private final boolean mFaceDetectSupported;
+ private boolean mFaceDetectEnabled = false;
+
+ private final Object mLock = new Object();
+ private Camera.Face[] mFaces;
+ private Camera.Face[] mFacesPrev;
+ /**
+ * Instantiate a new face detect mapper.
+ *
+ * @param camera a non-{@code null} camera1 device
+ * @param characteristics a non-{@code null} camera characteristics for that camera1
+ *
+ * @throws NullPointerException if any of the args were {@code null}
+ */
+ public LegacyFaceDetectMapper(Camera camera, CameraCharacteristics characteristics) {
+ mCamera = checkNotNull(camera, "camera must not be null");
+ checkNotNull(characteristics, "characteristics must not be null");
+
+ mFaceDetectSupported = ArrayUtils.contains(
+ characteristics.get(
+ CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES),
+ STATISTICS_FACE_DETECT_MODE_SIMPLE);
+
+ if (!mFaceDetectSupported) {
+ return;
+ }
+
+ mCamera.setFaceDetectionListener(new FaceDetectionListener() {
+
+ @Override
+ public void onFaceDetection(Camera.Face[] faces, Camera camera) {
+ int lengthFaces = faces == null ? 0 : faces.length;
+ synchronized (mLock) {
+ if (mFaceDetectEnabled) {
+ mFaces = faces;
+ } else if (lengthFaces > 0) {
+ // stopFaceDetectMode could race against the requests, print a debug log
+ Log.d(TAG,
+ "onFaceDetection - Ignored some incoming faces since" +
+ "face detection was disabled");
+ }
+ }
+
+ if (VERBOSE) {
+ Log.v(TAG, "onFaceDetection - read " + lengthFaces + " faces");
+ }
+ }
+ });
+ }
+
+ /**
+ * Process the face detect mode from the capture request into an api1 face detect toggle.
+ *
+ * <p>This method should be called after the parameters are {@link LegacyRequestMapper mapped}
+ * with the request.</p>
+ *
+ * <p>Callbacks are processed in the background, and the next call to {@link #mapResultTriggers}
+ * will have the latest faces detected as reflected by the camera1 callbacks.</p>
+ *
+ * <p>None of the arguments will be mutated.</p>
+ *
+ * @param captureRequest a non-{@code null} request
+ * @param parameters a non-{@code null} parameters corresponding to this request (read-only)
+ */
+ public void processFaceDetectMode(CaptureRequest captureRequest,
+ Camera.Parameters parameters) {
+ checkNotNull(captureRequest, "captureRequest must not be null");
+
+ /*
+ * statistics.faceDetectMode
+ */
+ int fdMode = ParamsUtils.getOrDefault(captureRequest, STATISTICS_FACE_DETECT_MODE,
+ STATISTICS_FACE_DETECT_MODE_OFF);
+
+ if (fdMode != STATISTICS_FACE_DETECT_MODE_OFF && !mFaceDetectSupported) {
+ Log.w(TAG,
+ "processFaceDetectMode - Ignoring statistics.faceDetectMode; " +
+ "face detection is not available");
+ return;
+ }
+
+ // Print some warnings out in case the values were wrong
+ switch (fdMode) {
+ case STATISTICS_FACE_DETECT_MODE_OFF:
+ case STATISTICS_FACE_DETECT_MODE_SIMPLE:
+ break;
+ case STATISTICS_FACE_DETECT_MODE_FULL:
+ Log.w(TAG,
+ "processFaceDetectMode - statistics.faceDetectMode == FULL unsupported, " +
+ "downgrading to SIMPLE");
+ break;
+ default:
+ Log.w(TAG, "processFaceDetectMode - ignoring unknown statistics.faceDetectMode = "
+ + fdMode);
+ return;
+ }
+
+ boolean enableFaceDetect = fdMode != STATISTICS_FACE_DETECT_MODE_OFF;
+ synchronized (mLock) {
+ // Enable/disable face detection if it's changed since last time
+ if (enableFaceDetect != mFaceDetectEnabled) {
+ if (enableFaceDetect) {
+ mCamera.startFaceDetection();
+
+ if (VERBOSE) {
+ Log.v(TAG, "processFaceDetectMode - start face detection");
+ }
+ } else {
+ mCamera.stopFaceDetection();
+
+ if (VERBOSE) {
+ Log.v(TAG, "processFaceDetectMode - stop face detection");
+ }
+
+ mFaces = null;
+ }
+
+ mFaceDetectEnabled = enableFaceDetect;
+ }
+ }
+ }
+
+ /**
+ * Update the {@code result} camera metadata map with the new value for the
+ * {@code statistics.faces} and {@code statistics.faceDetectMode}.
+ *
+ * <p>Face detect callbacks are processed in the background, and each call to
+ * {@link #mapResultFaces} will have the latest faces as reflected by the camera1 callbacks.</p>
+ *
+ * @param result a non-{@code null} result
+ * @param legacyRequest a non-{@code null} request (read-only)
+ */
+ public void mapResultFaces(CameraMetadataNative result, LegacyRequest legacyRequest) {
+ checkNotNull(result, "result must not be null");
+ checkNotNull(legacyRequest, "legacyRequest must not be null");
+
+ Camera.Face[] faces, previousFaces;
+ int fdMode;
+ synchronized (mLock) {
+ fdMode = mFaceDetectEnabled ?
+ STATISTICS_FACE_DETECT_MODE_SIMPLE : STATISTICS_FACE_DETECT_MODE_OFF;
+
+ if (mFaceDetectEnabled) {
+ faces = mFaces;
+ } else {
+ faces = null;
+ }
+
+ previousFaces = mFacesPrev;
+ mFacesPrev = faces;
+ }
+
+ CameraCharacteristics characteristics = legacyRequest.characteristics;
+ CaptureRequest request = legacyRequest.captureRequest;
+ Size previewSize = legacyRequest.previewSize;
+ Camera.Parameters params = legacyRequest.parameters;
+
+ Rect activeArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ ZoomData zoomData = ParameterUtils.convertScalerCropRegion(activeArray,
+ request.get(CaptureRequest.SCALER_CROP_REGION), previewSize, params);
+
+ List<Face> convertedFaces = new ArrayList<>();
+ if (faces != null) {
+ for (Camera.Face face : faces) {
+ if (face != null) {
+ convertedFaces.add(
+ ParameterUtils.convertFaceFromLegacy(face, activeArray, zoomData));
+ } else {
+ Log.w(TAG, "mapResultFaces - read NULL face from camera1 device");
+ }
+ }
+ }
+
+ if (VERBOSE && previousFaces != faces) { // Log only in verbose and IF the faces changed
+ Log.v(TAG, "mapResultFaces - changed to " + ListUtils.listToString(convertedFaces));
+ }
+
+ result.set(CaptureResult.STATISTICS_FACES, convertedFaces.toArray(new Face[0]));
+ result.set(CaptureResult.STATISTICS_FACE_DETECT_MODE, fdMode);
+ }
+}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
index e576b43da154..d0a3a3fd3e68 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
@@ -247,7 +247,8 @@ public class LegacyFocusStateMapper {
// No action necessary. The callbacks will handle transitions.
break;
default:
- Log.w(TAG, "mapTriggers - ignoring unknown control.afTrigger = " + afTrigger);
+ Log.w(TAG, "processRequestTriggers - ignoring unknown control.afTrigger = "
+ + afTrigger);
}
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 711edf4762e7..b05508b25824 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -204,6 +204,11 @@ public class LegacyMetadataMapper {
mapSensor(m, p);
/*
+ * statistics.*
+ */
+ mapStatistics(m, p);
+
+ /*
* sync.*
*/
mapSync(m, p);
@@ -487,6 +492,18 @@ public class LegacyMetadataMapper {
private static void mapControlOther(CameraMetadataNative m, Camera.Parameters p) {
/*
+ * android.control.availableVideoStabilizationModes
+ */
+ {
+ int stabModes[] = p.isVideoStabilizationSupported() ?
+ new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+ CONTROL_VIDEO_STABILIZATION_MODE_ON } :
+ new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF };
+
+ m.set(CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, stabModes);
+ }
+
+ /*
* android.control.maxRegions
*/
final int AE = 0, AWB = 1, AF = 2;
@@ -742,6 +759,31 @@ public class LegacyMetadataMapper {
m.set(SENSOR_INFO_PIXEL_ARRAY_SIZE, largestJpegSize);
}
+ private static void mapStatistics(CameraMetadataNative m, Parameters p) {
+ /*
+ * statistics.info.availableFaceDetectModes
+ */
+ int[] fdModes;
+
+ if (p.getMaxNumDetectedFaces() > 0) {
+ fdModes = new int[] {
+ STATISTICS_FACE_DETECT_MODE_OFF,
+ STATISTICS_FACE_DETECT_MODE_SIMPLE
+ // FULL is never-listed, since we have no way to query it statically
+ };
+ } else {
+ fdModes = new int[] {
+ STATISTICS_FACE_DETECT_MODE_OFF
+ };
+ }
+ m.set(STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, fdModes);
+
+ /*
+ * statistics.info.maxFaceCount
+ */
+ m.set(STATISTICS_INFO_MAX_FACE_COUNT, p.getMaxNumDetectedFaces());
+ }
+
private static void mapSync(CameraMetadataNative m, Parameters p) {
/*
* sync.maxLatency
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
index a6fe035ca144..20f3fd2f7b5b 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
@@ -150,10 +150,8 @@ public class LegacyRequestMapper {
if (supported) {
params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
- params.setRecordingHint(false);
} else {
Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]");
- params.setRecordingHint(true);
}
}
@@ -248,6 +246,18 @@ public class LegacyRequestMapper {
// TODO: Don't add control.awbLock to availableRequestKeys if it's not supported
}
+ // control.videoStabilizationMode
+ {
+ Integer stabMode = getIfSupported(request, CONTROL_VIDEO_STABILIZATION_MODE,
+ /*defaultValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+ params.isVideoStabilizationSupported(),
+ /*allowedValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF);
+
+ if (stabMode != null) {
+ params.setVideoStabilization(stabMode == CONTROL_VIDEO_STABILIZATION_MODE_ON);
+ }
+ }
+
// lens.focusDistance
{
boolean infinityFocusSupported =
diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
index 9eff943ac268..a2487f4bd9b8 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
@@ -35,6 +35,9 @@ import java.util.ArrayList;
import java.util.List;
import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON;
+import static android.hardware.camera2.CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE;
import static android.hardware.camera2.CaptureResult.*;
/**
@@ -142,7 +145,6 @@ public class LegacyResultMapper {
*/
mapAwb(result, /*out*/params);
-
/*
* control.mode
*/
@@ -171,7 +173,6 @@ public class LegacyResultMapper {
}
}
-
/*
* control.effectMode
*/
@@ -187,6 +188,15 @@ public class LegacyResultMapper {
}
}
+ // control.videoStabilizationMode
+ {
+ int stabMode =
+ (params.isVideoStabilizationSupported() && params.getVideoStabilization()) ?
+ CONTROL_VIDEO_STABILIZATION_MODE_ON :
+ CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+ result.set(CONTROL_VIDEO_STABILIZATION_MODE, stabMode);
+ }
+
/*
* flash
*/
diff --git a/core/java/android/hardware/camera2/legacy/ParameterUtils.java b/core/java/android/hardware/camera2/legacy/ParameterUtils.java
index efd12f289626..385f8440afb2 100644
--- a/core/java/android/hardware/camera2/legacy/ParameterUtils.java
+++ b/core/java/android/hardware/camera2/legacy/ParameterUtils.java
@@ -43,6 +43,7 @@ import static com.android.internal.util.Preconditions.*;
/**
* Various utilities for dealing with camera API1 parameters.
*/
+@SuppressWarnings("deprecation")
public class ParameterUtils {
/** Upper/left minimal point of a normalized rectangle */
public static final int NORMALIZED_RECTANGLE_MIN = -1000;
@@ -164,19 +165,23 @@ public class ParameterUtils {
* <p>If the score is out of range of {@value Face#SCORE_MIN}, {@value Face#SCORE_MAX},
* the score is clipped first and a warning is printed to logcat.</p>
*
+ * <p>If the id is negative, the id is changed to 0 and a warning is printed to
+ * logcat.</p>
+ *
* <p>All other parameters are passed-through as-is.</p>
*
* @return a new face with the optional features set
*/
public Face toFace(
int id, Point leftEyePosition, Point rightEyePosition, Point mouthPosition) {
+ int idSafe = clipLower(id, /*lo*/0, rect, "id");
int score = clip(weight,
Face.SCORE_MIN,
Face.SCORE_MAX,
rect,
"score");
- return new Face(rect, score, id, leftEyePosition, rightEyePosition, mouthPosition);
+ return new Face(rect, score, idSafe, leftEyePosition, rightEyePosition, mouthPosition);
}
/**
@@ -861,6 +866,61 @@ public class ParameterUtils {
/*usePreviewCrop*/true);
}
+ /**
+ * Convert an api1 face into an active-array based api2 face.
+ *
+ * <p>Out-of-ranges scores and ids will be clipped to be within range (with a warning).</p>
+ *
+ * @param face a non-{@code null} api1 face
+ * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
+ * @param zoomData the calculated zoom data corresponding to this request
+ *
+ * @return a non-{@code null} api2 face
+ *
+ * @throws NullPointerException if the {@code face} was {@code null}
+ */
+ public static Face convertFaceFromLegacy(Camera.Face face, Rect activeArray,
+ ZoomData zoomData) {
+ checkNotNull(face, "face must not be null");
+
+ Face api2Face;
+
+ Camera.Area fakeArea = new Camera.Area(face.rect, /*weight*/1);
+
+ WeightedRectangle faceRect =
+ convertCameraAreaToActiveArrayRectangle(activeArray, zoomData, fakeArea);
+
+ Point leftEye = face.leftEye, rightEye = face.rightEye, mouth = face.mouth;
+ if (leftEye != null && rightEye != null && mouth != null) {
+ leftEye = convertCameraPointToActiveArrayPoint(activeArray, zoomData,
+ leftEye, /*usePreviewCrop*/true);
+ rightEye = convertCameraPointToActiveArrayPoint(activeArray, zoomData,
+ leftEye, /*usePreviewCrop*/true);
+ mouth = convertCameraPointToActiveArrayPoint(activeArray, zoomData,
+ leftEye, /*usePreviewCrop*/true);
+
+ api2Face = faceRect.toFace(face.id, leftEye, rightEye, mouth);
+ } else {
+ api2Face = faceRect.toFace();
+ }
+
+ return api2Face;
+ }
+
+ private static Point convertCameraPointToActiveArrayPoint(
+ Rect activeArray, ZoomData zoomData, Point point, boolean usePreviewCrop) {
+ Rect pointedRect = new Rect(point.x, point.y, point.x, point.y);
+ Camera.Area pointedArea = new Area(pointedRect, /*weight*/1);
+
+ WeightedRectangle adjustedRect =
+ convertCameraAreaToActiveArrayRectangle(activeArray,
+ zoomData, pointedArea, usePreviewCrop);
+
+ Point transformedPoint = new Point(adjustedRect.rect.left, adjustedRect.rect.top);
+
+ return transformedPoint;
+ }
+
private static WeightedRectangle convertCameraAreaToActiveArrayRectangle(
Rect activeArray, ZoomData zoomData, Camera.Area area, boolean usePreviewCrop) {
Rect previewCrop = zoomData.previewCrop;
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index c556c3286ae8..ec233da79db2 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -39,7 +39,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import static com.android.internal.util.Preconditions.*;
@@ -55,18 +54,23 @@ import static com.android.internal.util.Preconditions.*;
* - An {@link CameraDeviceState} state machine that manages the callbacks for various operations.
* </p>
*/
+@SuppressWarnings("deprecation")
public class RequestThreadManager {
private final String TAG;
private final int mCameraId;
private final RequestHandlerThread mRequestThread;
private static final boolean DEBUG = Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.DEBUG);
+ // For slightly more spammy messages that will get repeated every frame
+ private static final boolean VERBOSE =
+ Log.isLoggable(LegacyCameraDevice.DEBUG_PROP, Log.VERBOSE);
private final Camera mCamera;
private final CameraCharacteristics mCharacteristics;
private final CameraDeviceState mDeviceState;
private final CaptureCollector mCaptureCollector;
private final LegacyFocusStateMapper mFocusStateMapper;
+ private final LegacyFaceDetectMapper mFaceDetectMapper;
private static final int MSG_CONFIGURE_OUTPUTS = 1;
private static final int MSG_SUBMIT_CAPTURE_REQUEST = 2;
@@ -219,6 +223,9 @@ public class RequestThreadManager {
};
private void stopPreview() {
+ if (VERBOSE) {
+ Log.v(TAG, "stopPreview - preview running? " + mPreviewRunning);
+ }
if (mPreviewRunning) {
mCamera.stopPreview();
mPreviewRunning = false;
@@ -226,14 +233,18 @@ public class RequestThreadManager {
}
private void startPreview() {
+ if (VERBOSE) {
+ Log.v(TAG, "startPreview - preview running? " + mPreviewRunning);
+ }
if (!mPreviewRunning) {
+ // XX: CameraClient:;startPreview is not getting called after a stop
mCamera.startPreview();
mPreviewRunning = true;
}
}
- private void doJpegCapture(RequestHolder request) throws IOException {
- if (DEBUG) Log.d(TAG, "doJpegCapture");
+ private void doJpegCapturePrepare(RequestHolder request) throws IOException {
+ if (DEBUG) Log.d(TAG, "doJpegCapturePrepare - preview running? " + mPreviewRunning);
if (!mPreviewRunning) {
if (DEBUG) Log.d(TAG, "doJpegCapture - create fake surface");
@@ -242,11 +253,20 @@ public class RequestThreadManager {
mCamera.setPreviewTexture(mDummyTexture);
startPreview();
}
+ }
+
+ private void doJpegCapture(RequestHolder request) {
+ if (DEBUG) Log.d(TAG, "doJpegCapturePrepare");
+
mCamera.takePicture(mJpegShutterCallback, /*raw*/null, mJpegCallback);
mPreviewRunning = false;
}
private void doPreviewCapture(RequestHolder request) throws IOException {
+ if (VERBOSE) {
+ Log.v(TAG, "doPreviewCapture - preview running? " + mPreviewRunning);
+ }
+
if (mPreviewRunning) {
return; // Already running
}
@@ -264,7 +284,20 @@ public class RequestThreadManager {
}
private void configureOutputs(Collection<Surface> outputs) throws IOException {
+ if (DEBUG) {
+ String outputsStr = outputs == null ? "null" : (outputs.size() + " surfaces");
+
+ Log.d(TAG, "configureOutputs with " + outputsStr);
+ }
+
stopPreview();
+ /*
+ * Try to release the previous preview's surface texture earlier if we end up
+ * using a different one; this also reduces the likelihood of getting into a deadlock
+ * when disconnecting from the old previous texture at a later time.
+ */
+ mCamera.setPreviewTexture(/*surfaceTexture*/null);
+
if (mGLThreadManager != null) {
mGLThreadManager.waitUntilStarted();
mGLThreadManager.ignoreNewFrames();
@@ -305,7 +338,6 @@ public class RequestThreadManager {
}
mParams.setPreviewFpsRange(bestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
bestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
- mParams.setRecordingHint(true);
if (mPreviewOutputs.size() > 0) {
List<Size> outputSizes = new ArrayList<>(outputs.size());
@@ -575,7 +607,6 @@ public class RequestThreadManager {
Log.e(TAG, "Interrupted while waiting for requests to complete.");
}
mDeviceState.setIdle();
- stopPreview();
break;
} else {
// Queue another capture if we did not get the last burst.
@@ -613,10 +644,6 @@ public class RequestThreadManager {
}
}
- // Unconditionally process AF triggers, since they're non-idempotent
- // - must be done after setting the most-up-to-date AF mode
- mFocusStateMapper.processRequestTriggers(request, mParams);
-
try {
boolean success = mCaptureCollector.queueRequest(holder,
mLastRequest, JPEG_FRAME_TIMEOUT, TimeUnit.MILLISECONDS);
@@ -624,6 +651,8 @@ public class RequestThreadManager {
if (!success) {
Log.e(TAG, "Timed out while queueing capture request.");
}
+ // Starting the preview needs to happen before enabling
+ // face detection or auto focus
if (holder.hasPreviewTargets()) {
doPreviewCapture(holder);
}
@@ -635,12 +664,33 @@ public class RequestThreadManager {
Log.e(TAG, "Timed out waiting for prior requests to complete.");
}
mReceivedJpeg.close();
+ doJpegCapturePrepare(holder);
+ if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) {
+ // TODO: report error to CameraDevice
+ Log.e(TAG, "Hit timeout for jpeg callback!");
+ }
+ }
+
+ /*
+ * Do all the actions that require a preview to have been started
+ */
+
+ // Toggle face detection on/off
+ // - do this before AF to give AF a chance to use faces
+ mFaceDetectMapper.processFaceDetectMode(request, /*in*/mParams);
+
+ // Unconditionally process AF triggers, since they're non-idempotent
+ // - must be done after setting the most-up-to-date AF mode
+ mFocusStateMapper.processRequestTriggers(request, mParams);
+
+ if (holder.hasJpegTargets()) {
doJpegCapture(holder);
if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) {
// TODO: report error to CameraDevice
Log.e(TAG, "Hit timeout for jpeg callback!");
}
}
+
} catch (IOException e) {
// TODO: report error to CameraDevice
throw new IOError(e);
@@ -677,6 +727,8 @@ public class RequestThreadManager {
mLastRequest, timestampMutable.value);
// Update AF state
mFocusStateMapper.mapResultTriggers(result);
+ // Update detected faces list
+ mFaceDetectMapper.mapResultFaces(result, mLastRequest);
mDeviceState.setCaptureResult(holder, result);
}
@@ -731,6 +783,7 @@ public class RequestThreadManager {
TAG = name;
mDeviceState = checkNotNull(deviceState, "deviceState must not be null");
mFocusStateMapper = new LegacyFocusStateMapper(mCamera);
+ mFaceDetectMapper = new LegacyFaceDetectMapper(mCamera, mCharacteristics);
mCaptureCollector = new CaptureCollector(MAX_IN_FLIGHT_REQUESTS, mDeviceState);
mRequestThread = new RequestHandlerThread(name, mRequestHandlerCb);
}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 1efabb1212bd..2e6b9aefc7d7 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -813,6 +813,7 @@ public final class StreamConfigurationMap {
switch (format) {
case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
case HAL_PIXEL_FORMAT_BLOB:
+ case HAL_PIXEL_FORMAT_RAW_OPAQUE:
return format;
case ImageFormat.JPEG:
throw new IllegalArgumentException(
@@ -843,12 +844,6 @@ public final class StreamConfigurationMap {
* @throws IllegalArgumentException if the format was not user-defined
*/
static int checkArgumentFormat(int format) {
- // TODO: remove this hack , CTS shouldn't have been using internal constants
- if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
- Log.w(TAG, "RAW_OPAQUE is not yet a published format; allowing it anyway");
- return format;
- }
-
if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
throw new IllegalArgumentException(String.format(
"format 0x%x was not defined in either ImageFormat or PixelFormat", format));
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 04e6227ca11e..30875060d35b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -864,15 +864,6 @@ public class UserManager {
}
/**
- * Kept during L development to simplify updating unbundled apps.
- * TODO: Remove after 2014-08-04
- * @hide
- */
- public String getBadgedLabelForUser(String label, UserHandle user) {
- return (String) getBadgedLabelForUser((CharSequence) label, user);
- }
-
- /**
* If the target user is a managed profile of the calling user or the caller
* is itself a managed profile, then this returns a drawable to use as a small
* icon to include in a view to distinguish it from the original icon.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 129476c91050..60ef6936783f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3996,6 +3996,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
return super.onGenericMotionEvent(event);
}
+ /**
+ * Initiate a fling with the given velocity.
+ *
+ * <p>Applications can use this method to manually initiate a fling as if the user
+ * initiated it via touch interaction.</p>
+ *
+ * @param velocityY Vertical velocity in pixels per second
+ */
+ public void fling(int velocityY) {
+ if (mFlingRunnable == null) {
+ mFlingRunnable = new FlingRunnable();
+ }
+ reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
+ mFlingRunnable.start(-velocityY);
+ }
+
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
return ((nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0);
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 59ec6d3da37c..8102c4acf364 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -18,6 +18,7 @@ package android.widget;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Parcel;
@@ -171,7 +172,10 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
/* Get the localized am/pm strings and use them in the spinner */
- mAmPmStrings = new DateFormatSymbols().getAmPmStrings();
+ final Resources res = context.getResources();
+ final String amText = res.getString(R.string.time_picker_am_label);
+ final String pmText = res.getString(R.string.time_picker_pm_label);
+ mAmPmStrings = new String[] {amText, pmText};
// am/pm
View amPmView = mDelegator.findViewById(R.id.amPm);
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 4e9a39fea095..523965c96e9e 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -134,6 +134,8 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
mSelectHours = res.getString(R.string.select_hours);
mMinutePickerDescription = res.getString(R.string.minute_picker_description);
mSelectMinutes = res.getString(R.string.select_minutes);
+ mAmText = res.getString(R.string.time_picker_am_label);
+ mPmText = res.getString(R.string.time_picker_pm_label);
final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
R.layout.time_picker_holo);
@@ -182,10 +184,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
R.id.radial_picker);
mDoneButton = (Button) mainView.findViewById(R.id.done_button);
- String[] amPmTexts = new DateFormatSymbols().getAmPmStrings();
- mAmText = amPmTexts[0];
- mPmText = amPmTexts[1];
-
setupListeners();
mAllowAutoAdvance = true;
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2a7bffd8ea73..bef98d57e133 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4134,6 +4134,10 @@
<string name="time_picker_increment_set_pm_button">Set PM</string>
<!-- Description of the button to decrease the TimePicker's set AM value. [CHAR LIMIT=NONE] -->
<string name="time_picker_decrement_set_am_button">Set AM</string>
+ <!-- Label for the TimePicker's PM button. [CHAR LIMIT=2] -->
+ <string name="time_picker_pm_label">PM</string>
+ <!-- Label for the TimePicker's AM button. [CHAR LIMIT=2] -->
+ <string name="time_picker_am_label">AM</string>
<!-- DatePicker - accessibility support -->
<!-- Description of the button to increase the DatePicker's month value. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 84bc62c9cd3c..603071511e4e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1969,9 +1969,7 @@
<java-symbol type="array" name="config_cdma_home_system" />
<java-symbol type="attr" name="headerSelectedTextColor" />
<java-symbol type="attr" name="amPmSelectedBackgroundColor" />
-
- <!--From SmsMessage-->
- <!--Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet
- string that's stored in 8-bit unpacked format) characters.-->
<java-symbol type="bool" name="config_sms_decode_gsm_8bit_data" />
+ <java-symbol type="string" name="time_picker_am_label" />
+ <java-symbol type="string" name="time_picker_pm_label" />
</resources>
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index 65148bf2d2ff..78946ee9de94 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -225,8 +225,7 @@ com.android.support:gridlayout-v7:18.0.+
<p>This library provides {@link android.support.v7.media.MediaRouter}, {@link
android.support.v7.media.MediaRouteProvider}, and related media classes that
-support the <a href="https://developers.google.com/cast/">Google Cast
-developer preview</a>. </p>
+support <a href="https://developers.google.com/cast/docs/android_sender">Google Cast</a>. </p>
<p>In general, the APIs in the v7 mediarouter library provide a means of
controlling the routing of media channels and streams from the current device to
@@ -258,9 +257,8 @@ com.android.support:mediarouter-v7:18.0.+
<p class="caution">The v7 mediarouter library APIs introduced in Support Library
r18 are subject to change in later revisions of the Support Library. At this
-time, we recommend using the library only in connection with the <a
-href="https://developers.google.com/cast/">Google Cast
-developer preview</a>. </p>
+time, we recommend using the library only in connection with <a
+href="https://developers.google.com/cast/docs/android_sender">Google Cast</a>. </p>
<h2 id="v8">v8 Support Library</h2>
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 6ebb8b558a7f..a6dbcb0df1b2 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -626,13 +626,18 @@ public class NinePatchDrawable extends Drawable {
mAutoMirrored = autoMirror;
// Sanity check for valid padding when we have optical insets.
- if (mPadding.left < mOpticalInsets.left) {
- mPadding.left = mOpticalInsets.left;
- mPadding.right = mOpticalInsets.right;
- }
- if (mPadding.top < mOpticalInsets.top) {
- mPadding.top = mOpticalInsets.top;
- mPadding.bottom = mOpticalInsets.bottom;
+ if (!opticalInsets.isEmpty()) {
+ if (mPadding == null) {
+ mPadding = new Rect();
+ }
+ if (mPadding.left < opticalInsets.left) {
+ mPadding.left = opticalInsets.left;
+ mPadding.right = opticalInsets.right;
+ }
+ if (mPadding.top < opticalInsets.top) {
+ mPadding.top = opticalInsets.top;
+ mPadding.bottom = opticalInsets.bottom;
+ }
}
}
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 6f21f2e00495..be2241bca205 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -276,7 +276,7 @@ class Ripple {
public void getBounds(Rect bounds) {
final int outerX = (int) mOuterX;
final int outerY = (int) mOuterY;
- final int r = (int) mOuterRadius;
+ final int r = (int) mOuterRadius + 1;
bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
}
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index d404ccd8b1f2..93df64874542 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -264,7 +264,7 @@ class RippleBackground {
public void getBounds(Rect bounds) {
final int outerX = (int) mOuterX;
final int outerY = (int) mOuterY;
- final int r = (int) mOuterRadius;
+ final int r = (int) mOuterRadius + 1;
bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
}
diff --git a/media/java/android/media/tv/ITvInputService.aidl b/media/java/android/media/tv/ITvInputService.aidl
index c98a48dafc32..7a853d1caa62 100644
--- a/media/java/android/media/tv/ITvInputService.aidl
+++ b/media/java/android/media/tv/ITvInputService.aidl
@@ -35,6 +35,6 @@ oneway interface ITvInputService {
// For hardware TvInputService
void notifyHardwareAdded(in TvInputHardwareInfo hardwareInfo);
void notifyHardwareRemoved(in TvInputHardwareInfo hardwareInfo);
- void notifyHdmiCecDeviceAdded(in HdmiDeviceInfo deviceInfo);
- void notifyHdmiCecDeviceRemoved(in HdmiDeviceInfo deviceInfo);
+ void notifyHdmiDeviceAdded(in HdmiDeviceInfo deviceInfo);
+ void notifyHdmiDeviceRemoved(in HdmiDeviceInfo deviceInfo);
}
diff --git a/media/java/android/media/tv/ITvInputServiceCallback.aidl b/media/java/android/media/tv/ITvInputServiceCallback.aidl
index df648e737d31..de5d56f85f40 100644
--- a/media/java/android/media/tv/ITvInputServiceCallback.aidl
+++ b/media/java/android/media/tv/ITvInputServiceCallback.aidl
@@ -24,7 +24,7 @@ import android.media.tv.TvInputInfo;
* @hide
*/
oneway interface ITvInputServiceCallback {
- void addHardwareTvInput(in int deviceID, in TvInputInfo inputInfo);
- void addHdmiCecTvInput(in int logicalAddress, in TvInputInfo inputInfo);
+ void addHardwareTvInput(in int deviceId, in TvInputInfo inputInfo);
+ void addHdmiTvInput(in int logicalAddress, in TvInputInfo inputInfo);
void removeTvInput(in String inputId);
}
diff --git a/media/java/android/media/tv/TvContentRating.java b/media/java/android/media/tv/TvContentRating.java
index 2e4d0310ef0e..18136e9e39a5 100644
--- a/media/java/android/media/tv/TvContentRating.java
+++ b/media/java/android/media/tv/TvContentRating.java
@@ -19,7 +19,6 @@ package android.media.tv;
import android.annotation.SystemApi;
import android.net.Uri;
import android.text.TextUtils;
-import android.util.Log;
import java.util.Arrays;
import java.util.Collections;
@@ -963,8 +962,6 @@ import java.util.List;
* </table>
*/
public final class TvContentRating {
- private static final String TAG = "TvContentRating";
-
/** @hide */
public static final Uri SYSTEM_CONTENT_RATING_SYSTEM_XML = Uri.parse(
"android.resource://system/" + com.android.internal.R.xml.tv_content_rating_systems);
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index a826957272fb..ae6f5bc6415f 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -20,7 +20,6 @@ import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
-import android.media.tv.TvContract.Programs;
import android.net.Uri;
import android.provider.BaseColumns;
import android.util.ArraySet;
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 8feb7e6c2386..8d0e986a5b98 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -103,10 +103,10 @@ public final class TvInputInfo implements Parcelable {
private static final String XML_START_TAG_NAME = "tv-input";
private static final String DELIMITER_INFO_IN_ID = "/";
- private static final String PREFIX_CEC_DEVICE = "CEC";
+ private static final String PREFIX_HDMI_DEVICE = "HDMI";
private static final String PREFIX_HARDWARE_DEVICE = "HW";
- private static final int LENGTH_CEC_PHYSICAL_ADDRESS = 4;
- private static final int LENGTH_CEC_LOGICAL_ADDRESS = 2;
+ private static final int LENGTH_HDMI_PHYSICAL_ADDRESS = 4;
+ private static final int LENGTH_HDMI_LOGICAL_ADDRESS = 2;
private final ResolveInfo mService;
private final String mId;
@@ -155,7 +155,7 @@ public final class TvInputInfo implements Parcelable {
* instantiating it from the given Context, ResolveInfo, and HdmiDeviceInfo.
*
* @param service The ResolveInfo returned from the package manager about this TV input service.
- * @param cecInfo The HdmiDeviceInfo for a HDMI CEC logical device.
+ * @param deviceInfo The HdmiDeviceInfo for a HDMI CEC logical device.
* @param parentId The ID of this TV input's parent input. {@code null} if none exists.
* @param iconUri The {@link android.net.Uri} to load the icon image.
* {@see android.content.ContentResolver#openInputStream}. If it is null, the application
@@ -166,12 +166,12 @@ public final class TvInputInfo implements Parcelable {
*/
@SystemApi
public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
- HdmiDeviceInfo cecInfo, String parentId, String label, Uri iconUri)
+ HdmiDeviceInfo deviceInfo, String parentId, String label, Uri iconUri)
throws XmlPullParserException, IOException {
- boolean isConnectedToHdmiSwitch = (cecInfo.getPhysicalAddress() & 0x0FFF) != 0;
- return createTvInputInfo(context, service, generateInputIdForHdmiCec(
+ boolean isConnectedToHdmiSwitch = (deviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
+ return createTvInputInfo(context, service, generateInputIdForHdmiDevice(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
- cecInfo), parentId, TYPE_HDMI, label, iconUri, isConnectedToHdmiSwitch);
+ deviceInfo), parentId, TYPE_HDMI, label, iconUri, isConnectedToHdmiSwitch);
}
/**
@@ -497,16 +497,16 @@ public final class TvInputInfo implements Parcelable {
* Used to generate an input id from a ComponentName and HdmiDeviceInfo.
*
* @param name the component name for generating an input id.
- * @param cecInfo HdmiDeviceInfo describing this TV input.
- * @return the generated input id for the given {@code name} and {@code cecInfo}.
- */
- private static final String generateInputIdForHdmiCec(
- ComponentName name, HdmiDeviceInfo cecInfo) {
- // Example of the format : "/CEC%04X%02X"
- String format = String.format("%s%s%%0%sX%%0%sX", DELIMITER_INFO_IN_ID, PREFIX_CEC_DEVICE,
- LENGTH_CEC_PHYSICAL_ADDRESS, LENGTH_CEC_LOGICAL_ADDRESS);
+ * @param deviceInfo HdmiDeviceInfo describing this TV input.
+ * @return the generated input id for the given {@code name} and {@code deviceInfo}.
+ */
+ private static final String generateInputIdForHdmiDevice(
+ ComponentName name, HdmiDeviceInfo deviceInfo) {
+ // Example of the format : "/HDMI%04X%02X"
+ String format = String.format("%s%s%%0%sX%%0%sX", DELIMITER_INFO_IN_ID, PREFIX_HDMI_DEVICE,
+ LENGTH_HDMI_PHYSICAL_ADDRESS, LENGTH_HDMI_LOGICAL_ADDRESS);
return name.flattenToShortString() + String.format(format,
- cecInfo.getPhysicalAddress(), cecInfo.getLogicalAddress());
+ deviceInfo.getPhysicalAddress(), deviceInfo.getLogicalAddress());
}
/**
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 6a41c61dba18..408ee7bbb750 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -28,7 +28,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -42,7 +41,6 @@ import android.view.InputEventReceiver;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
-import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.CaptioningManager;
@@ -92,7 +90,7 @@ public abstract class TvInputService extends Service {
* Handler instance to handle request from TV Input Manager Service. Should be run in the main
* looper to be synchronously run with {@code Session.mHandler}.
*/
- private Handler mServiceHandler = new ServiceHandler();
+ private final Handler mServiceHandler = new ServiceHandler();
private final RemoteCallbackList<ITvInputServiceCallback> mCallbacks =
new RemoteCallbackList<ITvInputServiceCallback>();
@@ -142,15 +140,15 @@ public abstract class TvInputService extends Service {
}
@Override
- public void notifyHdmiCecDeviceAdded(HdmiDeviceInfo cecDeviceInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_CEC_TV_INPUT,
- cecDeviceInfo).sendToTarget();
+ public void notifyHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
+ mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_TV_INPUT,
+ deviceInfo).sendToTarget();
}
@Override
- public void notifyHdmiCecDeviceRemoved(HdmiDeviceInfo cecDeviceInfo) {
- mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_CEC_TV_INPUT,
- cecDeviceInfo).sendToTarget();
+ public void notifyHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
+ mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HDMI_TV_INPUT,
+ deviceInfo).sendToTarget();
}
};
}
@@ -203,27 +201,27 @@ public abstract class TvInputService extends Service {
/**
* Returns a new {@link TvInputInfo} object if this service is responsible for
- * {@code cecDeviceInfo}; otherwise, return {@code null}. Override to modify default behavior
- * of ignoring all HDMI CEC logical input device.
+ * {@code deviceInfo}; otherwise, return {@code null}. Override to modify default behavior of
+ * ignoring all HDMI logical input device.
*
- * @param cecDeviceInfo {@link HdmiDeviceInfo} object just added.
+ * @param deviceInfo {@link HdmiDeviceInfo} object just added.
* @hide
*/
@SystemApi
- public TvInputInfo onHdmiCecDeviceAdded(HdmiDeviceInfo cecDeviceInfo) {
+ public TvInputInfo onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
return null;
}
/**
- * Returns the input ID for {@code logicalAddress} if it is handled by this service;
- * otherwise, return {@code null}. Override to modify default behavior of ignoring all HDMI CEC
- * logical input device.
+ * Returns the input ID for {@code logicalAddress} if it is handled by this service; otherwise,
+ * return {@code null}. Override to modify default behavior of ignoring all HDMI logical input
+ * device.
*
- * @param cecDeviceInfo {@link HdmiDeviceInfo} object just removed.
+ * @param deviceInfo {@link HdmiDeviceInfo} object just removed.
* @hide
*/
@SystemApi
- public String onHdmiCecDeviceRemoved(HdmiDeviceInfo cecDeviceInfo) {
+ public String onHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
return null;
}
@@ -1164,8 +1162,8 @@ public abstract class TvInputService extends Service {
private static final int DO_NOTIFY_SESSION_CREATED = 2;
private static final int DO_ADD_HARDWARE_TV_INPUT = 3;
private static final int DO_REMOVE_HARDWARE_TV_INPUT = 4;
- private static final int DO_ADD_HDMI_CEC_TV_INPUT = 5;
- private static final int DO_REMOVE_HDMI_CEC_TV_INPUT = 6;
+ private static final int DO_ADD_HDMI_TV_INPUT = 5;
+ private static final int DO_REMOVE_HDMI_TV_INPUT = 6;
private void broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
@@ -1179,12 +1177,11 @@ public abstract class TvInputService extends Service {
mCallbacks.finishBroadcast();
}
- private void broadcastAddHdmiCecTvInput(
- int logicalAddress, TvInputInfo inputInfo) {
+ private void broadcastAddHdmiTvInput(int logicalAddress, TvInputInfo inputInfo) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
- mCallbacks.getBroadcastItem(i).addHdmiCecTvInput(logicalAddress, inputInfo);
+ mCallbacks.getBroadcastItem(i).addHdmiTvInput(logicalAddress, inputInfo);
} catch (RemoteException e) {
Log.e(TAG, "Error while broadcasting.", e);
}
@@ -1286,17 +1283,17 @@ public abstract class TvInputService extends Service {
}
return;
}
- case DO_ADD_HDMI_CEC_TV_INPUT: {
- HdmiDeviceInfo cecDeviceInfo = (HdmiDeviceInfo) msg.obj;
- TvInputInfo inputInfo = onHdmiCecDeviceAdded(cecDeviceInfo);
+ case DO_ADD_HDMI_TV_INPUT: {
+ HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
+ TvInputInfo inputInfo = onHdmiDeviceAdded(deviceInfo);
if (inputInfo != null) {
- broadcastAddHdmiCecTvInput(cecDeviceInfo.getLogicalAddress(), inputInfo);
+ broadcastAddHdmiTvInput(deviceInfo.getLogicalAddress(), inputInfo);
}
return;
}
- case DO_REMOVE_HDMI_CEC_TV_INPUT: {
- HdmiDeviceInfo cecDeviceInfo = (HdmiDeviceInfo) msg.obj;
- String inputId = onHdmiCecDeviceRemoved(cecDeviceInfo);
+ case DO_REMOVE_HDMI_TV_INPUT: {
+ HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
+ String inputId = onHdmiDeviceRemoved(deviceInfo);
if (inputId != null) {
broadcastRemoveTvInput(inputId);
}
diff --git a/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java b/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
index 6bb1f2cd09af..e664fb965ae7 100644
--- a/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
+++ b/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
@@ -26,38 +26,70 @@ import android.view.animation.Interpolator;
*/
public class AppearAnimationUtils implements AppearAnimationCreator<View> {
- public static final long APPEAR_DURATION = 220;
+ public static final long DEFAULT_APPEAR_DURATION = 220;
- private final Interpolator mLinearOutSlowIn;
+ private final Interpolator mInterpolator;
private final float mStartTranslation;
private final AppearAnimationProperties mProperties = new AppearAnimationProperties();
private final float mDelayScale;
+ private final long mDuration;
public AppearAnimationUtils(Context ctx) {
- this(ctx, 1.0f, 1.0f);
+ this(ctx, DEFAULT_APPEAR_DURATION,
+ ctx.getResources().getDimensionPixelSize(R.dimen.appear_y_translation_start),
+ 1.0f,
+ AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in));
}
- public AppearAnimationUtils(Context ctx, float delayScaleFactor,
- float translationScaleFactor) {
- mLinearOutSlowIn = AnimationUtils.loadInterpolator(
- ctx, android.R.interpolator.linear_out_slow_in);
+ public AppearAnimationUtils(Context ctx, long duration, float translationScaleFactor,
+ float delayScaleFactor, Interpolator interpolator) {
+ mInterpolator = interpolator;
mStartTranslation = ctx.getResources().getDimensionPixelOffset(
R.dimen.appear_y_translation_start) * translationScaleFactor;
mDelayScale = delayScaleFactor;
+ mDuration = duration;
}
public void startAppearAnimation(View[][] objects, final Runnable finishListener) {
startAppearAnimation(objects, finishListener, this);
}
+ public void startAppearAnimation(View[] objects, final Runnable finishListener) {
+ startAppearAnimation(objects, finishListener, this);
+ }
+
public <T> void startAppearAnimation(T[][] objects, final Runnable finishListener,
AppearAnimationCreator<T> creator) {
AppearAnimationProperties properties = getDelays(objects);
startAnimations(properties, objects, finishListener, creator);
}
+ public <T> void startAppearAnimation(T[] objects, final Runnable finishListener,
+ AppearAnimationCreator<T> creator) {
+ AppearAnimationProperties properties = getDelays(objects);
+ startAnimations(properties, objects, finishListener, creator);
+ }
+
+ private <T> void startAnimations(AppearAnimationProperties properties, T[] objects,
+ final Runnable finishListener, AppearAnimationCreator<T> creator) {
+ if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) {
+ finishListener.run();
+ return;
+ }
+ for (int row = 0; row < properties.delays.length; row++) {
+ long[] columns = properties.delays[row];
+ long delay = columns[0];
+ Runnable endRunnable = null;
+ if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == 0) {
+ endRunnable = finishListener;
+ }
+ creator.createAnimation(objects[row], delay, mDuration,
+ mStartTranslation, mInterpolator, endRunnable);
+ }
+ }
+
private <T> void startAnimations(AppearAnimationProperties properties, T[][] objects,
- final Runnable finishListener, AppearAnimationCreator creator) {;
+ final Runnable finishListener, AppearAnimationCreator<T> creator) {
if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) {
finishListener.run();
return;
@@ -70,15 +102,32 @@ public class AppearAnimationUtils implements AppearAnimationCreator<View> {
if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == col) {
endRunnable = finishListener;
}
- creator.createAnimation(objects[row][col], delay, APPEAR_DURATION,
- mStartTranslation, mLinearOutSlowIn, endRunnable);
+ creator.createAnimation(objects[row][col], delay, mDuration,
+ mStartTranslation, mInterpolator, endRunnable);
}
}
+ }
+ private <T> AppearAnimationProperties getDelays(T[] items) {
+ long maxDelay = -1;
+ mProperties.maxDelayColIndex = -1;
+ mProperties.maxDelayRowIndex = -1;
+ mProperties.delays = new long[items.length][];
+ for (int row = 0; row < items.length; row++) {
+ mProperties.delays[row] = new long[1];
+ long delay = calculateDelay(row, 0);
+ mProperties.delays[row][0] = delay;
+ if (items[row] != null && delay > maxDelay) {
+ maxDelay = delay;
+ mProperties.maxDelayColIndex = 0;
+ mProperties.maxDelayRowIndex = row;
+ }
+ }
+ return mProperties;
}
private <T> AppearAnimationProperties getDelays(T[][] items) {
- long maxDelay = 0;
+ long maxDelay = -1;
mProperties.maxDelayColIndex = -1;
mProperties.maxDelayRowIndex = -1;
mProperties.delays = new long[items.length][];
@@ -103,7 +152,7 @@ public class AppearAnimationUtils implements AppearAnimationCreator<View> {
}
public Interpolator getInterpolator() {
- return mLinearOutSlowIn;
+ return mInterpolator;
}
public float getStartTranslation() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index d5dcd71030f9..12bbd353198d 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -37,6 +37,7 @@ import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.LinearLayout;
@@ -108,8 +109,10 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
public KeyguardPatternView(Context context, AttributeSet attrs) {
super(context, attrs);
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
- mAppearAnimationUtils = new AppearAnimationUtils(context, 1.5f /* delayScale */,
- 2.0f /* transitionScale */);
+ mAppearAnimationUtils = new AppearAnimationUtils(context,
+ AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 1.5f /* delayScale */,
+ 2.0f /* transitionScale */, AnimationUtils.loadInterpolator(
+ mContext, android.R.interpolator.linear_out_slow_in));
}
public void setKeyguardCallback(KeyguardSecurityCallback callback) {
@@ -420,7 +423,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
this);
if (!TextUtils.isEmpty(mHelpMessage.getText())) {
mAppearAnimationUtils.createAnimation(mHelpMessage, 0,
- AppearAnimationUtils.APPEAR_DURATION,
+ AppearAnimationUtils.DEFAULT_APPEAR_DURATION,
mAppearAnimationUtils.getStartTranslation(),
mAppearAnimationUtils.getInterpolator(),
null /* finishRunnable */);
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher.xml b/packages/SystemUI/res/layout/keyguard_user_switcher.xml
index 5648065b3b0e..7c918c2fa7e7 100644
--- a/packages/SystemUI/res/layout/keyguard_user_switcher.xml
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher.xml
@@ -14,7 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.AlphaOptimizedLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keyguard_user_switcher"
android:orientation="vertical"
android:layout_height="wrap_content"
@@ -22,4 +23,4 @@
android:gravity="end"
android:visibility="gone"
android:paddingTop="4dp">
-</LinearLayout>
+</com.android.systemui.statusbar.AlphaOptimizedLinearLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 97efb474c31a..51633dc8e0b4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -768,13 +768,13 @@
<string name="disconnect_vpn">Disconnect VPN</string>
<!-- Monitoring dialog device owner body text [CHAR LIMIT=300] -->
- <string name="monitoring_description_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator can monitor your network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>
+ <string name="monitoring_description_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator can monitor your device and network activity, including emails, apps and secure websites.\n\nFor more information, contact your administrator.</string>
<!-- Monitoring dialog non-legacy VPN text [CHAR LIMIT=300] -->
- <string name="monitoring_description_vpn">You gave \"<xliff:g id="application">%1$s</xliff:g>\" permission to set up a VPN connection.\n\nThis app can monitor your network activity, including emails, apps and secure websites.</string>
+ <string name="monitoring_description_vpn">You gave \"<xliff:g id="application">%1$s</xliff:g>\" permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and secure websites.</string>
<!-- Monitoring dialog legacy VPN text [CHAR LIMIT=300] -->
- <string name="monitoring_description_legacy_vpn">You\'re connected to a VPN (\"<xliff:g id="application">%1$s</xliff:g>\").\n\nYour VPN service provider can monitor your network activity including emails, apps, and secure websites.</string>
+ <string name="monitoring_description_legacy_vpn">You\'re connected to a VPN (\"<xliff:g id="application">%1$s</xliff:g>\").\n\nYour VPN service provider can monitor your device and network activity including emails, apps, and secure websites.</string>
<!-- Monitoring dialog non-legacy VPN with device owner text [CHAR LIMIT=300] -->
<string name="monitoring_description_vpn_device_owned">This device is managed by:\n<xliff:g id="organization">%1$s</xliff:g>\n\nYour administrator is capable of monitoring your network activity including emails, apps, and secure websites. For more information, contact your administrator.\n\nAlso, you gave \"<xliff:g id="application">%2$s</xliff:g>\" permission to set up a VPN connection. This app can monitor network activity too.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index 759d540feda1..a56b7a72c08e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -116,4 +116,9 @@ public class UserDetailItemView extends LinearLayout {
boolean activated = ArrayUtils.contains(getDrawableState(), android.R.attr.state_activated);
mName.setTypeface(activated ? mActivatedTypeface : mRegularTypeface);
}
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 98bdee0c16ea..2a782cc09935 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -738,12 +738,12 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
}
}
- private void startApplicationDetailsActivity(String packageName) {
+ private void startApplicationDetailsActivity(String packageName, int userId) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null));
intent.setComponent(intent.resolveActivity(getContext().getPackageManager()));
TaskStackBuilder.create(getContext())
- .addNextIntentWithParentStack(intent).startActivities();
+ .addNextIntentWithParentStack(intent).startActivities(null, new UserHandle(userId));
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
@@ -769,7 +769,7 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
if (viewHolder != null) {
final TaskDescription ad = viewHolder.taskDescription;
- startApplicationDetailsActivity(ad.packageName);
+ startApplicationDetailsActivity(ad.packageName, ad.userId);
show(false);
} else {
throw new IllegalStateException("Oops, no tag on view " + selectedView);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 1a32b81c767e..58d5df77c59e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -26,6 +26,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.net.Uri;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -474,7 +475,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
Uri.fromParts("package", baseIntent.getComponent().getPackageName(), null));
intent.setComponent(intent.resolveActivity(getContext().getPackageManager()));
TaskStackBuilder.create(getContext())
- .addNextIntentWithParentStack(intent).startActivities();
+ .addNextIntentWithParentStack(intent).startActivities(null,
+ new UserHandle(t.userId));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 899619761940..3b1408234887 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -82,6 +82,7 @@ public class KeyguardBouncer {
public void hide(boolean destroyView) {
if (mKeyguardView != null) {
+ mKeyguardView.setOnDismissAction(null);
mKeyguardView.cleanUp();
}
if (destroyView) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index bf66c4104033..b66c3101304f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -16,10 +16,14 @@
package com.android.systemui.statusbar.phone;
+import android.animation.LayoutTransition;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -48,6 +52,7 @@ public class KeyguardStatusBarView extends RelativeLayout
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private int mSystemIconsSwitcherHiddenExpandedMargin;
+ private Interpolator mFastOutSlowInInterpolator;
public KeyguardStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -61,6 +66,8 @@ public class KeyguardStatusBarView extends RelativeLayout
mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar);
mBatteryLevel = (TextView) findViewById(R.id.battery_level);
loadDimens();
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+ android.R.interpolator.fast_out_slow_in);
updateUserSwitcher();
}
@@ -70,7 +77,14 @@ public class KeyguardStatusBarView extends RelativeLayout
}
private void updateVisibilities() {
- mMultiUserSwitch.setVisibility(!mKeyguardUserSwitcherShowing ? VISIBLE : GONE);
+ if (mMultiUserSwitch.getParent() != this && !mKeyguardUserSwitcherShowing) {
+ if (mMultiUserSwitch.getParent() != null) {
+ getOverlay().remove(mMultiUserSwitch);
+ }
+ addView(mMultiUserSwitch, 0);
+ } else if (mMultiUserSwitch.getParent() == this && mKeyguardUserSwitcherShowing) {
+ removeView(mMultiUserSwitch);
+ }
mBatteryLevel.setVisibility(mBatteryCharging ? View.VISIBLE : View.GONE);
}
@@ -137,12 +151,71 @@ public class KeyguardStatusBarView extends RelativeLayout
updateUserSwitcher();
}
- public void setKeyguardUserSwitcherShowing(boolean showing) {
+ public void setKeyguardUserSwitcherShowing(boolean showing, boolean animate) {
mKeyguardUserSwitcherShowing = showing;
+ if (animate) {
+ animateNextLayoutChange();
+ }
updateVisibilities();
updateSystemIconsLayoutParams();
}
+ private void animateNextLayoutChange() {
+ final int systemIconsCurrentX = mSystemIconsSuperContainer.getLeft();
+ final boolean userSwitcherVisible = mMultiUserSwitch.getParent() == this;
+ getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ boolean userSwitcherHiding = userSwitcherVisible
+ && mMultiUserSwitch.getParent() != KeyguardStatusBarView.this;
+ mSystemIconsSuperContainer.setX(systemIconsCurrentX);
+ mSystemIconsSuperContainer.animate()
+ .translationX(0)
+ .setDuration(400)
+ .setStartDelay(userSwitcherHiding ? 300 : 0)
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .start();
+ if (userSwitcherHiding) {
+ getOverlay().add(mMultiUserSwitch);
+ mMultiUserSwitch.animate()
+ .alpha(0f)
+ .setDuration(300)
+ .setStartDelay(0)
+ .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ mMultiUserSwitch.setAlpha(1f);
+ getOverlay().remove(mMultiUserSwitch);
+ }
+ })
+ .start();
+
+ } else {
+ mMultiUserSwitch.setAlpha(0f);
+ mMultiUserSwitch.animate()
+ .alpha(1f)
+ .setDuration(300)
+ .setStartDelay(200)
+ .setInterpolator(PhoneStatusBar.ALPHA_IN);
+ }
+ return true;
+ }
+ });
+
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+ if (visibility != View.VISIBLE) {
+ mSystemIconsSuperContainer.animate().cancel();
+ mMultiUserSwitch.animate().cancel();
+ mMultiUserSwitch.setAlpha(1f);
+ }
+ }
+
@Override
public boolean hasOverlappingRendering() {
return false;
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 af302662e070..47325c82fab4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -65,7 +65,7 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
if (um.isUserSwitcherEnabled()) {
if (mKeyguardMode) {
if (mKeyguardUserSwitcher != null) {
- mKeyguardUserSwitcher.show();
+ mKeyguardUserSwitcher.show(true /* animate */);
}
} else {
mQsPanel.showDetailAdapter(true,
@@ -78,4 +78,9 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
getContext().startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
}
}
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index e70422b42780..74ae4a4f614b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -950,7 +950,7 @@ public class NotificationPanelView extends PanelView implements
? View.VISIBLE
: View.INVISIBLE);
if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
- mKeyguardUserSwitcher.hide();
+ mKeyguardUserSwitcher.hide(true /* animate */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 1d678af18743..75e31e4f2d69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3341,7 +3341,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void showKeyguard() {
setBarState(StatusBarState.KEYGUARD);
- updateKeyguardState(false /* goingToFullShade */);
+ updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
instantExpandNotificationsPanel();
mLeaveOpenOnKeyguardHide = false;
if (mDraggedDownRow != null) {
@@ -3413,7 +3413,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
} else {
instantCollapseNotificationPanel();
}
- updateKeyguardState(staying);
+ updateKeyguardState(staying, false /* fromShadeLocked */);
return staying;
}
@@ -3449,14 +3449,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
&& mStatusBarKeyguardViewManager.isSecure());
}
- private void updateKeyguardState(boolean goingToFullShade) {
+ private void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
if (mState == StatusBarState.KEYGUARD) {
mKeyguardIndicationController.setVisible(true);
mNotificationPanel.resetViews();
- mKeyguardUserSwitcher.setKeyguard(true);
+ mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked);
} else {
mKeyguardIndicationController.setVisible(false);
- mKeyguardUserSwitcher.setKeyguard(false);
+ mKeyguardUserSwitcher.setKeyguard(false,
+ goingToFullShade || mState == StatusBarState.SHADE_LOCKED || fromShadeLocked);
}
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
mScrimController.setKeyguardShowing(true);
@@ -3686,7 +3687,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
} else {
mNotificationPanel.animateToFullShade(0 /* delay */);
setBarState(StatusBarState.SHADE_LOCKED);
- updateKeyguardState(false /* goingToFullShade */);
+ updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
if (row != null) {
row.setUserLocked(false);
}
@@ -3699,7 +3700,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void goToKeyguard() {
if (mState == StatusBarState.SHADE_LOCKED) {
setBarState(StatusBarState.KEYGUARD);
- updateKeyguardState(false /* goingToFullShade */);
+ updateKeyguardState(false /* goingToFullShade */, true /* fromShadeLocked*/);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 203196ebe802..18583ee401c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -16,18 +16,25 @@
package com.android.systemui.statusbar.policy;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
+import android.view.animation.AnimationUtils;
import android.widget.TextView;
+import com.android.keyguard.AppearAnimationUtils;
import com.android.systemui.R;
import com.android.systemui.qs.tiles.UserDetailItemView;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.StatusBarHeaderView;
import com.android.systemui.statusbar.phone.UserAvatarView;
@@ -43,33 +50,42 @@ public class KeyguardUserSwitcher {
private final KeyguardStatusBarView mStatusBarView;
private final Adapter mAdapter;
private final boolean mSimpleUserSwitcher;
+ private final AppearAnimationUtils mAppearAnimationUtils;
+ private final KeyguardUserSwitcherScrim mBackground;
+ private ObjectAnimator mBgAnimator;
public KeyguardUserSwitcher(Context context, ViewStub userSwitcher,
KeyguardStatusBarView statusBarView, NotificationPanelView panelView,
UserSwitcherController userSwitcherController) {
if (context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON) {
mUserSwitcher = (ViewGroup) userSwitcher.inflate();
- mUserSwitcher.setBackground(new KeyguardUserSwitcherScrim(mUserSwitcher));
+ mBackground = new KeyguardUserSwitcherScrim(mUserSwitcher);
+ mUserSwitcher.setBackground(mBackground);
mStatusBarView = statusBarView;
mStatusBarView.setKeyguardUserSwitcher(this);
panelView.setKeyguardUserSwitcher(this);
mAdapter = new Adapter(context, userSwitcherController);
mAdapter.registerDataSetObserver(mDataSetObserver);
mSimpleUserSwitcher = userSwitcherController.isSimpleUserSwitcher();
+ mAppearAnimationUtils = new AppearAnimationUtils(context, 400, -0.5f, 0.5f,
+ AnimationUtils.loadInterpolator(
+ context, android.R.interpolator.fast_out_slow_in));
} else {
mUserSwitcher = null;
mStatusBarView = null;
mAdapter = null;
mSimpleUserSwitcher = false;
+ mAppearAnimationUtils = null;
+ mBackground = null;
}
}
- public void setKeyguard(boolean keyguard) {
+ public void setKeyguard(boolean keyguard, boolean animate) {
if (mUserSwitcher != null) {
if (keyguard && shouldExpandByDefault()) {
- show();
+ show(animate);
} else {
- hide();
+ hide(animate);
}
}
}
@@ -82,20 +98,79 @@ public class KeyguardUserSwitcher {
return mSimpleUserSwitcher;
}
- public void show() {
- if (mUserSwitcher != null) {
- // TODO: animate
+ public void show(boolean animate) {
+ if (mUserSwitcher != null && mUserSwitcher.getVisibility() != View.VISIBLE) {
+ cancelAnimations();
mUserSwitcher.setVisibility(View.VISIBLE);
- mStatusBarView.setKeyguardUserSwitcherShowing(true);
+ mStatusBarView.setKeyguardUserSwitcherShowing(true, animate);
+ if (animate) {
+ startAppearAnimation();
+ }
}
}
- public void hide() {
+ public void hide(boolean animate) {
if (mUserSwitcher != null && mUserSwitcher.getVisibility() == View.VISIBLE) {
- // TODO: animate
- mUserSwitcher.setVisibility(View.GONE);
- mStatusBarView.setKeyguardUserSwitcherShowing(false);
+ cancelAnimations();
+ if (animate) {
+ startDisappearAnimation();
+ } else {
+ mUserSwitcher.setVisibility(View.GONE);
+ }
+ mStatusBarView.setKeyguardUserSwitcherShowing(false, animate);
+ }
+ }
+
+ private void cancelAnimations() {
+ int count = mUserSwitcher.getChildCount();
+ for (int i = 0; i < count; i++) {
+ mUserSwitcher.getChildAt(i).animate().cancel();
+ }
+ if (mBgAnimator != null) {
+ mBgAnimator.cancel();
}
+ mUserSwitcher.animate().cancel();
+ }
+
+ private void startAppearAnimation() {
+ int count = mUserSwitcher.getChildCount();
+ View[] objects = new View[count];
+ for (int i = 0; i < count; i++) {
+ objects[i] = mUserSwitcher.getChildAt(i);
+ }
+ mUserSwitcher.setClipChildren(false);
+ mUserSwitcher.setClipToPadding(false);
+ mAppearAnimationUtils.startAppearAnimation(objects, new Runnable() {
+ @Override
+ public void run() {
+ mUserSwitcher.setClipChildren(true);
+ mUserSwitcher.setClipToPadding(true);
+ }
+ });
+ mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255);
+ mBgAnimator.setDuration(400);
+ mBgAnimator.setInterpolator(PhoneStatusBar.ALPHA_IN);
+ mBgAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBgAnimator = null;
+ }
+ });
+ mBgAnimator.start();
+ }
+
+ private void startDisappearAnimation() {
+ mUserSwitcher.animate()
+ .alpha(0f)
+ .setDuration(300)
+ .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ mUserSwitcher.setVisibility(View.GONE);
+ mUserSwitcher.setAlpha(1f);
+ }
+ });
}
private void refresh() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
index 3356afdcb37e..43630375633f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherScrim.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.policy;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
+import android.graphics.LightingColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RadialGradient;
@@ -41,7 +42,9 @@ public class KeyguardUserSwitcherScrim extends Drawable
private int mDarkColor;
private int mTop;
+ private int mAlpha;
private Paint mRadialGradientPaint = new Paint();
+ private int mLayoutWidth;
public KeyguardUserSwitcherScrim(View host) {
host.addOnLayoutChangeListener(this);
@@ -56,13 +59,21 @@ public class KeyguardUserSwitcherScrim extends Drawable
float width = bounds.width() * OUTER_EXTENT;
float height = (mTop + bounds.height()) * OUTER_EXTENT;
canvas.translate(0, -mTop);
- canvas.scale(1, height/width);
+ canvas.scale(1, height / width);
canvas.drawRect(isLtr ? bounds.right - width : 0, 0,
isLtr ? bounds.right : bounds.left + width, width, mRadialGradientPaint);
}
@Override
public void setAlpha(int alpha) {
+ mAlpha = alpha;
+ updatePaint();
+ invalidateSelf();
+ }
+
+ @Override
+ public int getAlpha() {
+ return mAlpha;
}
@Override
@@ -78,15 +89,24 @@ public class KeyguardUserSwitcherScrim extends Drawable
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom) {
- int width = right - left;
- float radius = width * OUTER_EXTENT;
- boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
- mRadialGradientPaint.setShader(
- new RadialGradient(isLtr ? width : 0, 0, radius,
- new int[] { mDarkColor, Color.TRANSPARENT},
- new float[] { Math.max(0f, width * INNER_EXTENT / radius), 1f},
- Shader.TileMode.CLAMP));
+ mLayoutWidth = right - left;
mTop = top;
+ updatePaint();
}
}
+
+ private void updatePaint() {
+ if (mLayoutWidth == 0) {
+ return;
+ }
+ float radius = mLayoutWidth * OUTER_EXTENT;
+ boolean isLtr = getLayoutDirection() == LayoutDirection.LTR;
+ mRadialGradientPaint.setShader(
+ new RadialGradient(isLtr ? mLayoutWidth : 0, 0, radius,
+ new int[] { Color.argb(
+ (int) (Color.alpha(mDarkColor) * mAlpha / 255f), 0, 0, 0),
+ Color.TRANSPARENT },
+ new float[] { Math.max(0f, mLayoutWidth * INNER_EXTENT / radius), 1f },
+ Shader.TileMode.CLAMP));
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index ff3cd9d651b1..964acbdc3433 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1314,7 +1314,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mBackgroundDrawable = drawable;
if (mDecor != null) {
mDecor.setWindowBackground(drawable);
- mDecor.setClipToOutline(drawable != null && mClipToOutline);
}
}
}
@@ -3389,10 +3388,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
mDecor.setWindowBackground(background);
- if (background != null) {
- mDecor.setClipToOutline(mClipToOutline);
- }
-
final Drawable frame;
if (mFrameResource != 0) {
frame = getContext().getDrawable(mFrameResource);
@@ -3402,6 +3397,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mDecor.setWindowFrame(frame);
mDecor.setElevation(mElevation);
+ mDecor.setClipToOutline(mClipToOutline);
if (mTitle != null) {
setTitle(mTitle);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 59aef328ef76..77b14ac18742 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -5129,6 +5129,14 @@ public class BackupManagerService extends IBackupManager.Stub {
}
}
+ // The path needs to be canonical
+ if (info.path.contains("..") || info.path.contains("//")) {
+ if (MORE_DEBUG) {
+ Slog.w(TAG, "Dropping invalid path " + info.path);
+ }
+ return false;
+ }
+
// Otherwise we think this file is good to go
return true;
}
@@ -5680,6 +5688,14 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
break;
}
+ // The path needs to be canonical
+ if (info.path.contains("..") || info.path.contains("//")) {
+ if (MORE_DEBUG) {
+ Slog.w(TAG, "Dropping invalid path " + info.path);
+ }
+ okay = false;
+ }
+
// If the policy is satisfied, go ahead and set up to pipe the
// data to the agent.
if (DEBUG && okay && mAgent != null) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6761f24afb08..f9baccdaeed8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -251,10 +251,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private int mNetworkPreference;
private int mActiveDefaultNetwork = -1;
// 0 is full bad, 100 is full good
- private int mDefaultInetCondition = 0;
private int mDefaultInetConditionPublished = 0;
- private boolean mInetConditionChangeInFlight = false;
- private int mDefaultConnectionSequence = 0;
private Object mDnsLock = new Object();
private int mNumDnsEntries;
@@ -274,19 +271,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2;
/**
- * used internally to synchronize inet condition reports
- * arg1 = networkType
- * arg2 = condition (0 bad, 100 good)
- */
- private static final int EVENT_INET_CONDITION_CHANGE = 4;
-
- /**
- * used internally to mark the end of inet condition hold periods
- * arg1 = networkType
- */
- private static final int EVENT_INET_CONDITION_HOLD_END = 5;
-
- /**
* used internally to clear a wakelock when transitioning
* from one net to another. Clear happens when we get a new
* network - EVENT_EXPIRE_NET_TRANSITION_WAKELOCK happens
@@ -490,10 +474,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mTypeLists[type] = new ArrayList<NetworkAgentInfo>();
}
- private boolean isDefaultNetwork(NetworkAgentInfo nai) {
- return mNetworkForRequestId.get(mDefaultRequest.requestId) == nai;
- }
-
public boolean isTypeSupported(int type) {
return isNetworkTypeValid(type) && mTypeLists[type] != null;
}
@@ -2052,6 +2032,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
null, null);
}
+ if (isDefaultNetwork(nai)) {
+ mDefaultInetConditionPublished = 0;
+ }
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
mNetworkAgentInfos.remove(msg.replyTo);
@@ -2222,18 +2205,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
break;
}
- case EVENT_INET_CONDITION_CHANGE: {
- int netType = msg.arg1;
- int condition = msg.arg2;
- handleInetConditionChange(netType, condition);
- break;
- }
- case EVENT_INET_CONDITION_HOLD_END: {
- int netType = msg.arg1;
- int sequence = msg.arg2;
- handleInetConditionHoldEnd(netType, sequence);
- break;
- }
case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
handleDeprecatedGlobalHttpProxy();
break;
@@ -2428,99 +2399,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// 100 percent is full good, 0 is full bad.
public void reportInetCondition(int networkType, int percentage) {
- if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.STATUS_BAR,
- "ConnectivityService");
-
- if (DBG) {
- int pid = getCallingPid();
- int uid = getCallingUid();
- String s = pid + "(" + uid + ") reports inet is " +
- (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " +
- "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime();
- mInetLog.add(s);
- while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) {
- mInetLog.remove(0);
- }
- }
- mHandler.sendMessage(mHandler.obtainMessage(
- EVENT_INET_CONDITION_CHANGE, networkType, percentage));
+ if (percentage > 50) return; // don't handle good network reports
+ NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
+ if (nai != null) reportBadNetwork(nai.network);
}
public void reportBadNetwork(Network network) {
//TODO
}
- private void handleInetConditionChange(int netType, int condition) {
- if (mActiveDefaultNetwork == -1) {
- if (DBG) log("handleInetConditionChange: no active default network - ignore");
- return;
- }
- if (mActiveDefaultNetwork != netType) {
- if (DBG) log("handleInetConditionChange: net=" + netType +
- " != default=" + mActiveDefaultNetwork + " - ignore");
- return;
- }
- if (VDBG) {
- log("handleInetConditionChange: net=" +
- netType + ", condition=" + condition +
- ",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
- }
- mDefaultInetCondition = condition;
- int delay;
- if (mInetConditionChangeInFlight == false) {
- if (VDBG) log("handleInetConditionChange: starting a change hold");
- // setup a new hold to debounce this
- if (mDefaultInetCondition > 50) {
- delay = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY, 500);
- } else {
- delay = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000);
- }
- mInetConditionChangeInFlight = true;
- mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END,
- mActiveDefaultNetwork, mDefaultConnectionSequence), delay);
- } else {
- // we've set the new condition, when this hold ends that will get picked up
- if (VDBG) log("handleInetConditionChange: currently in hold - not setting new end evt");
- }
- }
-
- private void handleInetConditionHoldEnd(int netType, int sequence) {
- if (DBG) {
- log("handleInetConditionHoldEnd: net=" + netType +
- ", condition=" + mDefaultInetCondition +
- ", published condition=" + mDefaultInetConditionPublished);
- }
- mInetConditionChangeInFlight = false;
-
- if (mActiveDefaultNetwork == -1) {
- if (DBG) log("handleInetConditionHoldEnd: no active default network - ignoring");
- return;
- }
- if (mDefaultConnectionSequence != sequence) {
- if (DBG) log("handleInetConditionHoldEnd: event hold for obsolete network - ignoring");
- return;
- }
- // TODO: Figure out why this optimization sometimes causes a
- // change in mDefaultInetCondition to be missed and the
- // UI to not be updated.
- //if (mDefaultInetConditionPublished == mDefaultInetCondition) {
- // if (DBG) log("no change in condition - aborting");
- // return;
- //}
- NetworkInfo networkInfo = getNetworkInfoForType(mActiveDefaultNetwork);
- if (networkInfo.isConnected() == false) {
- if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring");
- return;
- }
- mDefaultInetConditionPublished = mDefaultInetCondition;
- sendInetConditionBroadcast(networkInfo);
- return;
- }
-
public ProxyInfo getProxy() {
// this information is already available as a world read/writable jvm property
// so this API change wouldn't have a benifit. It also breaks the passing
@@ -4206,6 +4093,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private final NetworkRequest mDefaultRequest;
+ private boolean isDefaultNetwork(NetworkAgentInfo nai) {
+ return mNetworkForRequestId.get(mDefaultRequest.requestId) == nai;
+ }
+
public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkMisc networkMisc) {
@@ -4532,6 +4423,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mLegacyTypeTracker.remove(currentNetwork.networkInfo.getType(),
currentNetwork);
}
+ mDefaultInetConditionPublished = 100;
mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
}
}
@@ -4581,8 +4473,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// to connected after our normal pause unless somebody reports us as
// really disconnected
mDefaultInetConditionPublished = 0;
- mDefaultConnectionSequence++;
- mInetConditionChangeInFlight = false;
// TODO - read the tcp buffer size config string from somewhere
// updateNetworkSettings();
}
diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java
index af38664080ec..d05c280093fb 100644
--- a/services/core/java/com/android/server/DockObserver.java
+++ b/services/core/java/com/android/server/DockObserver.java
@@ -201,9 +201,6 @@ final class DockObserver extends SystemService {
// There are many components in the system watching for this so as to
// adjust audio routing, screen orientation, etc.
getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
-
- // Release the wake lock that was acquired when the message was posted.
- mWakeLock.release();
}
}
@@ -213,6 +210,7 @@ final class DockObserver extends SystemService {
switch (msg.what) {
case MSG_DOCK_STATE_CHANGED:
handleDockStateChange();
+ mWakeLock.release();
break;
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 74f725f36f60..71f43b487214 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -37,13 +37,12 @@ import android.media.AudioPort;
import android.media.AudioPortConfig;
import android.media.tv.ITvInputHardware;
import android.media.tv.ITvInputHardwareCallback;
-import android.media.tv.TvInputHardwareInfo;
import android.media.tv.TvContract;
+import android.media.tv.TvInputHardwareInfo;
import android.media.tv.TvInputInfo;
import android.media.tv.TvStreamConfig;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -59,12 +58,10 @@ import com.android.server.SystemService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* A helper class for TvInputManagerService to handle TV input hardware.
@@ -82,11 +79,11 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private final TvInputHal mHal = new TvInputHal(this);
private final SparseArray<Connection> mConnections = new SparseArray<>();
private final List<TvInputHardwareInfo> mHardwareList = new ArrayList<>();
- private List<HdmiDeviceInfo> mHdmiCecDeviceList = new LinkedList<>();
+ private final List<HdmiDeviceInfo> mHdmiDeviceList = new LinkedList<>();
/* A map from a device ID to the matching TV input ID. */
private final SparseArray<String> mHardwareInputIdMap = new SparseArray<>();
/* A map from a HDMI logical address to the matching TV input ID. */
- private final SparseArray<String> mHdmiCecInputIdMap = new SparseArray<>();
+ private final SparseArray<String> mHdmiInputIdMap = new SparseArray<>();
private final Map<String, TvInputInfo> mInputMap = new ArrayMap<>();
private final AudioManager mAudioManager;
@@ -119,7 +116,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
try {
mHdmiControlService.addHotplugEventListener(mHdmiHotplugEventListener);
mHdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener);
- mHdmiCecDeviceList.addAll(mHdmiControlService.getInputDevices());
+ mHdmiDeviceList.addAll(mHdmiControlService.getInputDevices());
mHdmiControlService.setInputChangeListener(mHdmiInputChangeListener);
} catch (RemoteException e) {
Slog.w(TAG, "Error registering listeners to HdmiControlService:", e);
@@ -163,12 +160,11 @@ class TvInputHardwareManager implements TvInputHal.Callback {
buildHardwareListLocked();
TvInputHardwareInfo info = connection.getHardwareInfoLocked();
if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) {
- // Remove HDMI CEC devices linked with this hardware.
- for (Iterator<HdmiDeviceInfo> it = mHdmiCecDeviceList.iterator();
- it.hasNext(); ) {
+ // Remove HDMI devices linked with this hardware.
+ for (Iterator<HdmiDeviceInfo> it = mHdmiDeviceList.iterator(); it.hasNext();) {
HdmiDeviceInfo deviceInfo = it.next();
if (deviceInfo.getPortId() == info.getHdmiPortId()) {
- mHandler.obtainMessage(ListenerHandler.HDMI_CEC_DEVICE_REMOVED, 0, 0,
+ mHandler.obtainMessage(ListenerHandler.HDMI_DEVICE_REMOVED, 0, 0,
deviceInfo).sendToTarget();
it.remove();
}
@@ -220,9 +216,9 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
- public List<HdmiDeviceInfo> getHdmiCecInputDeviceList() {
+ public List<HdmiDeviceInfo> getHdmiDeviceList() {
synchronized (mLock) {
- return Collections.unmodifiableList(mHdmiCecDeviceList);
+ return Collections.unmodifiableList(mHdmiDeviceList);
}
}
@@ -283,7 +279,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
return -1;
}
- public void addHdmiCecTvInput(int logicalAddress, TvInputInfo info) {
+ public void addHdmiTvInput(int logicalAddress, TvInputInfo info) {
if (info.getType() != TvInputInfo.TYPE_HDMI) {
throw new IllegalArgumentException("info (" + info + ") has non-HDMI type.");
}
@@ -293,13 +289,13 @@ class TvInputHardwareManager implements TvInputHal.Callback {
if (parentIndex < 0) {
throw new IllegalArgumentException("info (" + info + ") has invalid parentId.");
}
- String oldInputId = mHdmiCecInputIdMap.get(logicalAddress);
+ String oldInputId = mHdmiInputIdMap.get(logicalAddress);
if (oldInputId != null) {
Slog.w(TAG, "Trying to override previous registration: old = "
+ mInputMap.get(oldInputId) + ":" + logicalAddress + ", new = "
+ info + ":" + logicalAddress);
}
- mHdmiCecInputIdMap.put(logicalAddress, info.getId());
+ mHdmiInputIdMap.put(logicalAddress, info.getId());
mInputMap.put(info.getId(), info);
}
}
@@ -311,9 +307,9 @@ class TvInputHardwareManager implements TvInputHal.Callback {
if (hardwareIndex >= 0) {
mHardwareInputIdMap.removeAt(hardwareIndex);
}
- int cecIndex = indexOfEqualValue(mHdmiCecInputIdMap, inputId);
- if (cecIndex >= 0) {
- mHdmiCecInputIdMap.removeAt(cecIndex);
+ int deviceIndex = indexOfEqualValue(mHdmiInputIdMap, inputId);
+ if (deviceIndex >= 0) {
+ mHdmiInputIdMap.removeAt(deviceIndex);
}
}
}
@@ -864,16 +860,16 @@ class TvInputHardwareManager implements TvInputHal.Callback {
public void onStateChanged(String inputId, int state);
public void onHardwareDeviceAdded(TvInputHardwareInfo info);
public void onHardwareDeviceRemoved(TvInputHardwareInfo info);
- public void onHdmiCecDeviceAdded(HdmiDeviceInfo cecDevice);
- public void onHdmiCecDeviceRemoved(HdmiDeviceInfo cecDevice);
+ public void onHdmiDeviceAdded(HdmiDeviceInfo device);
+ public void onHdmiDeviceRemoved(HdmiDeviceInfo device);
}
private class ListenerHandler extends Handler {
private static final int STATE_CHANGED = 1;
private static final int HARDWARE_DEVICE_ADDED = 2;
private static final int HARDWARE_DEVICE_REMOVED = 3;
- private static final int HDMI_CEC_DEVICE_ADDED = 4;
- private static final int HDMI_CEC_DEVICE_REMOVED = 5;
+ private static final int HDMI_DEVICE_ADDED = 4;
+ private static final int HDMI_DEVICE_REMOVED = 5;
@Override
public final void handleMessage(Message msg) {
@@ -894,14 +890,14 @@ class TvInputHardwareManager implements TvInputHal.Callback {
mListener.onHardwareDeviceRemoved(info);
break;
}
- case HDMI_CEC_DEVICE_ADDED: {
+ case HDMI_DEVICE_ADDED: {
HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj;
- mListener.onHdmiCecDeviceAdded(info);
+ mListener.onHdmiDeviceAdded(info);
break;
}
- case HDMI_CEC_DEVICE_REMOVED: {
+ case HDMI_DEVICE_REMOVED: {
HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj;
- mListener.onHdmiCecDeviceRemoved(info);
+ mListener.onHdmiDeviceRemoved(info);
break;
}
default: {
@@ -939,21 +935,21 @@ class TvInputHardwareManager implements TvInputHal.Callback {
public void onStatusChanged(HdmiDeviceInfo deviceInfo, boolean activated) {
synchronized (mLock) {
if (activated) {
- if (!mHdmiCecDeviceList.contains(deviceInfo)) {
- mHdmiCecDeviceList.add(deviceInfo);
+ if (!mHdmiDeviceList.contains(deviceInfo)) {
+ mHdmiDeviceList.add(deviceInfo);
} else {
Slog.w(TAG, "The list already contains " + deviceInfo + "; ignoring.");
return;
}
} else {
- if (!mHdmiCecDeviceList.remove(deviceInfo)) {
+ if (!mHdmiDeviceList.remove(deviceInfo)) {
Slog.w(TAG, "The list doesn't contain " + deviceInfo + "; ignoring.");
return;
}
}
Message msg = mHandler.obtainMessage(
- activated ? ListenerHandler.HDMI_CEC_DEVICE_ADDED
- : ListenerHandler.HDMI_CEC_DEVICE_REMOVED,
+ activated ? ListenerHandler.HDMI_DEVICE_ADDED
+ : ListenerHandler.HDMI_DEVICE_REMOVED,
0, 0, deviceInfo);
if (findHardwareInfoForHdmiPortLocked(deviceInfo.getPortId()) != null) {
msg.sendToTarget();
@@ -970,7 +966,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
String inputId;
synchronized (mLock) {
if (device.isCecDevice()) {
- inputId = mHdmiCecInputIdMap.get(device.getLogicalAddress());
+ inputId = mHdmiInputIdMap.get(device.getLogicalAddress());
} else {
TvInputHardwareInfo hardwareInfo =
findHardwareInfoForHdmiPortLocked(device.getPortId());
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 14d1ec4af617..c5e30d5705f6 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -1933,13 +1933,13 @@ public final class TvInputManagerService extends SystemService {
}
}
- List<HdmiDeviceInfo> cecDeviceInfoList =
- mTvInputHardwareManager.getHdmiCecInputDeviceList();
- for (HdmiDeviceInfo cecDeviceInfo : cecDeviceInfoList) {
+ List<HdmiDeviceInfo> deviceInfoList =
+ mTvInputHardwareManager.getHdmiDeviceList();
+ for (HdmiDeviceInfo deviceInfo : deviceInfoList) {
try {
- serviceState.mService.notifyHdmiCecDeviceAdded(cecDeviceInfo);
+ serviceState.mService.notifyHdmiDeviceAdded(deviceInfo);
} catch (RemoteException e) {
- Slog.e(TAG, "error in notifyHdmiCecDeviceAdded", e);
+ Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
}
}
}
@@ -2025,11 +2025,11 @@ public final class TvInputManagerService extends SystemService {
}
@Override
- public void addHdmiCecTvInput(int logicalAddress, TvInputInfo inputInfo) {
+ public void addHdmiTvInput(int logicalAddress, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
synchronized (mLock) {
- mTvInputHardwareManager.addHdmiCecTvInput(logicalAddress, inputInfo);
+ mTvInputHardwareManager.addHdmiTvInput(logicalAddress, inputInfo);
addTvInputLocked(inputInfo);
}
}
@@ -2275,32 +2275,32 @@ public final class TvInputManagerService extends SystemService {
}
@Override
- public void onHdmiCecDeviceAdded(HdmiDeviceInfo cecDeviceInfo) {
+ public void onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
synchronized (mLock) {
UserState userState = getUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.mIsHardware || serviceState.mService == null) continue;
try {
- serviceState.mService.notifyHdmiCecDeviceAdded(cecDeviceInfo);
+ serviceState.mService.notifyHdmiDeviceAdded(deviceInfo);
} catch (RemoteException e) {
- Slog.e(TAG, "error in notifyHdmiCecDeviceAdded", e);
+ Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
}
}
}
}
@Override
- public void onHdmiCecDeviceRemoved(HdmiDeviceInfo cecDeviceInfo) {
+ public void onHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
synchronized (mLock) {
UserState userState = getUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.mIsHardware || serviceState.mService == null) continue;
try {
- serviceState.mService.notifyHdmiCecDeviceRemoved(cecDeviceInfo);
+ serviceState.mService.notifyHdmiDeviceRemoved(deviceInfo);
} catch (RemoteException e) {
- Slog.e(TAG, "error in notifyHdmiCecDeviceRemoved", e);
+ Slog.e(TAG, "error in notifyHdmiDeviceRemoved", e);
}
}
}
diff --git a/tools/layoutlib/rename_font/build_font_single.py b/tools/layoutlib/rename_font/build_font_single.py
new file mode 100755
index 000000000000..d648b047b4b9
--- /dev/null
+++ b/tools/layoutlib/rename_font/build_font_single.py
@@ -0,0 +1,207 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2014 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.
+
+"""
+Rename the PS name of the input font.
+
+OpenType fonts (*.otf) are not currently supported. They are copied to the destination without renaming.
+XML files are also copied in case they are passed there by mistake.
+
+Usage: build_font.py /path/to/input_font.ttf /path/to/output_font.ttf
+
+"""
+
+import glob
+import os
+import re
+import shutil
+import sys
+import xml.etree.ElementTree as etree
+
+# Prevent .pyc files from being created.
+sys.dont_write_bytecode = True
+
+# fontTools is available at platform/external/fonttools
+from fontTools import ttx
+
+
+class FontInfo(object):
+ family = None
+ style = None
+ version = None
+ ends_in_regular = False
+ fullname = None
+
+
+class InvalidFontException(Exception):
+ pass
+
+
+# A constant to copy the font without modifying. This is useful when running
+# locally and speed up the time to build the SDK.
+COPY_ONLY = False
+
+# These constants represent the value of nameID parameter in the namerecord for
+# different information.
+# see http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#3054f18b
+NAMEID_FAMILY = 1
+NAMEID_STYLE = 2
+NAMEID_FULLNAME = 4
+NAMEID_VERSION = 5
+
+# A list of extensions to process.
+EXTENSIONS = ['.ttf', '.otf', '.xml']
+
+def main(argv):
+ if len(argv) < 2:
+ sys.exit('Usage: build_font.py /path/to/input/font.ttf /path/to/out/font.ttf')
+ dest_path = argv[-1]
+ input_path = argv[0]
+ extension = os.path.splitext(input_path)[1].lower()
+ if extension in EXTENSIONS:
+ if not COPY_ONLY and extension == '.ttf':
+ convert_font(input_path, dest_path)
+ return
+ shutil.copy(input_path, dest_path)
+
+
+def convert_font(input_path, dest_path):
+ filename = os.path.basename(input_path)
+ print 'Converting font: ' + filename
+ # the path to the output file. The file name is the fontfilename.ttx
+ ttx_path = dest_path[:-1] + 'x'
+ try:
+ # run ttx to generate an xml file in the output folder which represents all
+ # its info
+ ttx_args = ['-q', '-o', ttx_path, input_path]
+ ttx.main(ttx_args)
+ # now parse the xml file to change its PS name.
+ tree = etree.parse(ttx_path)
+ root = tree.getroot()
+ for name in root.iter('name'):
+ update_tag(name, get_font_info(name))
+ tree.write(ttx_path, xml_declaration=True, encoding='utf-8')
+ # generate the udpated font now.
+ ttx_args = ['-q', '-o', dest_path, ttx_path]
+ ttx.main(ttx_args)
+ except InvalidFontException:
+ # In case of invalid fonts, we exit.
+ print filename + ' is not a valid font'
+ raise
+ except Exception as e:
+ print 'Error converting font: ' + filename
+ print e
+ # Some fonts are too big to be handled by the ttx library.
+ # Just copy paste them.
+ shutil.copy(input_path, dest_path)
+ try:
+ # delete the temp ttx file is it exists.
+ os.remove(ttx_path)
+ except OSError:
+ pass
+
+
+def get_font_info(tag):
+ """ Returns a list of FontInfo representing the various sets of namerecords
+ found in the name table of the font. """
+ fonts = []
+ font = None
+ last_name_id = sys.maxint
+ for namerecord in tag.iter('namerecord'):
+ if 'nameID' in namerecord.attrib:
+ name_id = int(namerecord.attrib['nameID'])
+ # A new font should be created for each platform, encoding and language
+ # id. But, since the nameIDs are sorted, we use the easy approach of
+ # creating a new one when the nameIDs reset.
+ if name_id <= last_name_id and font is not None:
+ fonts.append(font)
+ font = None
+ last_name_id = name_id
+ if font is None:
+ font = FontInfo()
+ if name_id == NAMEID_FAMILY:
+ font.family = namerecord.text.strip()
+ if name_id == NAMEID_STYLE:
+ font.style = namerecord.text.strip()
+ if name_id == NAMEID_FULLNAME:
+ font.ends_in_regular = ends_in_regular(namerecord.text)
+ font.fullname = namerecord.text.strip()
+ if name_id == NAMEID_VERSION:
+ font.version = get_version(namerecord.text)
+ if font is not None:
+ fonts.append(font)
+ return fonts
+
+
+def update_tag(tag, fonts):
+ last_name_id = sys.maxint
+ fonts_iterator = fonts.__iter__()
+ font = None
+ for namerecord in tag.iter('namerecord'):
+ if 'nameID' in namerecord.attrib:
+ name_id = int(namerecord.attrib['nameID'])
+ if name_id <= last_name_id:
+ font = fonts_iterator.next()
+ font = update_font_name(font)
+ last_name_id = name_id
+ if name_id == NAMEID_FAMILY:
+ namerecord.text = font.family
+ if name_id == NAMEID_FULLNAME:
+ namerecord.text = font.fullname
+
+
+def update_font_name(font):
+ """ Compute the new font family name and font fullname. If the font has a
+ valid version, it's sanitized and appended to the font family name. The
+ font fullname is then created by joining the new family name and the
+ style. If the style is 'Regular', it is appended only if the original font
+ had it. """
+ if font.family is None or font.style is None:
+ raise InvalidFontException('Font doesn\'t have proper family name or style')
+ if font.version is not None:
+ new_family = font.family + font.version
+ else:
+ new_family = font.family
+ if font.style is 'Regular' and not font.ends_in_regular:
+ font.fullname = new_family
+ else:
+ font.fullname = new_family + ' ' + font.style
+ font.family = new_family
+ return font
+
+
+def ends_in_regular(string):
+ """ According to the specification, the font fullname should not end in
+ 'Regular' for plain fonts. However, some fonts don't obey this rule. We
+ keep the style info, to minimize the diff. """
+ string = string.strip().split()[-1]
+ return string is 'Regular'
+
+
+def get_version(string):
+ # The string must begin with 'Version n.nn '
+ # to extract n.nn, we return the second entry in the split strings.
+ string = string.strip()
+ if not string.startswith('Version '):
+ raise InvalidFontException('mal-formed font version')
+ return sanitize(string.split()[1])
+
+
+def sanitize(string):
+ return re.sub(r'[^\w-]+', '', string)
+
+if __name__ == '__main__':
+ main(sys.argv[1:])