Merge "QS: Repoint Wifi + BT dual tile labels to settings." into lmp-dev
diff --git a/Android.mk b/Android.mk
index 80b860b..6280332 100644
--- a/Android.mk
+++ b/Android.mk
@@ -156,6 +156,7 @@
core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl \
core/java/android/hardware/hdmi/IHdmiHotplugEventListener.aidl \
core/java/android/hardware/hdmi/IHdmiInputChangeListener.aidl \
+ core/java/android/hardware/hdmi/IHdmiMhlScratchpadCommandListener.aidl \
core/java/android/hardware/hdmi/IHdmiRecordListener.aidl \
core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl \
core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 7bc30fd..547ec6c 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -222,6 +222,7 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services.core_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/inputflinger $(PRODUCT_OUT)/symbols/system/bin/inputflinger)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/RsFountainFbo_intermediates)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index de3723c..9c97cc9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1028,6 +1028,8 @@
field public static final int readPermission = 16842759; // 0x1010007
field public static final int recognitionService = 16843932; // 0x101049c
field public static final int relinquishTaskIdentity = 16843894; // 0x1010476
+ field public static final int reparent = 16843965; // 0x10104bd
+ field public static final int reparentWithOverlay = 16843966; // 0x10104be
field public static final int repeatCount = 16843199; // 0x10101bf
field public static final int repeatMode = 16843200; // 0x10101c0
field public static final int reqFiveWayNav = 16843314; // 0x1010232
@@ -1445,6 +1447,7 @@
field public static final int windowSharedElementExitTransition = 16843834; // 0x101043a
field public static final int windowSharedElementReenterTransition = 16843954; // 0x10104b2
field public static final int windowSharedElementReturnTransition = 16843953; // 0x10104b1
+ field public static final int windowSharedElementsUseOverlay = 16843964; // 0x10104bc
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -12978,7 +12981,7 @@
}
public class CaptureFailure {
- method public int getFrameNumber();
+ method public long getFrameNumber();
method public int getReason();
method public android.hardware.camera2.CaptureRequest getRequest();
method public int getSequenceId();
@@ -13571,7 +13574,7 @@
method public void onStartInput(android.view.inputmethod.EditorInfo, boolean);
method public void onStartInputView(android.view.inputmethod.EditorInfo, boolean);
method public void onUnbindInput();
- method public void onUpdateCursor(android.graphics.Rect);
+ method public deprecated void onUpdateCursor(android.graphics.Rect);
method public void onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
method public void onUpdateExtractedText(int, android.view.inputmethod.ExtractedText);
method public void onUpdateExtractingViews(android.view.inputmethod.EditorInfo);
@@ -17212,12 +17215,12 @@
}
public class Network implements android.os.Parcelable {
+ method public void bindSocket(java.net.Socket) throws java.io.IOException;
method public int describeContents();
method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
- method public java.net.URL getBoundURL(java.net.URL) throws java.net.MalformedURLException;
method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException;
method public javax.net.SocketFactory getSocketFactory();
- method public static void setNetworkBoundURLFactory(android.net.NetworkBoundURLFactory);
+ method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
@@ -31802,7 +31805,7 @@
ctor public ChangeBounds(android.content.Context, android.util.AttributeSet);
method public void captureEndValues(android.transition.TransitionValues);
method public void captureStartValues(android.transition.TransitionValues);
- method public void setReparent(boolean);
+ method public deprecated void setReparent(boolean);
method public void setResizeClip(boolean);
}
@@ -31825,6 +31828,10 @@
ctor public ChangeTransform(android.content.Context, android.util.AttributeSet);
method public void captureEndValues(android.transition.TransitionValues);
method public void captureStartValues(android.transition.TransitionValues);
+ method public boolean getReparent();
+ method public boolean getReparentWithOverlay();
+ method public void setReparent(boolean);
+ method public void setReparentWithOverlay(boolean);
}
public class CircularPropagation extends android.transition.VisibilityPropagation {
@@ -35137,6 +35144,7 @@
method public android.transition.Transition getSharedElementExitTransition();
method public android.transition.Transition getSharedElementReenterTransition();
method public android.transition.Transition getSharedElementReturnTransition();
+ method public boolean getSharedElementsUseOverlay();
method public abstract int getStatusBarColor();
method public long getTransitionBackgroundFadeDuration();
method public android.transition.TransitionManager getTransitionManager();
@@ -35198,6 +35206,7 @@
method public void setSharedElementExitTransition(android.transition.Transition);
method public void setSharedElementReenterTransition(android.transition.Transition);
method public void setSharedElementReturnTransition(android.transition.Transition);
+ method public void setSharedElementsUseOverlay(boolean);
method public void setSoftInputMode(int);
method public abstract void setStatusBarColor(int);
method public abstract void setTitle(java.lang.CharSequence);
@@ -36178,7 +36187,7 @@
method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
method public static final void removeComposingSpans(android.text.Spannable);
method public boolean reportFullscreenMode(boolean);
- method public int requestCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfoRequest);
+ method public boolean requestUpdateCursorAnchorInfo(int);
method public boolean sendKeyEvent(android.view.KeyEvent);
method public boolean setComposingRegion(int, int);
method public static void setComposingSpans(android.text.Spannable);
@@ -36244,25 +36253,6 @@
method public android.view.inputmethod.CursorAnchorInfo.Builder setSelectionRange(int, int);
}
- public final class CursorAnchorInfoRequest implements android.os.Parcelable {
- ctor public CursorAnchorInfoRequest(int, int);
- ctor public CursorAnchorInfoRequest(android.os.Parcel);
- method public int describeContents();
- method public int getRequestFlags();
- method public int getRequestType();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- field public static final int FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE = 2; // 0x2
- field public static final int FLAG_CURSOR_ANCHOR_INFO_MONITOR = 1; // 0x1
- field public static final int FLAG_CURSOR_RECT_IN_SCREEN_COORDINATES = 2; // 0x2
- field public static final int FLAG_CURSOR_RECT_MONITOR = 1; // 0x1
- field public static final int FLAG_CURSOR_RECT_WITH_VIEW_MATRIX = 4; // 0x4
- field public static final int RESULT_NOT_HANDLED = 0; // 0x0
- field public static final int RESULT_SCHEDULED = 1; // 0x1
- field public static final int TYPE_CURSOR_ANCHOR_INFO = 1; // 0x1
- field public static final int TYPE_CURSOR_RECT = 2; // 0x2
- }
-
public class EditorInfo implements android.text.InputType android.os.Parcelable {
ctor public EditorInfo();
method public int describeContents();
@@ -36360,13 +36350,15 @@
method public abstract boolean performEditorAction(int);
method public abstract boolean performPrivateCommand(java.lang.String, android.os.Bundle);
method public abstract boolean reportFullscreenMode(boolean);
- method public abstract int requestCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfoRequest);
+ method public abstract boolean requestUpdateCursorAnchorInfo(int);
method public abstract boolean sendKeyEvent(android.view.KeyEvent);
method public abstract boolean setComposingRegion(int, int);
method public abstract boolean setComposingText(java.lang.CharSequence, int);
method public abstract boolean setSelection(int, int);
field public static final int GET_EXTRACTED_TEXT_MONITOR = 1; // 0x1
field public static final int GET_TEXT_WITH_STYLES = 1; // 0x1
+ field public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE = 1; // 0x1
+ field public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR = 2; // 0x2
}
public class InputConnectionWrapper implements android.view.inputmethod.InputConnection {
@@ -36388,7 +36380,7 @@
method public boolean performEditorAction(int);
method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
method public boolean reportFullscreenMode(boolean);
- method public int requestCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfoRequest);
+ method public boolean requestUpdateCursorAnchorInfo(int);
method public boolean sendKeyEvent(android.view.KeyEvent);
method public boolean setComposingRegion(int, int);
method public boolean setComposingText(java.lang.CharSequence, int);
@@ -36454,7 +36446,7 @@
method public boolean isActive(android.view.View);
method public boolean isActive();
method public boolean isFullscreenMode();
- method public boolean isWatchingCursor(android.view.View);
+ method public deprecated boolean isWatchingCursor(android.view.View);
method public void restartInput(android.view.View);
method public void sendAppPrivateCommand(android.view.View, java.lang.String, android.os.Bundle);
method public void setAdditionalInputMethodSubtypes(java.lang.String, android.view.inputmethod.InputMethodSubtype[]);
@@ -36472,7 +36464,7 @@
method public boolean switchToNextInputMethod(android.os.IBinder, boolean);
method public void toggleSoftInput(int, int);
method public void toggleSoftInputFromWindow(android.os.IBinder, int, int);
- method public void updateCursor(android.view.View, int, int, int, int);
+ method public deprecated void updateCursor(android.view.View, int, int, int, int);
method public void updateCursorAnchorInfo(android.view.View, android.view.inputmethod.CursorAnchorInfo);
method public void updateExtractedText(android.view.View, int, android.view.inputmethod.ExtractedText);
method public void updateSelection(android.view.View, int, int, int, int);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f5ac5f7..ffcdcf7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5021,6 +5021,9 @@
}
}
}
+ if (mActionBar != null) {
+ mActionBar.setTitle(title);
+ }
}
protected void onChildTitleChanged(Activity childActivity, CharSequence title) {
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 7d2f677..e4f2b88 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -665,6 +665,9 @@
}
protected void moveSharedElementsToOverlay() {
+ if (!mWindow.getSharedElementsUseOverlay()) {
+ return;
+ }
int numSharedElements = mSharedElements.size();
ViewGroup decor = getDecor();
if (decor != null) {
@@ -700,6 +703,17 @@
}
protected void moveSharedElementsFromOverlay() {
+ int numListeners = mGhostViewListeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ GhostViewListeners listener = mGhostViewListeners.get(i);
+ ViewGroup parent = (ViewGroup) listener.getView().getParent();
+ parent.getViewTreeObserver().removeOnPreDrawListener(listener);
+ }
+ mGhostViewListeners.clear();
+
+ if (mWindow == null || !mWindow.getSharedElementsUseOverlay()) {
+ return;
+ }
ViewGroup decor = getDecor();
if (decor != null) {
ViewGroupOverlay overlay = decor.getOverlay();
@@ -709,13 +723,6 @@
GhostView.removeGhost(sharedElement);
}
}
- int numListeners = mGhostViewListeners.size();
- for (int i = 0; i < numListeners; i++) {
- GhostViewListeners listener = mGhostViewListeners.get(i);
- ViewGroup parent = (ViewGroup) listener.getView().getParent();
- parent.getViewTreeObserver().removeOnPreDrawListener(listener);
- }
- mGhostViewListeners.clear();
}
protected void setGhostVisibility(int visibility) {
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 936e205..b7af544 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -434,6 +434,12 @@
* @return The job object to hand to the JobScheduler. This object is immutable.
*/
public JobInfo build() {
+ // Allow tasks with no constraints. What am I, a database?
+ if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging &&
+ !mRequiresDeviceIdle && mNetworkCapabilities == NetworkType.NONE) {
+ throw new IllegalArgumentException("You're trying to build a job with no " +
+ "constraints, this is not allowed.");
+ }
mExtras = new PersistableBundle(mExtras); // Make our own copy.
// Check that a deadline was not set on a periodic job.
if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index 7fe192c..ca7022d 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -22,7 +22,13 @@
/**
* Class for scheduling various types of jobs with the scheduling framework on the device.
- *
+ * See {@link android.app.job.JobInfo} for more description of the types of jobs that can be run
+ * and how to construct them.
+ * The framework will be intelligent about when you receive your callbacks, and attempt to batch
+ * and defer them as much as possible. Typically if you don't specify a deadline on your job, it
+ * can be run at any moment depending on the current state of the JobScheduler's internal queue,
+ * however it might be deferred as long as until the next time the device is connected to a power
+ * source.
* <p>You do not
* instantiate this class directly; instead, retrieve it through
* {@link android.content.Context#getSystemService
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index a83bd4a..d19418b 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1470,6 +1470,12 @@
case 320:
parts.add("xhdpi");
break;
+ case 480:
+ parts.add("xxhdpi");
+ break;
+ case 640:
+ parts.add("xxxhdpi");
+ break;
default:
parts.add(config.densityDpi + "dpi");
break;
@@ -1542,7 +1548,7 @@
break;
}
- parts.add("v" + Build.VERSION.SDK_INT);
+ parts.add("v" + Build.VERSION.RESOURCES_SDK_INT);
return TextUtils.join("-", parts);
}
}
diff --git a/core/java/android/hardware/camera2/CaptureFailure.java b/core/java/android/hardware/camera2/CaptureFailure.java
index 2c505e5..b6d3b08 100644
--- a/core/java/android/hardware/camera2/CaptureFailure.java
+++ b/core/java/android/hardware/camera2/CaptureFailure.java
@@ -47,13 +47,13 @@
private final int mReason;
private final boolean mDropped;
private final int mSequenceId;
- private final int mFrameNumber;
+ private final long mFrameNumber;
/**
* @hide
*/
public CaptureFailure(CaptureRequest request, int reason, boolean dropped, int sequenceId,
- int frameNumber) {
+ long frameNumber) {
mRequest = request;
mReason = reason;
mDropped = dropped;
@@ -95,9 +95,9 @@
* for every new result or failure; and the scope is the lifetime of the
* {@link CameraDevice}.</p>
*
- * @return int frame number
+ * @return long frame number
*/
- public int getFrameNumber() {
+ public long getFrameNumber() {
return mFrameNumber;
}
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index a15028c..621968b 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -68,6 +68,8 @@
/** This session is closed; all further calls will throw ISE */
private boolean mClosed = false;
+ /** This session failed to be configured successfully */
+ private final boolean mConfigureSuccess;
/** Do not unconfigure if this is set; another session will overwrite configuration */
private boolean mSkipUnconfigure = false;
@@ -119,10 +121,12 @@
if (configureSuccess) {
mStateListener.onConfigured(this);
if (VERBOSE) Log.v(TAG, "ctor - Created session successfully");
+ mConfigureSuccess = true;
} else {
mStateListener.onConfigureFailed(this);
mClosed = true; // do not fire any other callbacks, do not allow any other work
Log.e(TAG, "Failed to create capture session; configuration failed");
+ mConfigureSuccess = false;
}
}
@@ -285,9 +289,9 @@
// - 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.
+ // configureOutputsChecked(null) has already been called.
//
- // Do not call configureOutputs(null) going forward, since it would race with the
+ // Do not call configureOutputsChecked(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;
@@ -506,7 +510,7 @@
public void onUnconfigured(CameraDevice camera) {
synchronized (session) {
// Ignore #onUnconfigured before #close is called
- if (mClosed) {
+ if (mClosed && mConfigureSuccess) {
mUnconfigureDrainer.taskFinished();
}
}
@@ -619,7 +623,7 @@
try {
mUnconfigureDrainer.taskStarted();
- mDeviceImpl.configureOutputs(null); // begin transition to unconfigured state
+ mDeviceImpl.configureOutputsChecked(null); // begin transition to unconfigured
} catch (CameraAccessException e) {
// OK: do not throw checked exceptions.
Log.e(TAG, "Exception while configuring outputs: ", e);
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 71eb0e9..79ce9df 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -312,10 +312,33 @@
}
public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
+ // Leave this here for backwards compatibility with older code using this directly
+ configureOutputsChecked(outputs);
+ }
+
+ /**
+ * Attempt to configure the outputs; the device goes to idle and then configures the
+ * new outputs if possible.
+ *
+ * <p>The configuration may gracefully fail, if there are too many outputs, if the formats
+ * are not supported, or if the sizes for that format is not supported. In this case this
+ * function will return {@code false} and the unconfigured callback will be fired.</p>
+ *
+ * <p>If the configuration succeeds (with 1 or more outputs), then the idle callback is fired.
+ * Unconfiguring the device always fires the idle callback.</p>
+ *
+ * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
+ * @return whether or not the configuration was successful
+ *
+ * @throws CameraAccessException if there were any unexpected problems during configuration
+ */
+ public boolean configureOutputsChecked(List<Surface> outputs) throws CameraAccessException {
// Treat a null input the same an empty list
if (outputs == null) {
outputs = new ArrayList<Surface>();
}
+ boolean success = false;
+
synchronized(mInterfaceLock) {
checkIfCameraClosedOrInError();
@@ -355,7 +378,17 @@
mConfiguredOutputs.put(streamId, s);
}
- mRemoteDevice.endConfigure();
+ try {
+ mRemoteDevice.endConfigure();
+ }
+ catch (IllegalArgumentException e) {
+ // OK. camera service can reject stream config if it's not supported by HAL
+ // This is only the result of a programmer misusing the camera2 api.
+ Log.e(TAG, "Stream configuration failed", e);
+ return false;
+ }
+
+ success = true;
} catch (CameraRuntimeException e) {
if (e.getReason() == CAMERA_IN_USE) {
throw new IllegalStateException("The camera is currently busy." +
@@ -365,15 +398,18 @@
throw e.asChecked();
} catch (RemoteException e) {
// impossible
- return;
- }
-
- if (outputs.size() > 0) {
- mDeviceHandler.post(mCallOnIdle);
- } else {
- mDeviceHandler.post(mCallOnUnconfigured);
+ return false;
+ } finally {
+ if (success && outputs.size() > 0) {
+ mDeviceHandler.post(mCallOnIdle);
+ } else {
+ // Always return to the 'unconfigured' state if we didn't hit a fatal error
+ mDeviceHandler.post(mCallOnUnconfigured);
+ }
}
}
+
+ return success;
}
@Override
@@ -397,7 +433,7 @@
boolean configureSuccess = true;
CameraAccessException pendingException = null;
try {
- configureOutputs(outputs); // and then block until IDLE
+ configureSuccess = configureOutputsChecked(outputs); // and then block until IDLE
} catch (CameraAccessException e) {
configureSuccess = false;
pendingException = e;
diff --git a/core/java/android/hardware/camera2/params/ColorSpaceTransform.java b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
index b4289db2..1e1c4b1 100644
--- a/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
@@ -225,7 +225,18 @@
}
if (obj instanceof ColorSpaceTransform) {
final ColorSpaceTransform other = (ColorSpaceTransform) obj;
- return Arrays.equals(mElements, other.mElements);
+ for (int i = 0, j = 0; i < COUNT; ++i, j += RATIONAL_SIZE) {
+ int numerator = mElements[j + OFFSET_NUMERATOR];
+ int denominator = mElements[j + OFFSET_DENOMINATOR];
+ int numeratorOther = other.mElements[j + OFFSET_NUMERATOR];
+ int denominatorOther = other.mElements[j + OFFSET_DENOMINATOR];
+ Rational r = new Rational(numerator, denominator);
+ Rational rOther = new Rational(numeratorOther, denominatorOther);
+ if (!r.equals(rOther)) {
+ return false;
+ }
+ }
+ return true;
}
return false;
}
@@ -238,5 +249,51 @@
return HashCodeHelpers.hashCode(mElements);
}
+ /**
+ * Return the color space transform as a string representation.
+ *
+ * <p> Example:
+ * {@code "ColorSpaceTransform([1/1, 0/1, 0/1], [0/1, 1/1, 0/1], [0/1, 0/1, 1/1])"} is an
+ * identity transform. Elements are printed in row major order. </p>
+ *
+ * @return string representation of color space transform
+ */
+ @Override
+ public String toString() {
+ return String.format("ColorSpaceTransform%s", toShortString());
+ }
+
+ /**
+ * Return the color space transform as a compact string representation.
+ *
+ * <p> Example:
+ * {@code "([1/1, 0/1, 0/1], [0/1, 1/1, 0/1], [0/1, 0/1, 1/1])"} is an identity transform.
+ * Elements are printed in row major order. </p>
+ *
+ * @return compact string representation of color space transform
+ */
+ private String toShortString() {
+ StringBuilder sb = new StringBuilder("(");
+ for (int row = 0, i = 0; row < ROWS; row++) {
+ sb.append("[");
+ for (int col = 0; col < COLUMNS; col++, i += RATIONAL_SIZE) {
+ int numerator = mElements[i + OFFSET_NUMERATOR];
+ int denominator = mElements[i + OFFSET_DENOMINATOR];
+ sb.append(numerator);
+ sb.append("/");
+ sb.append(denominator);
+ if (col < COLUMNS - 1) {
+ sb.append(", ");
+ }
+ }
+ sb.append("]");
+ if (row < ROWS - 1) {
+ sb.append(", ");
+ }
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
private final int[] mElements;
-};
+}
diff --git a/core/java/android/hardware/camera2/params/RggbChannelVector.java b/core/java/android/hardware/camera2/params/RggbChannelVector.java
index cf3e1de..e08ec55d 100644
--- a/core/java/android/hardware/camera2/params/RggbChannelVector.java
+++ b/core/java/android/hardware/camera2/params/RggbChannelVector.java
@@ -190,6 +190,32 @@
Float.floatToIntBits(mBlue);
}
+ /**
+ * Return the RggbChannelVector as a string representation.
+ *
+ * <p> {@code "RggbChannelVector{R:%f, G_even:%f, G_odd:%f, B:%f}"}, where each
+ * {@code %f} respectively represents one of the the four color channels. </p>
+ *
+ * @return string representation of {@link RggbChannelVector}
+ */
+ @Override
+ public String toString() {
+ return String.format("RggbChannelVector%s", toShortString());
+ }
+
+ /**
+ * Return the RggbChannelVector as a string in compact form.
+ *
+ * <p> {@code "{R:%f, G_even:%f, G_odd:%f, B:%f}"}, where each {@code %f}
+ * respectively represents one of the the four color channels. </p>
+ *
+ * @return compact string representation of {@link RggbChannelVector}
+ */
+ private String toShortString() {
+ return String.format("{R:%f, G_even:%f, G_odd:%f, B:%f}",
+ mRed, mGreenEven, mGreenOdd, mBlue);
+ }
+
private final float mRed;
private final float mGreenEven;
private final float mGreenOdd;
diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java
index f95ed0f..aba90e47 100644
--- a/core/java/android/hardware/hdmi/HdmiClient.java
+++ b/core/java/android/hardware/hdmi/HdmiClient.java
@@ -50,7 +50,7 @@
try {
mService.sendKeyEvent(getDeviceType(), keyCode, isPressed);
} catch (RemoteException e) {
- Log.e(TAG, "queryDisplayStatus threw exception ", e);
+ Log.e(TAG, "sendKeyEvent threw exception ", e);
}
}
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index 354c05e..c37fb5b 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -35,6 +35,11 @@
public final class HdmiTvClient extends HdmiClient {
private static final String TAG = "HdmiTvClient";
+ /**
+ * Size of MHL scratchpad register.
+ */
+ public static final int SCRATCHPAD_DATA_SIZE = 16;
+
HdmiTvClient(IHdmiControlService service) {
super(service);
}
@@ -80,6 +85,15 @@
}
}
+ private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
+ return new IHdmiControlCallback.Stub() {
+ @Override
+ public void onComplete(int result) {
+ callback.onComplete(result);
+ }
+ };
+ }
+
/**
* Select a HDMI port to be a new route path.
*
@@ -126,6 +140,15 @@
}
}
+ private static IHdmiInputChangeListener getListenerWrapper(final InputChangeListener listener) {
+ return new IHdmiInputChangeListener.Stub() {
+ @Override
+ public void onChanged(HdmiDeviceInfo info) {
+ listener.onChanged(info);
+ }
+ };
+ }
+
/**
* Set system audio volume
*
@@ -170,6 +193,38 @@
}
}
+ private static IHdmiRecordListener getListenerWrapper(final HdmiRecordListener callback) {
+ return new IHdmiRecordListener.Stub() {
+ @Override
+ public byte[] getOneTouchRecordSource(int recorderAddress) {
+ HdmiRecordSources.RecordSource source =
+ callback.getOneTouchRecordSource(recorderAddress);
+ if (source == null) {
+ return EmptyArray.BYTE;
+ }
+ byte[] data = new byte[source.getDataSize(true)];
+ source.toByteArray(true, data, 0);
+ return data;
+ }
+
+ @Override
+ public void onOneTouchRecordResult(int result) {
+ callback.onOneTouchRecordResult(result);
+ }
+
+ @Override
+ public void onTimerRecordingResult(int result) {
+ callback.onTimerRecordingResult(
+ HdmiRecordListener.TimerStatusData.parseFrom(result));
+ }
+
+ @Override
+ public void onClearTimerRecordingResult(int result) {
+ callback.onClearTimerRecordingResult(result);
+ }
+ };
+ }
+
/**
* Start one touch recording with the given recorder address and recorder source.
* <p>
@@ -276,53 +331,63 @@
}
}
- private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
- return new IHdmiControlCallback.Stub() {
+ /**
+ * Interface used to get incoming MHL scratchpad command.
+ */
+ public interface HdmiMhlScratchpadCommandListener {
+ void onReceived(int portId, int offset, int length, byte[] data);
+ }
+
+ /**
+ * Set {@link HdmiMhlScratchpadCommandListener} to get incoming MHL sSratchpad command.
+ *
+ * @param listener to receive incoming MHL Scratchpad command
+ */
+ public void setHdmiMhlScratchpadCommandListener(HdmiMhlScratchpadCommandListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null.");
+ }
+ try {
+ mService.addHdmiMhlScratchpadCommandListener(getListenerWrapper(listener));
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to set hdmi mhl scratchpad command listener: ", e);
+ }
+ }
+
+ private IHdmiMhlScratchpadCommandListener getListenerWrapper(
+ final HdmiMhlScratchpadCommandListener listener) {
+ return new IHdmiMhlScratchpadCommandListener.Stub() {
@Override
- public void onComplete(int result) {
- callback.onComplete(result);
+ public void onReceived(int portId, int offset, int length, byte[] data) {
+ listener.onReceived(portId, offset, length, data);
}
};
}
- private static IHdmiInputChangeListener getListenerWrapper(final InputChangeListener listener) {
- return new IHdmiInputChangeListener.Stub() {
- @Override
- public void onChanged(HdmiDeviceInfo info) {
- listener.onChanged(info);
- }
- };
- }
+ /**
+ * Send MHL Scratchpad command to the device connected to a port of the given portId.
+ *
+ * @param portId id of port to send MHL Scratchpad command
+ * @param offset offset in the in given data
+ * @param length length of data. offset + length should be bound to length of data.
+ * @param data container for Scratchpad data. It should be 16 bytes.
+ * @throws IllegalArgumentException if the given parameters are invalid
+ */
+ public void sendScratchpadCommand(int portId, int offset, int length, byte[] data) {
+ if (data == null || data.length != SCRATCHPAD_DATA_SIZE) {
+ throw new IllegalArgumentException("Invalid scratchpad data.");
+ }
+ if (offset < 0 || offset >= SCRATCHPAD_DATA_SIZE) {
+ throw new IllegalArgumentException("Invalid offset:" + offset);
+ }
+ if (length < 0 || offset + length > SCRATCHPAD_DATA_SIZE) {
+ throw new IllegalArgumentException("Invalid length:" + length);
+ }
- private static IHdmiRecordListener getListenerWrapper(final HdmiRecordListener callback) {
- return new IHdmiRecordListener.Stub() {
- @Override
- public byte[] getOneTouchRecordSource(int recorderAddress) {
- HdmiRecordSources.RecordSource source =
- callback.getOneTouchRecordSource(recorderAddress);
- if (source == null) {
- return EmptyArray.BYTE;
- }
- byte[] data = new byte[source.getDataSize(true)];
- source.toByteArray(true, data, 0);
- return data;
- }
-
- @Override
- public void onOneTouchRecordResult(int result) {
- callback.onOneTouchRecordResult(result);
- }
-
- @Override
- public void onTimerRecordingResult(int result) {
- callback.onTimerRecordingResult(
- HdmiRecordListener.TimerStatusData.parseFrom(result));
- }
-
- @Override
- public void onClearTimerRecordingResult(int result) {
- callback.onClearTimerRecordingResult(result);
- }
- };
+ try {
+ mService.sendScratchpadCommand(portId, offset, length, data);
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to send scratchpad command: ", e);
+ }
}
}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 17f290b..3bd45ed 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -22,6 +22,7 @@
import android.hardware.hdmi.IHdmiDeviceEventListener;
import android.hardware.hdmi.IHdmiHotplugEventListener;
import android.hardware.hdmi.IHdmiInputChangeListener;
+import android.hardware.hdmi.IHdmiMhlScratchpadCommandListener;
import android.hardware.hdmi.IHdmiRecordListener;
import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
import android.hardware.hdmi.IHdmiVendorCommandListener;
@@ -66,4 +67,6 @@
void stopOneTouchRecord(int recorderAddress);
void startTimerRecording(int recorderAddress, int sourceType, in byte[] recordSource);
void clearTimerRecording(int recorderAddress, int sourceType, in byte[] recordSource);
+ void sendScratchpadCommand(int portId, int offset, int length, in byte[] data);
+ void addHdmiMhlScratchpadCommandListener(IHdmiMhlScratchpadCommandListener listener);
}
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfoRequest.aidl b/core/java/android/hardware/hdmi/IHdmiMhlScratchpadCommandListener.aidl
similarity index 69%
rename from core/java/android/view/inputmethod/CursorAnchorInfoRequest.aidl
rename to core/java/android/hardware/hdmi/IHdmiMhlScratchpadCommandListener.aidl
index 41ef7cc6..4176597 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfoRequest.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiMhlScratchpadCommandListener.aidl
@@ -14,6 +14,14 @@
* limitations under the License.
*/
-package android.view.inputmethod;
+package android.hardware.hdmi;
-parcelable CursorAnchorInfoRequest;
+ /**
+ * Callback interface definition for MHL client to get the scratchpad
+ * command.
+ *
+ * @hide
+ */
+ oneway interface IHdmiMhlScratchpadCommandListener {
+ void onReceived(int portId, int offset, int length, in byte[] data);
+ }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ba811b7..2eb42a7 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -53,7 +53,6 @@
import android.view.animation.AnimationUtils;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CursorAnchorInfo;
-import android.view.inputmethod.CursorAnchorInfoRequest;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -1711,13 +1710,12 @@
}
/**
- * Called when the application has reported a new location of its text cursor. This is only
- * called if explicitly requested by the input method. The default implementation does nothing.
- * @param newCursor The new cursor position, in screen coordinates if the input method calls
- * {@link InputConnection#requestCursorAnchorInfo(CursorAnchorInfoRequest)} with
- * {@link CursorAnchorInfoRequest#FLAG_CURSOR_RECT_IN_SCREEN_COORDINATES}. Otherwise,
- * this is in local coordinates.
+ * Called when the application has reported a new location of its text
+ * cursor. This is only called if explicitly requested by the input method.
+ * The default implementation does nothing.
+ * @deprecated Use {#link onUpdateCursorAnchorInfo(CursorAnchorInfo)} instead.
*/
+ @Deprecated
public void onUpdateCursor(Rect newCursor) {
// Intentionally empty
}
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 0de3f26..d2a4728 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -16,10 +16,10 @@
package android.net;
-import android.net.NetworkBoundURLFactory;
import android.net.NetworkUtils;
import android.os.Parcelable;
import android.os.Parcel;
+import android.system.ErrnoException;
import java.io.IOException;
import java.net.InetAddress;
@@ -30,6 +30,7 @@
import java.net.SocketException;
import java.net.UnknownHostException;
import java.net.URL;
+import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.SocketFactory;
@@ -54,7 +55,7 @@
public final int netId;
// Objects used to perform per-network operations such as getSocketFactory
- // and getBoundURL, and a lock to protect access to them.
+ // and openConnection, and a lock to protect access to them.
private volatile NetworkBoundSocketFactory mNetworkBoundSocketFactory = null;
private volatile OkHttpClient mOkHttpClient = null;
private Object mLock = new Object();
@@ -157,12 +158,7 @@
@Override
public Socket createSocket() throws IOException {
Socket socket = new Socket();
- // Query a property of the underlying socket to ensure the underlying
- // socket exists so a file descriptor is available to bind to a network.
- socket.getReuseAddress();
- if (!NetworkUtils.bindSocketToNetwork(socket.getFileDescriptor$().getInt$(), mNetId)) {
- throw new SocketException("Failed to bind socket to network.");
- }
+ bindSocket(socket);
return socket;
}
}
@@ -187,73 +183,63 @@
return mNetworkBoundSocketFactory;
}
- /** The default NetworkBoundURLFactory, used if setNetworkBoundURLFactory is never called. */
- private static final NetworkBoundURLFactory DEFAULT_URL_FACTORY = new NetworkBoundURLFactory() {
- public URL getBoundURL(final Network network, URL url) throws MalformedURLException {
- if (network.mOkHttpClient == null) {
- synchronized (network.mLock) {
- if (network.mOkHttpClient == null) {
- HostResolver hostResolver = new HostResolver() {
- @Override
- public InetAddress[] getAllByName(String host)
- throws UnknownHostException {
- return network.getAllByName(host);
- }
- };
- network.mOkHttpClient = new OkHttpClient()
- .setSocketFactory(network.getSocketFactory())
- .setHostResolver(hostResolver);
- }
+ private void maybeInitHttpClient() {
+ if (mOkHttpClient == null) {
+ synchronized (mLock) {
+ if (mOkHttpClient == null) {
+ HostResolver hostResolver = new HostResolver() {
+ @Override
+ public InetAddress[] getAllByName(String host) throws UnknownHostException {
+ return Network.this.getAllByName(host);
+ }
+ };
+ mOkHttpClient = new OkHttpClient()
+ .setSocketFactory(getSocketFactory())
+ .setHostResolver(hostResolver);
}
}
-
- String protocol = url.getProtocol();
- URLStreamHandler handler = network.mOkHttpClient.createURLStreamHandler(protocol);
- if (handler == null) {
- // OkHttpClient only supports HTTP and HTTPS and returns a null URLStreamHandler if
- // passed another protocol.
- throw new MalformedURLException("Invalid URL or unrecognized protocol " + protocol);
- }
- return new URL(url, "", handler);
}
- };
-
- private static AtomicReference<NetworkBoundURLFactory> sNetworkBoundURLFactory =
- new AtomicReference <NetworkBoundURLFactory>(DEFAULT_URL_FACTORY);
-
- /**
- * Returns a {@link URL} based on the given URL but bound to this {@code Network},
- * such that opening the URL will send all network traffic on this Network.
- *
- * Note that if this {@code Network} ever disconnects, any URL object generated by this method
- * in the past or future will cease to work.
- *
- * The returned URL may have a {@link URLStreamHandler} explicitly set, which may not be the
- * handler generated by the factory set with {@link java.net.URL#setURLStreamHandlerFactory}. To
- * affect the {@code URLStreamHandler}s of URLs returned by this method, call
- * {@link #setNetworkBoundURLFactory}.
- *
- * Because the returned URLs may have an explicit {@code URLStreamHandler} set, using them as a
- * context when constructing other URLs and explicitly specifying a {@code URLStreamHandler} may
- * result in URLs that are no longer bound to the same {@code Network}.
- *
- * The default implementation only supports {@code HTTP} and {@code HTTPS} URLs.
- *
- * @return a {@link URL} bound to this {@code Network}.
- */
- public URL getBoundURL(URL url) throws MalformedURLException {
- return sNetworkBoundURLFactory.get().getBoundURL(this, url);
}
/**
- * Sets the {@link NetworkBoundURLFactory} to be used by future {@link #getBoundURL} calls.
- * If {@code null}, clears any factory that was previously specified.
+ * Opens the specified {@link URL} on this {@code Network}, such that all traffic will be sent
+ * on this Network. The URL protocol must be {@code HTTP} or {@code HTTPS}.
+ *
+ * @return a {@code URLConnection} to the resource referred to by this URL.
+ * @throws MalformedURLException if the URL protocol is not HTTP or HTTPS.
+ * @throws IOException if an error occurs while opening the connection.
+ * @see java.net.URL#openConnection()
*/
- public static void setNetworkBoundURLFactory(NetworkBoundURLFactory factory) {
- if (factory == null) {
- factory = DEFAULT_URL_FACTORY;
+ public URLConnection openConnection(URL url) throws IOException {
+ maybeInitHttpClient();
+ String protocol = url.getProtocol();
+ URLStreamHandler handler = mOkHttpClient.createURLStreamHandler(protocol);
+ if (handler == null) {
+ // OkHttpClient only supports HTTP and HTTPS and returns a null URLStreamHandler if
+ // passed another protocol.
+ throw new MalformedURLException("Invalid URL or unrecognized protocol " + protocol);
}
- sNetworkBoundURLFactory.set(factory);
+ return new URL(url, "", handler).openConnection();
+ }
+
+ /**
+ * Binds the specified {@link Socket} to this {@code Network}. All data traffic on the socket
+ * will be sent on this {@code Network}, irrespective of any process-wide network binding set by
+ * {@link ConnectivityManager#setProcessDefaultNetwork}. The socket must not be connected.
+ */
+ public void bindSocket(Socket socket) throws IOException {
+ if (socket.isConnected()) {
+ throw new SocketException("Socket is connected");
+ }
+ // Query a property of the underlying socket to ensure the underlying
+ // socket exists so a file descriptor is available to bind to a network.
+ socket.getReuseAddress();
+ int err = NetworkUtils.bindSocketToNetwork(socket.getFileDescriptor$().getInt$(), netId);
+ if (err != 0) {
+ // bindSocketToNetwork returns negative errno.
+ throw new ErrnoException("Binding socket to network " + netId, -err)
+ .rethrowAsSocketException();
+ }
}
// implement the Parcelable interface
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 54d8676..d2a2997 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -128,8 +128,9 @@
/**
* Explicitly binds {@code socketfd} to the network designated by {@code netId}. This
* overrides any binding via {@link #bindProcessToNetwork}.
+ * @return 0 on success or negative errno on failure.
*/
- public native static boolean bindSocketToNetwork(int socketfd, int netId);
+ public native static int bindSocketToNetwork(int socketfd, int netId);
/**
* Protect {@code socketfd} from VPN connections. After protecting, data sent through
diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java
index 1e1ad9e..afa5885 100644
--- a/core/java/android/os/FileBridge.java
+++ b/core/java/android/os/FileBridge.java
@@ -95,6 +95,10 @@
int len = Memory.peekInt(temp, 4, ByteOrder.BIG_ENDIAN);
while (len > 0) {
int n = IoBridge.read(mServer, temp, 0, Math.min(temp.length, len));
+ if (n == -1) {
+ throw new IOException(
+ "Unexpected EOF; still expected " + len + " bytes");
+ }
IoBridge.write(mTarget, temp, 0, n);
len -= n;
}
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
index 6246cbe..ebb1a5c 100644
--- a/core/java/android/transition/ChangeBounds.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -107,6 +107,8 @@
*
* @param reparent true if the transition should track the parent
* container of target views and animate parent changes.
+ * @deprecated Use {@link android.transition.ChangeTransform} to handle
+ * transitions between different parents.
*/
public void setReparent(boolean reparent) {
mReparent = reparent;
diff --git a/core/java/android/transition/ChangeImageTransform.java b/core/java/android/transition/ChangeImageTransform.java
index 4b230eb..d7a9120 100644
--- a/core/java/android/transition/ChangeImageTransform.java
+++ b/core/java/android/transition/ChangeImageTransform.java
@@ -16,7 +16,6 @@
package android.transition;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.content.Context;
@@ -196,28 +195,6 @@
private ObjectAnimator createMatrixAnimator(final ImageView imageView, Matrix startMatrix,
final Matrix endMatrix) {
return ObjectAnimator.ofObject(imageView, ANIMATED_TRANSFORM_PROPERTY,
- new MatrixEvaluator(), startMatrix, endMatrix);
+ new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix);
}
-
- private static class MatrixEvaluator implements TypeEvaluator<Matrix> {
-
- float[] mTempStartValues = new float[9];
-
- float[] mTempEndValues = new float[9];
-
- Matrix mTempMatrix = new Matrix();
-
- @Override
- public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) {
- startValue.getValues(mTempStartValues);
- endValue.getValues(mTempEndValues);
- for (int i = 0; i < 9; i++) {
- float diff = mTempEndValues[i] - mTempStartValues[i];
- mTempEndValues[i] = mTempStartValues[i] + (fraction * diff);
- }
- mTempMatrix.setValues(mTempEndValues);
- return mTempMatrix;
- }
- }
-
}
diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java
index e9be3b9..d579f54 100644
--- a/core/java/android/transition/ChangeTransform.java
+++ b/core/java/android/transition/ChangeTransform.java
@@ -16,72 +16,134 @@
package android.transition;
import android.animation.Animator;
-import android.animation.FloatArrayEvaluator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Matrix;
import android.util.AttributeSet;
-import android.util.FloatProperty;
import android.util.Property;
+import android.view.GhostView;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.R;
/**
* This Transition captures scale and rotation for Views before and after the
* scene change and animates those changes during the transition.
*
- * <p>ChangeTransform does not work when the pivot changes between scenes, so either the
- * pivot must be set to prevent automatic pivot adjustment or the View's size must be unchanged.</p>
+ * A change in parent is handled as well by capturing the transforms from
+ * the parent before and after the scene change and animating those during the
+ * transition.
*/
public class ChangeTransform extends Transition {
private static final String TAG = "ChangeTransform";
- private static final String PROPNAME_SCALE_X = "android:changeTransform:scaleX";
- private static final String PROPNAME_SCALE_Y = "android:changeTransform:scaleY";
- private static final String PROPNAME_ROTATION_X = "android:changeTransform:rotationX";
- private static final String PROPNAME_ROTATION_Y = "android:changeTransform:rotationY";
- private static final String PROPNAME_ROTATION_Z = "android:changeTransform:rotationZ";
- private static final String PROPNAME_PIVOT_X = "android:changeTransform:pivotX";
- private static final String PROPNAME_PIVOT_Y = "android:changeTransform:pivotY";
+ private static final String PROPNAME_MATRIX = "android:changeTransform:matrix";
+ private static final String PROPNAME_TRANSFORMS = "android:changeTransform:transforms";
+ private static final String PROPNAME_PARENT = "android:changeTransform:parent";
+ private static final String PROPNAME_PARENT_MATRIX = "android:changeTransform:parentMatrix";
private static final String[] sTransitionProperties = {
- PROPNAME_SCALE_X,
- PROPNAME_SCALE_Y,
- PROPNAME_ROTATION_X,
- PROPNAME_ROTATION_Y,
- PROPNAME_ROTATION_Z,
+ PROPNAME_MATRIX,
+ PROPNAME_TRANSFORMS,
+ PROPNAME_PARENT_MATRIX,
};
- private static final FloatProperty<View>[] sChangedProperties = new FloatProperty[] {
- (FloatProperty) View.SCALE_X,
- (FloatProperty) View.SCALE_Y,
- (FloatProperty) View.ROTATION_X,
- (FloatProperty) View.ROTATION_Y,
- (FloatProperty) View.ROTATION,
- };
-
- private static Property<View, float[]> TRANSFORMS = new Property<View, float[]>(float[].class,
- "transforms") {
- @Override
- public float[] get(View object) {
- return null;
- }
-
- @Override
- public void set(View view, float[] values) {
- for (int i = 0; i < values.length; i++) {
- float value = values[i];
- if (!Float.isNaN(value)) {
- sChangedProperties[i].setValue(view, value);
+ private static final Property<View, Matrix> ANIMATION_MATRIX_PROPERTY =
+ new Property<View, Matrix>(Matrix.class, "animationMatrix") {
+ @Override
+ public Matrix get(View object) {
+ return null;
}
- }
- }
- };
+
+ @Override
+ public void set(View object, Matrix value) {
+ object.setAnimationMatrix(value);
+ }
+ };
+
+ private boolean mUseOverlay = true;
+ private boolean mReparent = true;
+ private Matrix mTempMatrix = new Matrix();
public ChangeTransform() {}
public ChangeTransform(Context context, AttributeSet attrs) {
super(context, attrs);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChangeTransform);
+ mUseOverlay = a.getBoolean(R.styleable.ChangeTransform_reparentWithOverlay, true);
+ mReparent = a.getBoolean(R.styleable.ChangeTransform_reparent, true);
+ a.recycle();
+ }
+
+ /**
+ * Returns whether changes to parent should use an overlay or not. When the parent
+ * change doesn't use an overlay, it affects the transforms of the child. The
+ * default value is <code>true</code>.
+ *
+ * <p>Note: when Overlays are not used when a parent changes, a view can be clipped when
+ * it moves outside the bounds of its parent. Setting
+ * {@link android.view.ViewGroup#setClipChildren(boolean)} and
+ * {@link android.view.ViewGroup#setClipToPadding(boolean)} can help. Also, when
+ * Overlays are not used and the parent is animating its location, the position of the
+ * child view will be relative to its parent's final position, so it may appear to "jump"
+ * at the beginning.</p>
+ *
+ * @return <code>true</code> when a changed parent should execute the transition
+ * inside the scene root's overlay or <code>false</code> if a parent change only
+ * affects the transform of the transitioning view.
+ */
+ public boolean getReparentWithOverlay() {
+ return mUseOverlay;
+ }
+
+ /**
+ * Sets whether changes to parent should use an overlay or not. When the parent
+ * change doesn't use an overlay, it affects the transforms of the child. The
+ * default value is <code>true</code>.
+ *
+ * <p>Note: when Overlays are not used when a parent changes, a view can be clipped when
+ * it moves outside the bounds of its parent. Setting
+ * {@link android.view.ViewGroup#setClipChildren(boolean)} and
+ * {@link android.view.ViewGroup#setClipToPadding(boolean)} can help. Also, when
+ * Overlays are not used and the parent is animating its location, the position of the
+ * child view will be relative to its parent's final position, so it may appear to "jump"
+ * at the beginning.</p>
+ *
+ * @return <code>true</code> when a changed parent should execute the transition
+ * inside the scene root's overlay or <code>false</code> if a parent change only
+ * affects the transform of the transitioning view.
+ */
+ public void setReparentWithOverlay(boolean reparentWithOverlay) {
+ mUseOverlay = reparentWithOverlay;
+ }
+
+ /**
+ * Returns whether parent changes will be tracked by the ChangeTransform. If parent
+ * changes are tracked, then the transform will adjust to the transforms of the
+ * different parents. If they aren't tracked, only the transforms of the transitioning
+ * view will be tracked. Default is true.
+ *
+ * @return whether parent changes will be tracked by the ChangeTransform.
+ */
+ public boolean getReparent() {
+ return mReparent;
+ }
+
+ /**
+ * Sets whether parent changes will be tracked by the ChangeTransform. If parent
+ * changes are tracked, then the transform will adjust to the transforms of the
+ * different parents. If they aren't tracked, only the transforms of the transitioning
+ * view will be tracked. Default is true.
+ *
+ * @param reparent Set to true to track parent changes or false to only track changes
+ * of the transitioning view without considering the parent change.
+ */
+ public void setReparent(boolean reparent) {
+ mReparent = reparent;
}
@Override
@@ -89,19 +151,29 @@
return sTransitionProperties;
}
- private void captureValues(TransitionValues values) {
- View view = values.view;
+ private void captureValues(TransitionValues transitionValues) {
+ View view = transitionValues.view;
if (view.getVisibility() == View.GONE) {
return;
}
-
- values.values.put(PROPNAME_SCALE_X, view.getScaleX());
- values.values.put(PROPNAME_SCALE_Y, view.getScaleY());
- values.values.put(PROPNAME_PIVOT_X, view.getPivotX());
- values.values.put(PROPNAME_PIVOT_Y, view.getPivotY());
- values.values.put(PROPNAME_ROTATION_X, view.getRotationX());
- values.values.put(PROPNAME_ROTATION_Y, view.getRotationY());
- values.values.put(PROPNAME_ROTATION_Z, view.getRotation());
+ transitionValues.values.put(PROPNAME_PARENT, view.getParent());
+ Transforms transforms = new Transforms(view);
+ transitionValues.values.put(PROPNAME_TRANSFORMS, transforms);
+ Matrix matrix = view.getMatrix();
+ if (matrix == null || matrix.isIdentity()) {
+ matrix = null;
+ } else {
+ matrix = new Matrix(matrix);
+ }
+ transitionValues.values.put(PROPNAME_MATRIX, matrix);
+ if (mReparent) {
+ Matrix parentMatrix = new Matrix();
+ ViewGroup parent = (ViewGroup) view.getParent();
+ parent.transformMatrixToGlobal(parentMatrix);
+ parentMatrix.preTranslate(-parent.getScrollX(), -parent.getScrollY());
+ transitionValues.values.put(PROPNAME_PARENT_MATRIX, parentMatrix);
+ }
+ return;
}
@Override
@@ -115,57 +187,252 @@
}
@Override
- public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues,
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
- if (startValues == null || endValues == null
- || !startValues.values.containsKey(PROPNAME_SCALE_X)
- || !endValues.values.containsKey(PROPNAME_SCALE_X)
- || !isPivotSame(startValues, endValues)
- || !isChanged(startValues, endValues)) {
+ if (startValues == null || endValues == null ||
+ !startValues.values.containsKey(PROPNAME_PARENT) ||
+ !endValues.values.containsKey(PROPNAME_PARENT)) {
return null;
}
- float[] start = createValues(startValues);
- float[] end = createValues(endValues);
- for (int i = 0; i < start.length; i++) {
- if (start[i] == end[i]) {
- start[i] = Float.NaN;
- end[i] = Float.NaN;
- } else {
- sChangedProperties[i].setValue(endValues.view, start[i]);
+ ViewGroup startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
+ ViewGroup endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
+ boolean handleParentChange = mReparent && !parentsMatch(startParent, endParent);
+
+ Matrix startMatrix = (Matrix) startValues.view.getTag(R.id.transitionTransform);
+ if (startMatrix != null) {
+ startValues.values.put(PROPNAME_MATRIX, startMatrix);
+ }
+
+ Matrix startParentMatrix = (Matrix) startValues.view.getTag(R.id.parentMatrix);
+ if (startParentMatrix != null) {
+ startValues.values.put(PROPNAME_PARENT_MATRIX, startParentMatrix);
+ }
+
+ // First handle the parent change:
+ if (handleParentChange) {
+ setMatricesForParent(startValues, endValues);
+ }
+
+ // Next handle the normal matrix transform:
+ ObjectAnimator transformAnimator = createTransformAnimator(startValues, endValues);
+
+ if (handleParentChange && transformAnimator != null && mUseOverlay) {
+ createGhostView(sceneRoot, startValues, endValues);
+ }
+
+ return transformAnimator;
+ }
+
+ private ObjectAnimator createTransformAnimator(TransitionValues startValues,
+ TransitionValues endValues) {
+ Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
+ Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
+
+ if (startMatrix == null) {
+ startMatrix = Matrix.IDENTITY_MATRIX;
+ }
+
+ if (endMatrix == null) {
+ endMatrix = Matrix.IDENTITY_MATRIX;
+ }
+
+ if (startMatrix.equals(endMatrix)) {
+ return null;
+ }
+
+ final Transforms transforms = (Transforms) endValues.values.get(PROPNAME_TRANSFORMS);
+
+ // clear the transform properties so that we can use the animation matrix instead
+ final View view = endValues.view;
+ setIdentityTransforms(view);
+
+ ObjectAnimator animator = ObjectAnimator.ofObject(view, ANIMATION_MATRIX_PROPERTY,
+ new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix);
+
+ AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+ private boolean mIsCanceled;
+ private Matrix mTempMatrix;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mIsCanceled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mIsCanceled) {
+ view.setTagInternal(R.id.transitionTransform, null);
+ view.setTagInternal(R.id.parentMatrix, null);
+ }
+ ANIMATION_MATRIX_PROPERTY.set(view, null);
+ transforms.restore(view);
+ }
+
+ @Override
+ public void onAnimationPause(Animator animation) {
+ ValueAnimator animator = (ValueAnimator) animation;
+ Matrix currentMatrix = (Matrix) animator.getAnimatedValue();
+ if (mTempMatrix == null) {
+ mTempMatrix = new Matrix(currentMatrix);
+ } else {
+ mTempMatrix.set(currentMatrix);
+ }
+ view.setTagInternal(R.id.transitionTransform, mTempMatrix);
+ transforms.restore(view);
+ }
+
+ @Override
+ public void onAnimationResume(Animator animation) {
+ setIdentityTransforms(view);
+ }
+ };
+
+ animator.addListener(listener);
+ animator.addPauseListener(listener);
+ return animator;
+ }
+
+ private boolean parentsMatch(ViewGroup startParent, ViewGroup endParent) {
+ boolean parentsMatch = false;
+ if (!isValidTarget(startParent) || !isValidTarget(endParent)) {
+ parentsMatch = startParent == endParent;
+ } else {
+ TransitionValues endValues = getMatchedTransitionValues(startParent, true);
+ if (endValues != null) {
+ parentsMatch = endParent == endValues.view;
}
}
- FloatArrayEvaluator evaluator = new FloatArrayEvaluator(new float[start.length]);
- return ObjectAnimator.ofObject(endValues.view, TRANSFORMS, evaluator, start, end);
+ return parentsMatch;
}
- private static float[] createValues(TransitionValues transitionValues) {
- float[] values = new float[sChangedProperties.length];
- for (int i = 0; i < values.length; i++) {
- values[i] = (Float) transitionValues.values.get(sTransitionProperties[i]);
+ private void createGhostView(final ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ View view = endValues.view;
+
+ Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_PARENT_MATRIX);
+ Matrix localEndMatrix = new Matrix(endMatrix);
+ sceneRoot.transformMatrixToLocal(localEndMatrix);
+
+ GhostView ghostView = GhostView.addGhost(view, sceneRoot, localEndMatrix);
+
+ Transition outerTransition = this;
+ while (outerTransition.mParent != null) {
+ outerTransition = outerTransition.mParent;
}
- return values;
+ GhostListener listener = new GhostListener(view, ghostView, endMatrix);
+ outerTransition.addListener(listener);
+
+ if (startValues.view != endValues.view) {
+ startValues.view.setTransitionAlpha(0);
+ }
+ view.setTransitionAlpha(1);
}
- private static boolean isPivotSame(TransitionValues startValues, TransitionValues endValues) {
- float startPivotX = (Float) startValues.values.get(PROPNAME_PIVOT_X);
- float startPivotY = (Float) startValues.values.get(PROPNAME_PIVOT_Y);
- float endPivotX = (Float) endValues.values.get(PROPNAME_PIVOT_X);
- float endPivotY = (Float) endValues.values.get(PROPNAME_PIVOT_Y);
+ private void setMatricesForParent(TransitionValues startValues, TransitionValues endValues) {
+ Matrix endParentMatrix = (Matrix) endValues.values.get(PROPNAME_PARENT_MATRIX);
+ endValues.view.setTagInternal(R.id.parentMatrix, endParentMatrix);
- // We don't support pivot changes, because they could be automatically set
- // and we can't end the state in an automatic state.
- return startPivotX == endPivotX && startPivotY == endPivotY;
+ Matrix toLocal = mTempMatrix;
+ toLocal.reset();
+ endParentMatrix.invert(toLocal);
+
+ Matrix startLocal = (Matrix) startValues.values.get(PROPNAME_MATRIX);
+ if (startLocal == null) {
+ startLocal = new Matrix();
+ startValues.values.put(PROPNAME_MATRIX, startLocal);
+ }
+
+ Matrix startParentMatrix = (Matrix) startValues.values.get(PROPNAME_PARENT_MATRIX);
+ startLocal.postConcat(startParentMatrix);
+ startLocal.postConcat(toLocal);
}
- private static boolean isChanged(TransitionValues startValues, TransitionValues endValues) {
- for (int i = 0; i < sChangedProperties.length; i++) {
- Object start = startValues.values.get(sTransitionProperties[i]);
- Object end = endValues.values.get(sTransitionProperties[i]);
- if (!start.equals(end)) {
- return true;
+ private static void setIdentityTransforms(View view) {
+ setTransforms(view, 0, 0, 0, 1, 1, 0, 0, 0);
+ }
+
+ private static void setTransforms(View view, float translationX, float translationY,
+ float translationZ, float scaleX, float scaleY, float rotationX,
+ float rotationY, float rotationZ) {
+ view.setTranslationX(translationX);
+ view.setTranslationY(translationY);
+ view.setTranslationZ(translationZ);
+ view.setScaleX(scaleX);
+ view.setScaleY(scaleY);
+ view.setRotationX(rotationX);
+ view.setRotationY(rotationY);
+ view.setRotation(rotationZ);
+ }
+
+ private static class Transforms {
+ public final float translationX;
+ public final float translationY;
+ public final float translationZ;
+ public final float scaleX;
+ public final float scaleY;
+ public final float rotationX;
+ public final float rotationY;
+ public final float rotationZ;
+
+ public Transforms(View view) {
+ translationX = view.getTranslationX();
+ translationY = view.getTranslationY();
+ translationZ = view.getTranslationZ();
+ scaleX = view.getScaleX();
+ scaleY = view.getScaleY();
+ rotationX = view.getRotationX();
+ rotationY = view.getRotationY();
+ rotationZ = view.getRotation();
+ }
+
+ public void restore(View view) {
+ setTransforms(view, translationX, translationY, translationZ, scaleX, scaleY,
+ rotationX, rotationY, rotationZ);
+ }
+
+ @Override
+ public boolean equals(Object that) {
+ if (!(that instanceof Transforms)) {
+ return false;
}
+ Transforms thatTransform = (Transforms) that;
+ return thatTransform.translationX == translationX &&
+ thatTransform.translationY == translationY &&
+ thatTransform.translationZ == translationZ &&
+ thatTransform.scaleX == scaleX &&
+ thatTransform.scaleY == scaleY &&
+ thatTransform.rotationX == rotationX &&
+ thatTransform.rotationY == rotationY &&
+ thatTransform.rotationZ == rotationZ;
}
- return false;
+ }
+
+ private static class GhostListener extends Transition.TransitionListenerAdapter {
+ private View mView;
+ private GhostView mGhostView;
+ private Matrix mEndMatrix;
+
+ public GhostListener(View view, GhostView ghostView, Matrix endMatrix) {
+ mView = view;
+ mGhostView = ghostView;
+ mEndMatrix = endMatrix;
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ transition.removeListener(this);
+ GhostView.removeGhost(mView);
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ mGhostView.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ mGhostView.setVisibility(View.VISIBLE);
+ }
}
}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 0d32d40..59ba71f 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -112,8 +112,8 @@
*
* Further information on XML resource descriptions for transitions can be found for
* {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
- * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade}, and
- * {@link android.R.styleable#Slide}.
+ * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade},
+ * {@link android.R.styleable#Slide}, and {@link android.R.styleable#ChangeTransform}.
*
*/
public abstract class Transition implements Cloneable {
@@ -1755,24 +1755,40 @@
// if oldValues null, then transition didn't care to stash values,
// and won't get canceled
if (oldValues != null && newValues != null) {
- for (String key : oldValues.values.keySet()) {
- Object oldValue = oldValues.values.get(key);
- Object newValue = newValues.values.get(key);
- if (oldValue != null && newValue != null &&
- !oldValue.equals(newValue)) {
- valuesChanged = true;
- if (DBG) {
- Log.d(LOG_TAG, "Transition.playTransition: " +
- "oldValue != newValue for " + key +
- ": old, new = " + oldValue + ", " + newValue);
+ String[] properties = getTransitionProperties();
+ if (properties != null) {
+ int count = properties.length;
+ for (int i = 0; i < count; i++) {
+ if (isValueChanged(oldValues, newValues, properties[i])) {
+ valuesChanged = true;
+ break;
}
- break;
+ }
+ } else {
+ for (String key : oldValues.values.keySet()) {
+ if (isValueChanged(oldValues, newValues, key)) {
+ valuesChanged = true;
+ break;
+ }
}
}
}
return valuesChanged;
}
+ private static boolean isValueChanged(TransitionValues oldValues, TransitionValues newValues,
+ String key) {
+ Object oldValue = oldValues.values.get(key);
+ Object newValue = newValues.values.get(key);
+ boolean changed = (oldValue != null && newValue != null && !oldValue.equals(newValue));
+ if (DBG && changed) {
+ Log.d(LOG_TAG, "Transition.playTransition: " +
+ "oldValue != newValue for " + key +
+ ": old, new = " + oldValue + ", " + newValue);
+ }
+ return changed;
+ }
+
/**
* This is a utility method used by subclasses to handle standard parts of
* setting up and running an Animator: it sets the {@link #getDuration()
diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java
index 931d46a..b0c9e9a 100644
--- a/core/java/android/transition/TransitionUtils.java
+++ b/core/java/android/transition/TransitionUtils.java
@@ -18,6 +18,8 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
+import android.animation.TypeEvaluator;
+import android.graphics.Matrix;
/**
* Static utility methods for Transitions.
@@ -37,4 +39,25 @@
return animatorSet;
}
}
+
+ public static class MatrixEvaluator implements TypeEvaluator<Matrix> {
+
+ float[] mTempStartValues = new float[9];
+
+ float[] mTempEndValues = new float[9];
+
+ Matrix mTempMatrix = new Matrix();
+
+ @Override
+ public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) {
+ startValue.getValues(mTempStartValues);
+ endValue.getValues(mTempEndValues);
+ for (int i = 0; i < 9; i++) {
+ float diff = mTempEndValues[i] - mTempStartValues[i];
+ mTempEndValues[i] = mTempStartValues[i] + (fraction * diff);
+ }
+ mTempMatrix.setValues(mTempEndValues);
+ return mTempMatrix;
+ }
+ }
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 79dbb49..81c69d1 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -63,8 +63,6 @@
private static final String[] sTransitionProperties = {
PROPNAME_VISIBILITY,
- PROPNAME_PARENT,
- PROPNAME_SCREEN_LOCATION,
};
private static class VisibilityInfo {
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index a56d448..9433237 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
+import android.animation.Animator.AnimatorListener;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
@@ -202,7 +203,7 @@
mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
}
- final ArrayList<AnimatorListener> listeners = getListeners();
+ final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationStart(this);
@@ -220,7 +221,7 @@
getHelper().removeDelayedAnimation(this);
nEnd(mNativePtr.get());
- final ArrayList<AnimatorListener> listeners = getListeners();
+ final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationCancel(this);
@@ -329,13 +330,22 @@
protected void onFinished() {
mFinished = true;
- final ArrayList<AnimatorListener> listeners = getListeners();
+ final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationEnd(this);
}
}
+ @SuppressWarnings("unchecked")
+ private ArrayList<AnimatorListener> cloneListeners() {
+ ArrayList<AnimatorListener> listeners = getListeners();
+ if (listeners != null) {
+ listeners = (ArrayList<AnimatorListener>) listeners.clone();
+ }
+ return listeners;
+ }
+
long getNativeAnimator() {
return mNativePtr.get();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 243d7d7..6f58582 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10793,6 +10793,15 @@
}
}
+ /** @hide */
+ public void setAnimationMatrix(Matrix matrix) {
+ invalidateViewProperty(true, false);
+ mRenderNode.setAnimationMatrix(matrix);
+ invalidateViewProperty(false, true);
+
+ invalidateParentIfNeededAndWasQuickRejected();
+ }
+
/**
* Returns the current StateListAnimator if exists.
*
@@ -13090,6 +13099,10 @@
removeSendViewScrolledAccessibilityEventCallback();
stopNestedScroll();
+ // Anything that started animating right before detach should already
+ // be in its final state when re-attached.
+ jumpDrawablesToCurrentState();
+
destroyDrawingCache();
cleanupDraw();
diff --git a/core/java/android/view/ViewAnimationUtils.java b/core/java/android/view/ViewAnimationUtils.java
index eeff90a..7ced088 100644
--- a/core/java/android/view/ViewAnimationUtils.java
+++ b/core/java/android/view/ViewAnimationUtils.java
@@ -26,7 +26,7 @@
public final class ViewAnimationUtils {
private ViewAnimationUtils() {}
/**
- * Returns a ValueAnimator which can animate a clipping circle.
+ * Returns an Animator which can animate a clipping circle.
*
* Any shadow cast by the View will respect the circular clip from this animator.
*
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index e7b3152..2c7ea3e 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1662,6 +1662,27 @@
public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) { }
/**
+ * Returns <code>true</code> when shared elements should use an Overlay during
+ * shared element transitions or <code>false</code> when they should animate as
+ * part of the normal View hierarchy. The default value is true.
+ *
+ * @return <code>true</code> when shared elements should use an Overlay during
+ * shared element transitions or <code>false</code> when they should animate as
+ * part of the normal View hierarchy.
+ */
+ public boolean getSharedElementsUseOverlay() { return true; }
+
+ /**
+ * Sets whether or not shared elements should use an Overlay during shared element transitions.
+ * The default value is true.
+ *
+ * @param sharedElementsUseOverlay <code>true</code> indicates that shared elements should
+ * be transitioned with an Overlay or <code>false</code>
+ * to transition within the normal View hierarchy.
+ */
+ public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) { }
+
+ /**
* @return the color of the status bar.
*/
public abstract int getStatusBarColor();
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 8cae27b..4d2f57a 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -429,25 +429,10 @@
}
/**
- * The default implementation is responsible for handling
- * {@link CursorAnchorInfoRequest#TYPE_CURSOR_RECT}. In fact, for derived classes, calling
- * {@code super.requestCursorAnchorInfo(request)} is the only way to handle
- * {@link CursorAnchorInfoRequest#TYPE_CURSOR_RECT}.
+ * The default implementation does nothing.
*/
- public int requestCursorAnchorInfo(CursorAnchorInfoRequest request) {
- // This implementation supports TYPE_CURSOR_RECT only.
- if (request == null ||
- request.getRequestType() != CursorAnchorInfoRequest.TYPE_CURSOR_RECT) {
- return CursorAnchorInfoRequest.RESULT_NOT_HANDLED;
- }
- if (mIMM == null) {
- // In this case, TYPE_CURSOR_RECT is not handled.
- // TODO: Return some notification code for the input method that indicates
- // Cursor rect information is temporarily unavailable.
- return CursorAnchorInfoRequest.RESULT_NOT_HANDLED;
- }
- mIMM.setCursorRectMonitorMode(request.getRequestFlags());
- return CursorAnchorInfoRequest.RESULT_SCHEDULED;
+ public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
+ return false;
}
/**
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfoRequest.java b/core/java/android/view/inputmethod/CursorAnchorInfoRequest.java
deleted file mode 100644
index e4c94f2..0000000
--- a/core/java/android/view/inputmethod/CursorAnchorInfoRequest.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * 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.view.inputmethod;
-
-import android.inputmethodservice.InputMethodService;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.view.View;
-
-/**
- * Used to enable or disable event notification for
- * {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)}. This class is also used to
- * enable {@link InputMethodService#onUpdateCursor(android.graphics.Rect)} for existing editors
- * that have not supported {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)}.
- */
-public final class CursorAnchorInfoRequest implements Parcelable {
- private final int mRequestType;
- private final int mRequestFlags;
-
- /**
- * Not handled by the editor.
- */
- public static final int RESULT_NOT_HANDLED = 0x00;
- /**
- * Request is scheduled in the editor task queue.
- */
- public static final int RESULT_SCHEDULED = 0x01;
-
- /**
- * The request is for {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)}.
- * This mechanism is powerful enough to retrieve fine-grained positional information of
- * characters in the editor.
- */
- public static final int TYPE_CURSOR_ANCHOR_INFO = 0x01;
- /**
- * The editor is requested to call
- * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)}
- * whenever cursor/anchor position is changed. To disable monitoring, call
- * {@link InputConnection#requestCursorAnchorInfo(CursorAnchorInfoRequest)} again with
- * {@link #TYPE_CURSOR_ANCHOR_INFO} and this flag off.
- * <p>
- * This flag can be used together with {@link #FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE}.
- * </p>
- */
- public static final int FLAG_CURSOR_ANCHOR_INFO_MONITOR = 0x01;
- /**
- * The editor is requested to call
- * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} at
- * once, as soon as possible, regardless of cursor/anchor position changes. This flag can be
- * used together with {@link #FLAG_CURSOR_ANCHOR_INFO_MONITOR}.
- */
- public static final int FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE = 0x02;
-
- /**
- * The request is for {@link InputMethodService#onUpdateCursor(android.graphics.Rect)}. This
- * mechanism has been available since API Level 3 (CUPCAKE) but only the cursor rectangle can
- * be retrieved with this mechanism.
- */
- public static final int TYPE_CURSOR_RECT = 0x02;
- /**
- * The editor is requested to call
- * {@link InputMethodManager#updateCursor(android.view.View, int, int, int, int)}
- * whenever the cursor position is changed. To disable monitoring, call
- * {@link InputConnection#requestCursorAnchorInfo(CursorAnchorInfoRequest)} again with
- * {@link #TYPE_CURSOR_RECT} and this flag off.
- * <p>
- * This flag can be used together with {@link #FLAG_CURSOR_RECT_IN_SCREEN_COORDINATES}.
- * </p>
- */
- public static final int FLAG_CURSOR_RECT_MONITOR = 0x01;
- /**
- * {@link InputMethodManager#updateCursor(android.view.View, int, int, int, int)} should be
- * called back in screen coordinates. To receive cursor position in local coordinates, call
- * {@link InputConnection#requestCursorAnchorInfo(CursorAnchorInfoRequest)} again with
- * {@link #TYPE_CURSOR_RECT} and this flag off.
- */
- public static final int FLAG_CURSOR_RECT_IN_SCREEN_COORDINATES = 0x02;
- /**
- * {@link InputMethodManager#updateCursor(android.view.View, int, int, int, int)} should be
- * called back in screen coordinates after coordinate conversion with {@link View#getMatrix()}.
- * To disable coordinate conversion with {@link View#getMatrix()} again, call
- * {@link InputConnection#requestCursorAnchorInfo(CursorAnchorInfoRequest)} with
- * {@link #TYPE_CURSOR_RECT} and this flag off.
- *
- * <p>
- * The flag is ignored if {@link #FLAG_CURSOR_RECT_IN_SCREEN_COORDINATES} is off.
- * </p>
- */
- public static final int FLAG_CURSOR_RECT_WITH_VIEW_MATRIX = 0x04;
-
- /**
- * Constructs the object with request type and type-specific flags.
- *
- * @param requestType the type of this request. Currently {@link #TYPE_CURSOR_ANCHOR_INFO} or
- * {@link #TYPE_CURSOR_RECT} is supported.
- * @param requestFlags the flags for the given request type.
- */
- public CursorAnchorInfoRequest(int requestType, int requestFlags) {
- mRequestType = requestType;
- mRequestFlags = requestFlags;
- }
-
- /**
- * Used to make this class parcelable.
- *
- * @param source the parcel from which the object is unmarshalled.
- */
- public CursorAnchorInfoRequest(Parcel source) {
- mRequestType = source.readInt();
- mRequestFlags = source.readInt();
- }
-
- /**
- * @return the type of this request.
- */
- public int getRequestType() {
- return mRequestType;
- }
-
- /**
- * @return the flags that are specific to the type of this request.
- */
- public int getRequestFlags() {
- return mRequestFlags;
- }
-
- /**
- * Used to package this object into a {@link Parcel}.
- *
- * @param dest The {@link Parcel} to be written.
- * @param flags The flags used for parceling.
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mRequestType);
- dest.writeInt(mRequestFlags);
- }
-
- @Override
- public int hashCode(){
- return mRequestType * 31 + mRequestFlags;
- }
-
- @Override
- public boolean equals(Object obj){
- if (obj == null) {
- return false;
- }
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof CursorAnchorInfoRequest)) {
- return false;
- }
- final CursorAnchorInfoRequest that = (CursorAnchorInfoRequest) obj;
- if (hashCode() != that.hashCode()) {
- return false;
- }
- return mRequestType != that.mRequestType && mRequestFlags == that.mRequestFlags;
- }
-
- @Override
- public String toString() {
- return "CursorAnchorInfoRequest{mRequestType=" + mRequestType
- + " mRequestFlags=" + mRequestFlags
- + "}";
- }
-
- /**
- * Used to make this class parcelable.
- */
- public static final Parcelable.Creator<CursorAnchorInfoRequest> CREATOR =
- new Parcelable.Creator<CursorAnchorInfoRequest>() {
- @Override
- public CursorAnchorInfoRequest createFromParcel(Parcel source) {
- return new CursorAnchorInfoRequest(source);
- }
-
- @Override
- public CursorAnchorInfoRequest[] newArray(int size) {
- return new CursorAnchorInfoRequest[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-}
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index dff91dc..ca094c1 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -725,13 +725,34 @@
public boolean performPrivateCommand(String action, Bundle data);
/**
- * Called by the IME to ask the editor for calling back
+ * The editor is requested to call
+ * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} at
+ * once, as soon as possible, regardless of cursor/anchor position changes. This flag can be
+ * used together with {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR}.
+ */
+ public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE = 1 << 0;
+
+ /**
+ * The editor is requested to call
+ * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)}
+ * whenever cursor/anchor position is changed. To disable monitoring, call
+ * {@link InputConnection#requestUpdateCursorAnchorInfo(int)} again with this flag off.
+ * <p>
+ * This flag can be used together with {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE}.
+ * </p>
+ */
+ public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR = 1 << 1;
+
+ /**
+ * Called by the input method to ask the editor for calling back
* {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)} to
* notify cursor/anchor locations.
*
- * @param request the details of the request.
- * @return a result code that depends on {@link CursorAnchorInfoRequest#getRequestType()}. See
- * {@link CursorAnchorInfoRequest} for details.
+ * @param cursorUpdateMode {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE} and/or
+ * {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR}
+ * @return {@code true} if the request is scheduled. {@code false} to indicate that when the
+ * application will not call
+ * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)}.
*/
- public int requestCursorAnchorInfo(CursorAnchorInfoRequest request);
+ public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode);
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index c831d7c..d95df25 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -126,7 +126,7 @@
return mTarget.performPrivateCommand(action, data);
}
- public int requestCursorAnchorInfo(CursorAnchorInfoRequest request) {
- return mTarget.requestCursorAnchorInfo(request);
+ public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
+ return mTarget.requestUpdateCursorAnchorInfo(cursorUpdateMode);
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index eec3570..0a472c7 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -313,9 +313,8 @@
CompletionInfo[] mCompletions;
// Cursor position on the screen.
- Rect mNextCursorRect = new Rect();
+ Rect mTmpCursorRect = new Rect();
Rect mCursorRect = new Rect();
- RectF mTempRectF = new RectF();
int mCursorSelStart;
int mCursorSelEnd;
int mCursorCandStart;
@@ -372,28 +371,12 @@
InputChannel mCurChannel;
ImeInputEventSender mCurSender;
- private static final int CURSOR_RECT_MONITOR_MODE_NONE = 0x0;
-
- private static final int CURSOR_RECT_MONITOR_FLAG_MASK =
- CursorAnchorInfoRequest.FLAG_CURSOR_RECT_MONITOR |
- CursorAnchorInfoRequest.FLAG_CURSOR_RECT_IN_SCREEN_COORDINATES |
- CursorAnchorInfoRequest.FLAG_CURSOR_RECT_WITH_VIEW_MATRIX;
-
- private static final int CURSOR_ANCHOR_INFO_MONITOR_MODE_NONE = 0x0;
-
- private static final int CURSOR_ANCHOR_INFO_MONITOR_FLAG_MASK =
- CursorAnchorInfoRequest.FLAG_CURSOR_ANCHOR_INFO_MONITOR |
- CursorAnchorInfoRequest.FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE;
-
- /**
- * The monitor mode for {@link #updateCursor(View, int, int, int, int)}.
- */
- private int mCursorRectMonitorMode = CURSOR_RECT_MONITOR_MODE_NONE;
+ private static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE = 0x0;
/**
* The monitor mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}.
*/
- private int mCursorAnchorInfoMonitorMode = CURSOR_ANCHOR_INFO_MONITOR_MODE_NONE;
+ private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
final Pool<PendingEvent> mPendingEventPool = new SimplePool<PendingEvent>(20);
final SparseArray<PendingEvent> mPendingEvents = new SparseArray<PendingEvent>(20);
@@ -446,8 +429,8 @@
return;
}
- mCursorAnchorInfoMonitorMode = CURSOR_ANCHOR_INFO_MONITOR_MODE_NONE;
- mCursorRectMonitorMode = CURSOR_RECT_MONITOR_MODE_NONE;
+ mRequestUpdateCursorAnchorInfoMonitorMode =
+ REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
setInputChannelLocked(res.channel);
mCurMethod = res.method;
@@ -1540,59 +1523,49 @@
}
/**
- * Returns true if the current input method wants to watch the location
+ * Return true if the current input method wants to watch the location
* of the input editor's cursor in its window.
- */
- public boolean isWatchingCursor(View view) {
- if (!isActive(view)) {
- return false;
- }
- synchronized (mH) {
- return (mCursorRectMonitorMode & CursorAnchorInfoRequest.FLAG_CURSOR_RECT_MONITOR) != 0;
- }
- }
-
- /**
- * Updates the result of {@link #isWatchingCursor(View)}.
*
- * @hide
+ * @deprecated Use {@link InputConnection#requestUpdateCursorAnchorInfo(int)} instead.
*/
- public void setCursorRectMonitorMode(int flags) {
- synchronized (mH) {
- mCursorRectMonitorMode = (CURSOR_RECT_MONITOR_FLAG_MASK & flags);
- }
+ @Deprecated
+ public boolean isWatchingCursor(View view) {
+ return false;
}
/**
- * Returns true if the current input method wants to be notified when cursor/anchor location
+ * Return true if the current input method wants to be notified when cursor/anchor location
* is changed.
*
* @hide
*/
public boolean isCursorAnchorInfoEnabled() {
synchronized (mH) {
- final boolean isImmediate = (mCursorAnchorInfoMonitorMode &
- CursorAnchorInfoRequest.FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0;
- final boolean isMonitoring = (mCursorAnchorInfoMonitorMode &
- CursorAnchorInfoRequest.FLAG_CURSOR_ANCHOR_INFO_MONITOR) != 0;
+ final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode &
+ InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0;
+ final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode &
+ InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR) != 0;
return isImmediate || isMonitoring;
}
}
/**
- * Updates the result of {@link #isWatchingCursor(View)}.
+ * Set the requested mode for {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}.
*
* @hide
*/
- public void setCursorAnchorInfoMonitorMode(int flags) {
+ public void setUpdateCursorAnchorInfoMode(int flags) {
synchronized (mH) {
- mCursorAnchorInfoMonitorMode = (CURSOR_ANCHOR_INFO_MONITOR_FLAG_MASK & flags);
+ mRequestUpdateCursorAnchorInfoMonitorMode = flags;
}
}
/**
* Report the current cursor location in its window.
+ *
+ * @deprecated Use {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)} instead.
*/
+ @Deprecated
public void updateCursor(View view, int left, int top, int right, int bottom) {
checkFocus();
synchronized (mH) {
@@ -1601,33 +1574,15 @@
|| mCurrentTextBoxAttribute == null || mCurMethod == null) {
return;
}
- if (DEBUG) Log.d(TAG, "updateCursor");
- final boolean usesScreenCoordinates = (mCursorRectMonitorMode &
- CursorAnchorInfoRequest.FLAG_CURSOR_RECT_IN_SCREEN_COORDINATES) != 0;
- if (usesScreenCoordinates) {
- view.getLocationOnScreen(mViewTopLeft);
- final Matrix viewMatrix = view.getMatrix();
- final boolean usesViewMatrix = (viewMatrix != null) && ((mCursorRectMonitorMode &
- CursorAnchorInfoRequest.FLAG_CURSOR_RECT_WITH_VIEW_MATRIX) != 0);
- if (usesViewMatrix) {
- mTempRectF.set(left, top, right, bottom);
- mViewToScreenMatrix.set(viewMatrix);
- mViewToScreenMatrix.postTranslate(mViewTopLeft[0], mViewTopLeft[1]);
- mViewToScreenMatrix.mapRect(mTempRectF);
- mNextCursorRect.set((int)mTempRectF.left, (int)mTempRectF.top,
- (int)mTempRectF.right, (int)mTempRectF.bottom);
- } else {
- mNextCursorRect.set(left + mViewTopLeft[0], top + mViewTopLeft[1],
- right + mViewTopLeft[0], bottom + mViewTopLeft[1]);
- }
- } else {
- mNextCursorRect.set(left, top, right, bottom);
- }
- if (!Objects.equals(mCursorRect, mNextCursorRect)) {
- if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mNextCursorRect);
+
+ mTmpCursorRect.set(left, top, right, bottom);
+ if (!mCursorRect.equals(mTmpCursorRect)) {
+ if (DEBUG) Log.d(TAG, "updateCursor");
+
try {
- mCurMethod.updateCursor(mNextCursorRect);
- mCursorRect.set(mNextCursorRect);
+ if (DEBUG) Log.v(TAG, "CURSOR CHANGE: " + mCurMethod);
+ mCurMethod.updateCursor(mTmpCursorRect);
+ mCursorRect.set(mTmpCursorRect);
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId, e);
}
@@ -1652,8 +1607,8 @@
}
// If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has
// not been changed from the previous call.
- final boolean isImmediate = (mCursorAnchorInfoMonitorMode &
- CursorAnchorInfoRequest.FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0;
+ final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode &
+ InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0;
if (!isImmediate && Objects.equals(mCursorAnchorInfo, cursorAnchorInfo)) {
// TODO: Consider always emitting this message once we have addressed redundant
// calls of this method from android.widget.Editor.
@@ -1668,8 +1623,8 @@
mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo);
mCursorAnchorInfo = cursorAnchorInfo;
// Clear immediate bit (if any).
- mCursorAnchorInfoMonitorMode &=
- ~CursorAnchorInfoRequest.FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE;
+ mRequestUpdateCursorAnchorInfoMonitorMode &=
+ ~InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE;
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId, e);
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 60ef693..eb93745 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -65,7 +65,6 @@
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
-import android.view.inputmethod.CursorAnchorInfoRequest;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -5718,8 +5717,8 @@
}
@Override
- public int requestCursorAnchorInfo(CursorAnchorInfoRequest request) {
- return getTarget().requestCursorAnchorInfo(request);
+ public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
+ return getTarget().requestUpdateCursorAnchorInfo(cursorUpdateMode);
}
}
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index f4a478a..49d47fe 100644
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -386,7 +386,9 @@
mCurrentDate.set(Calendar.YEAR, year);
mCurrentDate.set(Calendar.MONTH, month);
mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
- mDateChangedListener.onDateChanged(mDelegator, year, month, dayOfMonth);
+ if (mDateChangedListener != null) {
+ mDateChangedListener.onDateChanged(mDelegator, year, month, dayOfMonth);
+ }
updateDisplay(false);
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3f5f045..29c8298 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1298,25 +1298,6 @@
reported = reportExtractedText();
}
}
-
- if (imm.isWatchingCursor(mTextView) && highlight != null) {
- highlight.computeBounds(ims.mTmpRectF, true);
- ims.mTmpOffset[0] = ims.mTmpOffset[1] = 0;
-
- canvas.getMatrix().mapPoints(ims.mTmpOffset);
- ims.mTmpRectF.offset(ims.mTmpOffset[0], ims.mTmpOffset[1]);
-
- ims.mTmpRectF.offset(0, cursorOffsetVertical);
-
- ims.mCursorRectInWindow.set((int)(ims.mTmpRectF.left + 0.5),
- (int)(ims.mTmpRectF.top + 0.5),
- (int)(ims.mTmpRectF.right + 0.5),
- (int)(ims.mTmpRectF.bottom + 0.5));
-
- imm.updateCursor(mTextView,
- ims.mCursorRectInWindow.left, ims.mCursorRectInWindow.top,
- ims.mCursorRectInWindow.right, ims.mCursorRectInWindow.bottom);
- }
}
}
@@ -4136,7 +4117,6 @@
static class InputMethodState {
Rect mCursorRectInWindow = new Rect();
- RectF mTmpRectF = new RectF();
float[] mTmpOffset = new float[2];
ExtractedTextRequest mExtractedTextRequest;
final ExtractedText mExtractedText = new ExtractedText();
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 376e5b4..1b89179 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -73,16 +73,6 @@
private boolean mHourWithTwoDigit;
private char mHourFormat;
- /**
- * A no-op callback used in the constructor to avoid null checks later in
- * the code.
- */
- private static final TimePicker.OnTimeChangedListener NO_OP_CHANGE_LISTENER =
- new TimePicker.OnTimeChangedListener() {
- public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
- }
- };
-
public TimePickerClockDelegate(TimePicker delegator, Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(delegator, context);
@@ -216,8 +206,6 @@
updateMinuteControl();
updateAmPmControl();
- setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);
-
// set to current time
setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY));
setCurrentMinute(mTempCalendar.get(Calendar.MINUTE));
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 897381d..b1f5d90 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -25,7 +25,6 @@
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
-import android.view.inputmethod.CursorAnchorInfoRequest;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
@@ -55,7 +54,7 @@
private static final int DO_REPORT_FULLSCREEN_MODE = 100;
private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
private static final int DO_CLEAR_META_KEY_STATES = 130;
- private static final int DO_REQUEST_CURSOR_ANCHOR_INFO = 140;
+ private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
private WeakReference<InputConnection> mInputConnection;
@@ -177,9 +176,10 @@
dispatchMessage(obtainMessageOO(DO_PERFORM_PRIVATE_COMMAND, action, data));
}
- public void requestCursorAnchorInfo(CursorAnchorInfoRequest request, int seq,
+ public void requestUpdateCursorAnchorInfo(int cursorUpdateMode, int seq,
IInputContextCallback callback) {
- dispatchMessage(obtainMessageOSC(DO_REQUEST_CURSOR_ANCHOR_INFO, request, seq, callback));
+ dispatchMessage(obtainMessageISC(DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO, cursorUpdateMode,
+ seq, callback));
}
void dispatchMessage(Message msg) {
@@ -427,18 +427,17 @@
(Bundle)args.arg2);
return;
}
- case DO_REQUEST_CURSOR_ANCHOR_INFO: {
+ case DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO: {
SomeArgs args = (SomeArgs)msg.obj;
try {
InputConnection ic = mInputConnection.get();
if (ic == null || !isActive()) {
Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
- args.callback.setRequestCursorAnchorInfoResult(0, args.seq);
+ args.callback.setRequestUpdateCursorAnchorInfoResult(false, args.seq);
return;
}
- args.callback.setRequestCursorAnchorInfoResult(
- ic.requestCursorAnchorInfo((CursorAnchorInfoRequest)args.arg1),
- args.seq);
+ args.callback.setRequestUpdateCursorAnchorInfoResult(
+ ic.requestUpdateCursorAnchorInfo(msg.arg1), args.seq);
} catch (RemoteException e) {
Log.w(TAG, "Got RemoteException calling requestCursorAnchorInfo", e);
}
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index c06596a..fd2b513 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -20,7 +20,6 @@
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
-import android.view.inputmethod.CursorAnchorInfoRequest;
import android.view.inputmethod.ExtractedTextRequest;
import com.android.internal.view.IInputContextCallback;
@@ -74,6 +73,6 @@
void getSelectedText(int flags, int seq, IInputContextCallback callback);
- void requestCursorAnchorInfo(in CursorAnchorInfoRequest request, int seq,
+ void requestUpdateCursorAnchorInfo(in int cursorUpdateMode, int seq,
IInputContextCallback callback);
}
diff --git a/core/java/com/android/internal/view/IInputContextCallback.aidl b/core/java/com/android/internal/view/IInputContextCallback.aidl
index ab2fbdc..54ea306 100644
--- a/core/java/com/android/internal/view/IInputContextCallback.aidl
+++ b/core/java/com/android/internal/view/IInputContextCallback.aidl
@@ -27,5 +27,5 @@
void setCursorCapsMode(int capsMode, int seq);
void setExtractedText(in ExtractedText extractedText, int seq);
void setSelectedText(CharSequence selectedText, int seq);
- void setRequestCursorAnchorInfoResult(int result, int seq);
+ void setRequestUpdateCursorAnchorInfoResult(boolean result, int seq);
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 8535a98..a8526c8 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -23,7 +23,6 @@
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
-import android.view.inputmethod.CursorAnchorInfoRequest;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
@@ -41,7 +40,7 @@
public CharSequence mSelectedText;
public ExtractedText mExtractedText;
public int mCursorCapsMode;
- public int mCursorAnchorInfoRequestResult;
+ public boolean mRequestUpdateCursorAnchorInfoResult;
// A 'pool' of one InputContextCallback. Each ICW request will attempt to gain
// exclusive access to this object.
@@ -155,10 +154,10 @@
}
}
- public void setRequestCursorAnchorInfoResult(int result, int seq) {
+ public void setRequestUpdateCursorAnchorInfoResult(boolean result, int seq) {
synchronized (this) {
if (seq == mSeq) {
- mCursorAnchorInfoRequestResult = result;
+ mRequestUpdateCursorAnchorInfoResult = result;
mHaveValue = true;
notifyAll();
} else {
@@ -429,21 +428,21 @@
}
}
- public int requestCursorAnchorInfo(CursorAnchorInfoRequest request) {
- int value = CursorAnchorInfoRequest.RESULT_NOT_HANDLED;
+ public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
+ boolean result = false;
try {
InputContextCallback callback = InputContextCallback.getInstance();
- mIInputContext.requestCursorAnchorInfo(request, callback.mSeq, callback);
+ mIInputContext.requestUpdateCursorAnchorInfo(cursorUpdateMode, callback.mSeq, callback);
synchronized (callback) {
callback.waitForResultLocked();
if (callback.mHaveValue) {
- value = callback.mCursorAnchorInfoRequestResult;
+ result = callback.mRequestUpdateCursorAnchorInfoResult;
}
}
callback.dispose();
} catch (RemoteException e) {
- return CursorAnchorInfoRequest.RESULT_NOT_HANDLED;
+ return false;
}
- return value;
+ return result;
}
}
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index bfe0090..2967938 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -25,9 +25,9 @@
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
-import android.view.inputmethod.CursorAnchorInfoRequest;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
import android.widget.TextView;
public class EditableInputConnection extends BaseInputConnection {
@@ -188,24 +188,17 @@
}
@Override
- public int requestCursorAnchorInfo(CursorAnchorInfoRequest request) {
- if (DEBUG) Log.v(TAG, "requestCursorAnchorInfo " + request);
+ public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
+ if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode);
- // This implementation supports TYPE_CURSOR_ANCHOR_INFO only. Other events will be
- // delegated to the super class.
- if (request == null ||
- request.getRequestType() != CursorAnchorInfoRequest.TYPE_CURSOR_ANCHOR_INFO) {
- return super.requestCursorAnchorInfo(request);
- }
if (mIMM == null) {
// In this case, TYPE_CURSOR_ANCHOR_INFO is not handled.
- // TODO: Return some notification code for the input method that indicates
+ // TODO: Return some notification code rather than false to indicate method that
// CursorAnchorInfo is temporarily unavailable.
- return CursorAnchorInfoRequest.RESULT_NOT_HANDLED;
+ return false;
}
- final int flags = request.getRequestFlags();
- mIMM.setCursorAnchorInfoMonitorMode(flags);
- if ((flags & CursorAnchorInfoRequest.FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0) {
+ mIMM.setUpdateCursorAnchorInfoMode(cursorUpdateMode);
+ if ((cursorUpdateMode & InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0) {
if (mTextView == null) {
// In this case, FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE is silently ignored.
// TODO: Return some notification code for the input method that indicates
@@ -220,6 +213,6 @@
mTextView.requestLayout();
}
}
- return CursorAnchorInfoRequest.RESULT_SCHEDULED;
+ return true;
}
}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 5bd38f3..8b9f574 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -236,10 +236,10 @@
return (jboolean) !setNetworkForResolv(netId);
}
-static jboolean android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket,
+static jint android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket,
jint netId)
{
- return (jboolean) !setNetworkForSocket(netId, socket);
+ return setNetworkForSocket(netId, socket);
}
static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket)
@@ -263,7 +263,7 @@
{ "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
{ "getNetworkBoundToProcess", "()I", (void*) android_net_utils_getNetworkBoundToProcess },
{ "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
- { "bindSocketToNetwork", "(II)Z", (void*) android_net_utils_bindSocketToNetwork },
+ { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork },
{ "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
};
diff --git a/core/res/res/color/switch_thumb_material_dark.xml b/core/res/res/color/switch_thumb_material_dark.xml
new file mode 100644
index 0000000..8fede70
--- /dev/null
+++ b/core/res/res/color/switch_thumb_material_dark.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/switch_thumb_disabled_material_dark"/>
+ <item android:color="@color/switch_thumb_normal_material_dark"/>
+</selector>
diff --git a/core/res/res/color/switch_thumb_material_light.xml b/core/res/res/color/switch_thumb_material_light.xml
new file mode 100644
index 0000000..1a34b74
--- /dev/null
+++ b/core/res/res/color/switch_thumb_material_light.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/switch_thumb_disabled_material_light"/>
+ <item android:color="@color/switch_thumb_normal_material_light"/>
+</selector>
diff --git a/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 8af9ceb4..5e67395 100644
--- a/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png
index 81c78c6..9c2ee13 100644
--- a/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png
index 7bcebcd..ce577e5 100644
--- a/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png
index eb1d945..7c305ab 100644
--- a/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 22992c0..cb8f78a 100644
--- a/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png
index f44a2c2..64d4c81 100644
--- a/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png
index ef4ebc0..d7faacf 100644
--- a/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png
index 9ddbcf5..0a36039 100644
--- a/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 2d79d59..8e7862f 100644
--- a/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png
index 36f9753..95cb83f 100644
--- a/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png
index 1a2546f..33c1035 100644
--- a/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png
index 500ec33..0226f84 100644
--- a/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 9c0b19e..eb495c6 100644
--- a/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png
index 0edb4b8..c2268af 100644
--- a/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png
index cd5b00f..b6efff3 100644
--- a/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png
index 5ee867c..2b253fb 100644
--- a/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 78c5ebd..fbcd7d4 100644
--- a/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png
index 36974b7..ebc9bf7 100644
--- a/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_borderless_material.xml b/core/res/res/drawable/btn_borderless_material.xml
index 47cc455..016f0ff 100644
--- a/core/res/res/drawable/btn_borderless_material.xml
+++ b/core/res/res/drawable/btn_borderless_material.xml
@@ -15,10 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="@dimen/control_inset_material"
- android:insetTop="@dimen/control_inset_material"
- android:insetBottom="@dimen/control_inset_material"
- android:insetRight="@dimen/control_inset_material">
+ android:inset="@dimen/control_inset_material">
<ripple android:color="?attr/colorControlHighlight">
<item android:id="@id/mask"
android:drawable="@drawable/btn_default_mtrl_shape" />
diff --git a/core/res/res/drawable/btn_default_material.xml b/core/res/res/drawable/btn_default_material.xml
index b04d4fb..d00a348 100644
--- a/core/res/res/drawable/btn_default_material.xml
+++ b/core/res/res/drawable/btn_default_material.xml
@@ -15,10 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="@dimen/control_inset_material"
- android:insetTop="@dimen/control_inset_material"
- android:insetBottom="@dimen/control_inset_material"
- android:insetRight="@dimen/control_inset_material">
+ android:inset="@dimen/control_inset_material">
<ripple android:color="?attr/colorControlHighlight">
<item android:drawable="@drawable/btn_default_mtrl_shape" />
</ripple>
diff --git a/core/res/res/drawable/btn_toggle_material.xml b/core/res/res/drawable/btn_toggle_material.xml
index a9951e7..9726782 100644
--- a/core/res/res/drawable/btn_toggle_material.xml
+++ b/core/res/res/drawable/btn_toggle_material.xml
@@ -15,10 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="@dimen/control_inset_material"
- android:insetTop="@dimen/control_inset_material"
- android:insetBottom="@dimen/control_inset_material"
- android:insetRight="@dimen/control_inset_material">
+ android:inset="@dimen/control_inset_material">
<layer-list android:paddingMode="stack">
<item>
<ripple android:color="?attr/colorControlHighlight">
diff --git a/core/res/res/drawable/edit_text_material.xml b/core/res/res/drawable/edit_text_material.xml
index eaf5e45..bbc7301 100644
--- a/core/res/res/drawable/edit_text_material.xml
+++ b/core/res/res/drawable/edit_text_material.xml
@@ -15,10 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="@dimen/control_inset_material"
- android:insetTop="@dimen/control_inset_material"
- android:insetBottom="@dimen/control_inset_material"
- android:insetRight="@dimen/control_inset_material">
+ android:inset="@dimen/control_inset_material">
<ripple android:color="?attr/colorControlActivated">
<item>
<selector>
diff --git a/core/res/res/drawable/spinner_textfield_background_material.xml b/core/res/res/drawable/spinner_textfield_background_material.xml
index f818baf..5bdff4a 100644
--- a/core/res/res/drawable/spinner_textfield_background_material.xml
+++ b/core/res/res/drawable/spinner_textfield_background_material.xml
@@ -14,18 +14,20 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true">
- <item android:state_checked="true">
- <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:state_pressed="true">
- <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item>
- <nine-patch android:src="@drawable/spinner_textfield_default_mtrl_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
-</selector>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:inset="@dimen/control_inset_material">
+ <selector android:autoMirrored="true">
+ <item android:state_checked="true">
+ <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:state_pressed="true">
+ <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item>
+ <nine-patch android:src="@drawable/spinner_textfield_default_mtrl_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ </selector>
+</inset>
diff --git a/core/res/res/drawable/switch_thumb_material_anim.xml b/core/res/res/drawable/switch_thumb_material_anim.xml
index 30bc8882..0d4d78e 100644
--- a/core/res/res/drawable/switch_thumb_material_anim.xml
+++ b/core/res/res/drawable/switch_thumb_material_anim.xml
@@ -16,22 +16,12 @@
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize="true">
- <item
- android:state_enabled="false"
- android:state_checked="true">
- <nine-patch
- android:src="@drawable/btn_switch_to_on_mtrl_00012"
- android:gravity="center"
- android:tintMode="multiply"
- android:tint="?attr/colorControlActivated"
- android:alpha="?attr/disabledAlpha" />
- </item>
- <item android:state_enabled="false">
+ <item android:state_enabled="false" android:id="@+id/off">
<nine-patch
android:src="@drawable/btn_switch_to_on_mtrl_00001"
android:gravity="center"
android:tintMode="multiply"
- android:tint="?attr/colorButtonNormal" />
+ android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item
android:state_checked="true"
@@ -47,29 +37,29 @@
android:src="@drawable/btn_switch_to_on_mtrl_00001"
android:gravity="center"
android:tintMode="multiply"
- android:tint="?attr/colorButtonNormal" />
+ android:tint="?attr/colorSwitchThumbNormal" />
</item>
<transition
android:fromId="@+id/off"
android:toId="@+id/on">
<animation-list>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00001" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00001" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00002" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00002" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00003" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00003" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00004" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00004" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00005" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00005" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00006" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00006" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
<nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00007" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" />
@@ -112,22 +102,22 @@
<nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00006" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00007" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00007" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00008" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00008" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00009" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00009" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00010" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00010" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00011" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00011" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00012" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00012" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
</animation-list>
</transition>
diff --git a/core/res/res/drawable/switch_track_material.xml b/core/res/res/drawable/switch_track_material.xml
index 0728055..1ec2f88 100644
--- a/core/res/res/drawable/switch_track_material.xml
+++ b/core/res/res/drawable/switch_track_material.xml
@@ -15,10 +15,10 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:state_checked="true">
+ <item android:state_enabled="false">
<nine-patch android:src="@drawable/switch_track_mtrl_alpha"
- android:tint="?attr/colorControlActivated"
- android:alpha="0.2" />
+ android:tint="?attr/colorForeground"
+ android:alpha="0.1" />
</item>
<item android:state_checked="true">
<nine-patch android:src="@drawable/switch_track_mtrl_alpha"
@@ -27,7 +27,7 @@
</item>
<item>
<nine-patch android:src="@drawable/switch_track_mtrl_alpha"
- android:tint="?attr/colorButtonNormal"
+ android:tint="?attr/colorForeground"
android:alpha="0.3" />
</item>
</selector>
diff --git a/core/res/res/values-mcc310-mnc004/config.xml b/core/res/res/values-mcc310-mnc004/config.xml
index 4aac79d..423e250 100644
--- a/core/res/res/values-mcc310-mnc004/config.xml
+++ b/core/res/res/values-mcc310-mnc004/config.xml
@@ -33,4 +33,5 @@
<item>83</item>
</string-array>
+ <bool name="config_auto_attach_data_on_creation">false</bool>
</resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index 1c83644..e5af60b 100644
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -43,4 +43,5 @@
provisioning, availability etc -->
<bool name="config_mobile_allow_volte_vt">false</bool>
+ <bool name="config_auto_attach_data_on_creation">false</bool>
</resources>
diff --git a/core/res/res/values-sw720dp/dimens.xml b/core/res/res/values-sw720dp/dimens.xml
index 21235ec..2317d1f 100644
--- a/core/res/res/values-sw720dp/dimens.xml
+++ b/core/res/res/values-sw720dp/dimens.xml
@@ -35,9 +35,9 @@
<item type="dimen" name="dialog_fixed_height_minor">90%</item>
<!-- The width that is used when creating thumbnails of applications. -->
- <dimen name="thumbnail_width">640dp</dimen>
+ <dimen name="thumbnail_width">420dp</dimen>
<!-- The height that is used when creating thumbnails of applications. -->
- <dimen name="thumbnail_height">640dp</dimen>
+ <dimen name="thumbnail_height">420dp</dimen>
<!-- Preference activity, vertical padding for the header list -->
<dimen name="preference_screen_header_vertical_padding">32dp</dimen>
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
index a501fac..377982a 100644
--- a/core/res/res/values-television/themes.xml
+++ b/core/res/res/values-television/themes.xml
@@ -20,6 +20,8 @@
<style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
<style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
<style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+ <style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Leanback.Settings.Dialog.Alert" />
<style name="Theme.Material.Dialog" parent="Theme.Leanback.Dialog" />
<style name="Theme.Material.Light.Dialog" parent="Theme.Leanback.Light.Dialog" />
+ <style name="Theme.Material.Settings.Dialog" parent="Theme.Leanback.Settings.Dialog" />
</resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 327782d..f843d1f 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -506,12 +506,24 @@
<!-- Used in LocalePicker -->
<string-array translatable="false" name="special_locale_codes">
+ <!-- http://b/17150708 - ensure that the list of languages says "Arabic"
+ rather than "Arabic (Egypt)". If you're an OEM supporting multiple
+ Arabic locales, you should remove this entry so that ar_EG is shown
+ as "Arabic (Egypt)" in Settings. -->
+ <item>ar_EG</item>
+
<item>zh_CN</item>
<item>zh_TW</item>
</string-array>
<!-- Used in LocalePicker -->
<string-array translatable="false" name="special_locale_names">
+ <!-- http://b/17150708 - ensure that the list of languages says "Arabic"
+ rather than "Arabic (Egypt)". If you're an OEM supporting multiple
+ Arabic locales, you should remove this entry so that ar_EG is shown
+ as "Arabic (Egypt)" in Settings. -->
+ <item>العربية</item>
+
<item>中文 (简体)</item>
<item>中文 (繁體)</item>
</string-array>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b00d7e8..3524636 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -517,6 +517,10 @@
{@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
<attr name="windowAllowExitTransitionOverlap" format="boolean"/>
+ <!-- Indicates whether or not shared elements should use an overlay
+ during transitions. The default value is true. -->
+ <attr name="windowSharedElementsUseOverlay" format="boolean"/>
+
<!-- Internal layout used internally for window decor -->
<attr name="windowActionBarFullscreenDecorLayout" format="reference" />
@@ -1005,6 +1009,9 @@
<!-- The color applied to framework buttons in their normal state. -->
<attr name="colorButtonNormal" format="color" />
+ <!-- The color applied to framework switch thumbs in their normal state. -->
+ <attr name="colorSwitchThumbNormal" format="color" />
+
<!-- ================== -->
<!-- Hardware rendering -->
<!-- ================== -->
@@ -1836,6 +1843,10 @@
{@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
<attr name="windowAllowExitTransitionOverlap"/>
+ <!-- Indicates whether or not shared elements should use an overlay
+ during transitions. The default value is true. -->
+ <attr name="windowSharedElementsUseOverlay"/>
+
<!-- Flag indicating whether this Window is responsible for drawing the background for the
system bars. If true and the window is not floating, the system bars are drawn with a
transparent background and the corresponding areas in this window are filled with the
@@ -5597,6 +5608,19 @@
</attr>
</declare-styleable>
+ <!-- Use <code>changeTransform</code> as the root tag of the XML resource that
+ describes a {@link android.transition.ChangeTransform} transition. -->
+ <declare-styleable name="ChangeTransform">
+ <!-- A parent change should use an overlay or affect the transform of the
+ transitionining View. Default is true. Corresponds to
+ {@link android.transition.ChangeTransform#setReparentWithOverlay(boolean)}. -->
+ <attr name="reparentWithOverlay" format="boolean"/>
+
+ <!-- Tells ChangeTransform to track parent changes. Default is true. Corresponds to
+ {@link android.transition.ChangeTransform#setReparent(boolean)}. -->
+ <attr name="reparent" format="boolean"/>
+ </declare-styleable>
+
<!-- Use <code>transitionManager</code> as the root tag of the XML resource that
describes a {@link android.transition.TransitionManager
TransitionManager}. -->
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index ccbb8bc..2348951 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -25,6 +25,11 @@
<color name="button_material_dark">#ff5a595b</color>
<color name="button_material_light">#ffd6d7d7</color>
+ <color name="switch_thumb_normal_material_dark">#ffbdbdbd</color>
+ <color name="switch_thumb_normal_material_light">#fff1f1f1</color>
+ <color name="switch_thumb_disabled_material_dark">#ff616161</color>
+ <color name="switch_thumb_disabled_material_light">#ffbdbdbd</color>
+
<color name="bright_foreground_material_dark">@color/white</color>
<color name="bright_foreground_material_light">@color/black</color>
<!-- White 50% -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cf9a415..df7268f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1675,4 +1675,6 @@
Examples: <item>311480;prefix</item> <item>310260;suffix</item>
-->
<string-array translatable="false" name="no_ems_support_sim_operators" />
+
+ <bool name="config_auto_attach_data_on_creation">true</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6022bdc..6fd2bb1 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -19,9 +19,9 @@
-->
<resources>
<!-- The width that is used when creating thumbnails of applications. -->
- <dimen name="thumbnail_width">256dp</dimen>
+ <dimen name="thumbnail_width">192dp</dimen>
<!-- The height that is used when creating thumbnails of applications. -->
- <dimen name="thumbnail_height">256dp</dimen>
+ <dimen name="thumbnail_height">192dp</dimen>
<!-- The standard size (both width and height) of an application icon that
will be displayed in the app launcher and elsewhere. -->
<dimen name="app_icon_size">48dip</dimen>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index c64e910..4c59f73 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -85,4 +85,6 @@
<item type="id" name="scene_layoutid_cache" />
<item type="id" name="mask" />
<item type="id" name="transitionPosition" />
+ <item type="id" name="transitionTransform" />
+ <item type="id" name="parentMatrix" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4f0c5eb..f2466f7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2275,6 +2275,9 @@
<public type="attr" name="outlineProvider" />
<public type="attr" name="ageHint" />
<public type="attr" name="country" />
+ <public type="attr" name="windowSharedElementsUseOverlay" />
+ <public type="attr" name="reparent" />
+ <public type="attr" name="reparentWithOverlay" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index af73c02..b32cd1e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1990,4 +1990,7 @@
<java-symbol type="color" name="battery_saver_mode_color" />
<java-symbol type="color" name="system_notification_accent_color" />
<java-symbol type="dimen" name="text_handle_min_size" />
+ <java-symbol type="id" name="transitionTransform" />
+ <java-symbol type="id" name="parentMatrix" />
+ <java-symbol type="bool" name="config_auto_attach_data_on_creation" />
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index b36cdb9..5445816 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -116,12 +116,12 @@
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.Button</item>
-
<item name="buttonStyleSmall">@style/Widget.Button.Small</item>
<item name="buttonStyleInset">@style/Widget.Button.Inset</item>
-
<item name="buttonStyleToggle">@style/Widget.Button.Toggle</item>
+ <item name="switchStyle">@style/Widget.CompoundButton.Switch</item>
+
<item name="selectableItemBackground">@drawable/item_background</item>
<item name="selectableItemBackgroundBorderless">?attr/selectableItemBackground</item>
<item name="borderlessButtonStyle">?attr/buttonStyle</item>
diff --git a/core/res/res/values/themes_leanback.xml b/core/res/res/values/themes_leanback.xml
index 2b3b8d5..720733f 100644
--- a/core/res/res/values/themes_leanback.xml
+++ b/core/res/res/values/themes_leanback.xml
@@ -34,6 +34,16 @@
<item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
</style>
+ <style name="Theme.Leanback.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog">
+ <item name="colorBackground">@color/background_leanback_dark</item>
+ <item name="textColorPrimary">@color/primary_text_leanback_dark</item>
+ <item name="textColorSecondary">@color/secondary_text_leanback_dark</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
+ <item name="timePickerStyle">@style/Widget.Leanback.TimePicker</item>
+ <item name="datePickerStyle">@style/Widget.Leanback.DatePicker</item>
+ <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
+ </style>
+
<style name="Theme.Leanback.Dialog.Alert" parent="Theme.Material.Dialog.BaseAlert">
<item name="colorBackground">@color/background_leanback_dark</item>
<item name="textColorPrimary">@color/primary_text_leanback_dark</item>
@@ -54,6 +64,16 @@
<item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
</style>
+ <style name="Theme.Leanback.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert">
+ <item name="colorBackground">@color/background_leanback_light</item>
+ <item name="textColorPrimary">@color/primary_text_leanback_light</item>
+ <item name="textColorSecondary">@color/secondary_text_leanback_light</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Leanback.Light</item>
+ <item name="timePickerStyle">@style/Widget.Leanback.TimePicker</item>
+ <item name="datePickerStyle">@style/Widget.Leanback.DatePicker</item>
+ <item name="numberPickerStyle">@style/Widget.Leanback.NumberPicker</item>
+ </style>
+
<style name="Theme.Leanback.Dialog.AppError" parent="Theme.Leanback.Dialog">
<item name="windowContentTransitions">false</item>
<item name="windowCloseOnTouchOutside">false</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 18170ac..23faba8 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -357,10 +357,10 @@
<item name="timePickerDialogTheme">?attr/dialogTheme</item>
<!-- DatePicker style -->
- <item name="datePickerStyle">?attr/dialogTheme</item>
+ <item name="datePickerStyle">@style/Widget.Material.DatePicker</item>
<!-- DatePicker dialog theme -->
- <item name="datePickerDialogTheme">@style/Theme.Material.Dialog.Alert</item>
+ <item name="datePickerDialogTheme">?attr/dialogTheme</item>
<!-- TODO: This belongs in a FastScroll style -->
<item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item>
@@ -379,6 +379,7 @@
<item name="colorControlHighlight">@color/ripple_material_dark</item>
<item name="colorButtonNormal">@color/btn_default_material_dark</item>
+ <item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item>
</style>
<!-- Material theme (light version). -->
@@ -721,6 +722,7 @@
<item name="colorControlHighlight">@color/ripple_material_light</item>
<item name="colorButtonNormal">@color/btn_default_material_light</item>
+ <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
</style>
<!-- Variant of the material (light) theme that has a solid (opaque) action bar
@@ -774,6 +776,7 @@
<item name="colorControlNormal">?attr/textColorSecondary</item>
<item name="colorControlHighlight">@color/ripple_material_light</item>
<item name="colorButtonNormal">@color/btn_default_material_light</item>
+ <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
</style>
<!-- Theme overlay that replaces colors with their dark versions but preserves
@@ -811,6 +814,7 @@
<item name="colorControlNormal">?attr/textColorSecondary</item>
<item name="colorControlHighlight">@color/ripple_material_dark</item>
<item name="colorButtonNormal">@color/btn_default_material_dark</item>
+ <item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item>
</style>
<!-- Theme overlay that replaces the normal control color, which by default is the same as the
@@ -1192,7 +1196,7 @@
<style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.BaseAlert"/>
<!-- Theme for a presentation window on a secondary display. -->
- <style name="Theme.Material.Light.Dialog.Presentation" parent="@style/Theme.Material.Light.NoActionBar.Fullscreen" />
+ <style name="Theme.Material.Light.Dialog.Presentation" parent="Theme.Material.Light.NoActionBar.Fullscreen" />
<!-- Default material (dark) for windows that want to have the user's selected
wallpaper appear behind them. -->
@@ -1209,7 +1213,47 @@
</style>
<!-- Default theme for Settings and activities launched from Settings. -->
- <style name="Theme.Material.Settings" parent="@style/Theme.Material.Light.DarkActionBar">
+ <style name="Theme.Material.Settings" parent="Theme.Material.Light.DarkActionBar">
+ <item name="colorPrimary">@color/material_blue_grey_900</item>
+ <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+ <item name="colorAccent">@color/material_deep_teal_A500</item>
+
+ <item name="dialogTheme">@style/Theme.Material.Settings.Dialog</item>
+ <item name="alertDialogTheme">@style/Theme.Material.Settings.Dialog.Alert</item>
+ <item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
+ <item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
+ <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
+ </style>
+
+ <style name="Theme.Material.Settings.BaseDialog" parent="Theme.Material.Light.BaseDialog">
+ <item name="colorPrimary">@color/material_blue_grey_900</item>
+ <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+ <item name="colorAccent">@color/material_deep_teal_A500</item>
+ </style>
+
+ <style name="Theme.Material.Settings.Dialog" parent="Theme.Material.Settings.BaseDialog" />
+
+ <style name="Theme.Material.Settings.Dialog.BaseAlert" parent="Theme.Material.Light.Dialog.BaseAlert">
+ <item name="colorPrimary">@color/material_blue_grey_900</item>
+ <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+ <item name="colorAccent">@color/material_deep_teal_A500</item>
+ </style>
+
+ <style name="Theme.Material.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.BaseAlert" />
+
+ <style name="Theme.Material.Settings.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
+ <item name="colorPrimary">@color/material_blue_grey_900</item>
+ <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+ <item name="colorAccent">@color/material_deep_teal_A500</item>
+ </style>
+
+ <style name="Theme.Material.Settings.SearchBar" parent="Theme.Material.Light.SearchBar">
+ <item name="colorPrimary">@color/material_blue_grey_900</item>
+ <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+ <item name="colorAccent">@color/material_deep_teal_A500</item>
+ </style>
+
+ <style name="Theme.Material.Settings.CompactMenu" parent="Theme.Material.Light.CompactMenu">
<item name="colorPrimary">@color/material_blue_grey_900</item>
<item name="colorPrimaryDark">@color/material_blue_grey_950</item>
<item name="colorAccent">@color/material_deep_teal_A500</item>
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index be2241b..063ac09 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -211,7 +211,7 @@
final boolean canUseHardware = c.isHardwareAccelerated();
if (mCanUseHardware != canUseHardware && mCanUseHardware) {
// We've switched from hardware to non-hardware mode. Panic.
- cancelHardwareAnimations();
+ cancelHardwareAnimations(true);
}
mCanUseHardware = canUseHardware;
@@ -231,7 +231,7 @@
final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
final int N = pendingAnimations.size();
if (N > 0) {
- cancelHardwareAnimations();
+ cancelHardwareAnimations(false);
for (int i = 0; i < N; i++) {
pendingAnimations.get(i).setTarget(c);
@@ -399,6 +399,45 @@
invalidateSelf();
}
+ public void jump() {
+ endSoftwareAnimations();
+ endHardwareAnimations();
+ }
+
+ private void endSoftwareAnimations() {
+ if (mAnimRadius != null) {
+ mAnimRadius.end();
+ }
+
+ if (mAnimOpacity != null) {
+ mAnimOpacity.end();
+ }
+
+ if (mAnimX != null) {
+ mAnimX.end();
+ }
+
+ if (mAnimY != null) {
+ mAnimY.end();
+ }
+ }
+
+ private void endHardwareAnimations() {
+ final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
+ final int N = runningAnimations.size();
+ for (int i = 0; i < N; i++) {
+ runningAnimations.get(i).end();
+ }
+ runningAnimations.clear();
+
+ // Abort any pending animations. Since we always have a completion
+ // listener on a pending animation, we also need to remove ourselves.
+ if (!mPendingAnimations.isEmpty()) {
+ mPendingAnimations.clear();
+ removeSelf();
+ }
+ }
+
private Paint getTempPaint() {
if (mTempPaint == null) {
mTempPaint = new Paint();
@@ -444,7 +483,7 @@
*/
public void cancel() {
cancelSoftwareAnimations();
- cancelHardwareAnimations();
+ cancelHardwareAnimations(true);
}
private void cancelSoftwareAnimations() {
@@ -468,14 +507,18 @@
/**
* Cancels any running hardware animations.
*/
- private void cancelHardwareAnimations() {
+ private void cancelHardwareAnimations(boolean cancelPending) {
final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
final int N = runningAnimations.size();
for (int i = 0; i < N; i++) {
runningAnimations.get(i).cancel();
}
-
runningAnimations.clear();
+
+ if (cancelPending && !mPendingAnimations.isEmpty()) {
+ mPendingAnimations.clear();
+ removeSelf();
+ }
}
private void removeSelf() {
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 93df648..49862bc 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -203,7 +203,7 @@
final boolean canUseHardware = c.isHardwareAccelerated();
if (mCanUseHardware != canUseHardware && mCanUseHardware) {
// We've switched from hardware to non-hardware mode. Panic.
- cancelHardwareAnimations();
+ cancelHardwareAnimations(true);
}
mCanUseHardware = canUseHardware;
@@ -223,7 +223,7 @@
final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
final int N = pendingAnimations.size();
if (N > 0) {
- cancelHardwareAnimations();
+ cancelHardwareAnimations(false);
for (int i = 0; i < N; i++) {
pendingAnimations.get(i).setTarget(c);
@@ -403,6 +403,41 @@
invalidateSelf();
}
+ public void jump() {
+ endSoftwareAnimations();
+ endHardwareAnimations();
+ }
+
+ private void endSoftwareAnimations() {
+ if (mAnimOuterOpacity != null) {
+ mAnimOuterOpacity.end();
+ }
+
+ if (mAnimX != null) {
+ mAnimX.end();
+ }
+
+ if (mAnimY != null) {
+ mAnimY.end();
+ }
+ }
+
+ private void endHardwareAnimations() {
+ final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
+ final int N = runningAnimations.size();
+ for (int i = 0; i < N; i++) {
+ runningAnimations.get(i).end();
+ }
+ runningAnimations.clear();
+
+ // Abort any pending animations. Since we always have a completion
+ // listener on a pending animation, we also need to remove ourselves.
+ if (!mPendingAnimations.isEmpty()) {
+ mPendingAnimations.clear();
+ removeSelf();
+ }
+ }
+
private Paint getTempPaint() {
if (mTempPaint == null) {
mTempPaint = new Paint();
@@ -477,7 +512,7 @@
*/
public void cancel() {
cancelSoftwareAnimations();
- cancelHardwareAnimations();
+ cancelHardwareAnimations(true);
}
private void cancelSoftwareAnimations() {
@@ -497,7 +532,7 @@
/**
* Cancels any running hardware animations.
*/
- private void cancelHardwareAnimations() {
+ private void cancelHardwareAnimations(boolean cancelPending) {
final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
final int N = runningAnimations.size();
for (int i = 0; i < N; i++) {
@@ -505,6 +540,11 @@
}
runningAnimations.clear();
+
+ if (cancelPending && !mPendingAnimations.isEmpty()) {
+ mPendingAnimations.clear();
+ removeSelf();
+ }
}
private void removeSelf() {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 0447e17..ca32751f 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -199,6 +199,29 @@
}
@Override
+ public void jumpToCurrentState() {
+ super.jumpToCurrentState();
+
+ if (mRipple != null) {
+ mRipple.jump();
+ }
+
+ if (mBackground != null) {
+ mBackground.jump();
+ }
+
+ mClearingHotspots = true;
+ final int count = mAnimatingRipplesCount;
+ final Ripple[] ripples = mAnimatingRipples;
+ for (int i = 0; i < count; i++) {
+ ripples[i].jump();
+ ripples[i] = null;
+ }
+ mAnimatingRipplesCount = 0;
+ mClearingHotspots = false;
+ }
+
+ @Override
public void setAlpha(int alpha) {
super.setAlpha(alpha);
@@ -534,18 +557,6 @@
}
private void clearHotspots() {
- mClearingHotspots = true;
-
- final int count = mAnimatingRipplesCount;
- final Ripple[] ripples = mAnimatingRipples;
- for (int i = 0; i < count; i++) {
- // Calling cancel may remove the ripple from the animating ripple
- // array, so cache the reference before nulling it out.
- final Ripple ripple = ripples[i];
- ripples[i] = null;
- ripple.cancel();
- }
-
if (mRipple != null) {
mRipple.cancel();
mRipple = null;
@@ -556,8 +567,16 @@
mBackground = null;
}
- mClearingHotspots = false;
+ mClearingHotspots = true;
+ final int count = mAnimatingRipplesCount;
+ final Ripple[] ripples = mAnimatingRipples;
+ for (int i = 0; i < count; i++) {
+ ripples[i].cancel();
+ ripples[i] = null;
+ }
mAnimatingRipplesCount = 0;
+ mClearingHotspots = false;
+
invalidateSelf();
}
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index dca7520..977744f 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -215,7 +215,10 @@
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingPropertiesChanges(info);
}
- uint32_t animatorDirtyMask = mAnimatorManager.animate(info);
+ uint32_t animatorDirtyMask = 0;
+ if (CC_LIKELY(info.runAnimations)) {
+ animatorDirtyMask = mAnimatorManager.animate(info);
+ }
prepareLayer(info, animatorDirtyMask);
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingDisplayListChanges(info);
@@ -230,7 +233,9 @@
// Push the animators first so that setupStartValueIfNecessary() is called
// before properties() is trampled by stagingProperties(), as they are
// required by some animators.
- mAnimatorManager.pushStaging(info);
+ if (CC_LIKELY(info.runAnimations)) {
+ mAnimatorManager.pushStaging(info);
+ }
if (mDirtyPropertyFields) {
mDirtyPropertyFields = 0;
damageSelf(info);
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index 06c5ab4..bdac47b 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -196,12 +196,14 @@
float radius;
if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
- if (!MathUtils::isPositive(radius)) {
+ bool outlineIsRounded = MathUtils::isPositive(radius);
+ if (!outlineIsRounded || currentTransform()->isSimple()) {
// TODO: consider storing this rect separately, so that this can't be replaced with clip ops
clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkRegion::kIntersect_Op);
- return;
}
- setClippingRoundRect(allocator, bounds, radius);
+ if (outlineIsRounded) {
+ setClippingRoundRect(allocator, bounds, radius);
+ }
}
void StatefulBaseRenderer::setClippingRoundRect(LinearAllocator& allocator,
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 331f157..74d52a3 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -65,6 +65,7 @@
, frameTimeMs(0)
, animationHook(NULL)
, prepareTextures(mode == MODE_FULL)
+ , runAnimations(true)
, damageAccumulator(NULL)
, renderState(renderState)
, renderer(NULL)
@@ -76,6 +77,7 @@
, frameTimeMs(clone.frameTimeMs)
, animationHook(clone.animationHook)
, prepareTextures(mode == MODE_FULL)
+ , runAnimations(clone.runAnimations)
, damageAccumulator(clone.damageAccumulator)
, renderState(clone.renderState)
, renderer(clone.renderer)
@@ -88,6 +90,12 @@
// TODO: Remove this? Currently this is used to signal to stop preparing
// textures if we run out of cache space.
bool prepareTextures;
+ // TODO: buildLayer uses this to suppress running any animations, but this
+ // should probably be refactored somehow. The reason this is done is
+ // because buildLayer is not setup for injecting the animationHook, as well
+ // as this being otherwise wasted work as all the animators will be
+ // re-evaluated when the frame is actually drawn
+ bool runAnimations;
// Must not be null during actual usage
DamageAccumulator* damageAccumulator;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5922135..4bf5a8a 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -257,6 +257,7 @@
info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
info.damageAccumulator = &mDamageAccumulator;
info.renderer = mCanvas;
+ info.runAnimations = false;
node->prepareTree(info);
SkRect ignore;
mDamageAccumulator.finish(&ignore);
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 7bf9e98..96e6ab9 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -94,9 +94,17 @@
* and {@link #dequeueOutputBuffer} then transfer ownership from the codec
* to the client.<p>
* The client is not required to resubmit/release buffers immediately
- * to the codec, the sample code above simply does this for simplicity's sake.<p>
+ * to the codec, the sample code above simply does this for simplicity's sake.
+ * Nonetheless, it is possible that a codec may hold off on generating
+ * output buffers until all outstanding buffers have been
+ * released/resubmitted.
+ * <p>
* Once the client has an input buffer available it can fill it with data
- * and submit it it to the codec via a call to {@link #queueInputBuffer}.<p>
+ * and submit it it to the codec via a call to {@link #queueInputBuffer}.
+ * Do not submit multiple input buffers with the same timestamp (unless
+ * it is codec-specific data marked as such using the flag
+ * {@link #BUFFER_FLAG_CODEC_CONFIG}).
+ * <p>
* The codec in turn will return an output buffer to the client in response
* to {@link #dequeueOutputBuffer}. After the output buffer has been processed
* a call to {@link #releaseOutputBuffer} will return it to the codec.
@@ -128,18 +136,64 @@
* {@link #queueInputBuffer}. The codec will continue to return output buffers
* until it eventually signals the end of the output stream by specifying
* the same flag ({@link #BUFFER_FLAG_END_OF_STREAM}) on the BufferInfo returned in
- * {@link #dequeueOutputBuffer}.
+ * {@link #dequeueOutputBuffer}. Do not submit additional input buffers after
+ * signaling the end of the input stream, unless the codec has been flushed,
+ * or stopped and restarted.
* <p>
+ * <h3>Seeking & Adaptive Playback Support</h3>
+ *
+ * You can check if a decoder supports adaptive playback via {@link
+ * MediaCodecInfo.CodecCapabilities#isFeatureSupported}. Adaptive playback
+ * is only supported if you configure the codec to decode onto a {@link
+ * android.view.Surface}.
+ *
+ * <h4>For decoders that do not support adaptive playback (including
+ * when not decoding onto a Surface)</h4>
+ *
* In order to start decoding data that's not adjacent to previously submitted
- * data (i.e. after a seek) it is necessary to {@link #flush} the decoder.
+ * data (i.e. after a seek) <em>one must</em> {@link #flush} the decoder.
* Any input or output buffers the client may own at the point of the flush are
* immediately revoked, i.e. after a call to {@link #flush} the client does not
* own any buffers anymore.
+ * <p>
+ * It is important that the input data after a flush starts at a suitable
+ * stream boundary. The first frame must be able to be decoded completely on
+ * its own (for most codecs this means an I-frame), and that no frames should
+ * refer to frames before that first new frame.
* Note that the format of the data submitted after a flush must not change,
* flush does not support format discontinuities,
- * for this a full {@link #stop}, {@link #configure}, {@link #start}
+ * for this a full {@link #stop}, {@link #configure configure()}, {@link #start}
* cycle is necessary.
*
+ * <h4>For decoders that support adaptive playback</h4>
+ *
+ * In order to start decoding data that's not adjacent to previously submitted
+ * data (i.e. after a seek) it is <em>not necessary</em> to {@link #flush} the
+ * decoder.
+ * <p>
+ * It is still important that the input data after the discontinuity starts
+ * at a suitable stream boundary (e.g. I-frame), and that no new frames refer
+ * to frames before the first frame of the new input data segment.
+ * <p>
+ * For some video formats it is also possible to change the picture size
+ * mid-stream. To do this for H.264, the new Sequence Parameter Set (SPS) and
+ * Picture Parameter Set (PPS) values must be packaged together with an
+ * Instantaneous Decoder Refresh (IDR) frame in a single buffer, which then
+ * can be enqueued as a regular input buffer.
+ * The client will receive an {@link #INFO_OUTPUT_FORMAT_CHANGED} return
+ * value from {@link #dequeueOutputBuffer dequeueOutputBuffer()} or
+ * {@link Callback#onOutputBufferAvailable onOutputBufferAvailable()}
+ * just after the picture-size change takes place and before any
+ * frames with the new size have been returned.
+ * <p>
+ * Be careful when calling {@link #flush} shortly after you have changed
+ * the picture size. If you have not received confirmation of the picture
+ * size change, you will need to repeat the request for the new picture size.
+ * E.g. for H.264 you will need to prepend the PPS/SPS to the new IDR
+ * frame to ensure that the codec receives the picture size change request.
+ *
+ * <h3>States and error handling</h3>
+ *
* <p> During its life, a codec conceptually exists in one of the following states:
* Initialized, Configured, Executing, Error, Uninitialized, (omitting transitory states
* between them). When created by one of the factory methods,
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index d3b1520..05acf90 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -47,6 +47,7 @@
private InputStream mInputStream = null;
private boolean mAllowCrossDomainRedirect = true;
+ private boolean mAllowCrossProtocolRedirect = true;
// from com.squareup.okhttp.internal.http
private final static int HTTP_TEMP_REDIRECT = 307;
@@ -91,6 +92,8 @@
private boolean filterOutInternalHeaders(String key, String val) {
if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
mAllowCrossDomainRedirect = parseBoolean(val);
+ // cross-protocol redirects are also controlled by this flag
+ mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect;
} else {
return false;
}
@@ -190,8 +193,12 @@
!url.getProtocol().equals("http")) {
throw new NoRouteToHostException("Unsupported protocol redirect");
}
+ boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol());
+ if (!mAllowCrossProtocolRedirect && !sameProtocol) {
+ throw new NoRouteToHostException("Cross-protocol redirects are disallowed");
+ }
boolean sameHost = mURL.getHost().equals(url.getHost());
- if (!sameHost) {
+ if (!mAllowCrossDomainRedirect && !sameHost) {
throw new NoRouteToHostException("Cross-domain redirects are disallowed");
}
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 006b1ee..0d7e6c9 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -27,8 +27,7 @@
android:layout_height="wrap_content"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
androidprv:layout_maxHeight="@dimen/keyguard_security_height"
- android:gravity="center_horizontal|top"
- android:contentDescription="@string/keyguard_accessibility_status">
+ android:gravity="center_horizontal|top">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 55d8d81..a136acf 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -115,8 +115,6 @@
<string name="keyguard_accessibility_widget"><xliff:g id="widget_index">%1$s</xliff:g> widget.</string>
<!-- Accessibility description of the lock screen user selector widget. [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_user_selector">User selector</string>
- <!-- Accessibility description of the lock screen status widget. [CHAR_LIMIT=none] -->
- <string name="keyguard_accessibility_status">Status</string>
<!-- Accessibility description of the camera widget. [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_camera">Camera</string>
<!-- Accessibility description of the lock media control widget. [CHAR_LIMIT=none] -->
@@ -176,6 +174,9 @@
<!-- Accessibility description announced when user drags widget away from delete drop target [CHAR LIMIT=NONE] -->
<string name="keyguard_accessibility_delete_widget_end"><xliff:g id="widget_index">%1$s</xliff:g> will not be deleted.</string>
+ <!-- Accessibility description for the text view that indicates when the next alarm is set (not shown on screen). [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_next_alarm">Next alarm set for <xliff:g id="alarm" example="Fri 8:30 AM">%1$s</xliff:g></string>
+
<!-- Password keyboard strings. Used by LockScreen and Settings --><skip />
<!-- Label for "switch to symbols" key. Must be short to fit on key! -->
<string name="password_keyboard_label_symbol_key">\?123</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index 51a276e..a0fab42 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -143,7 +143,10 @@
void refreshAlarmStatus(AlarmManager.AlarmClockInfo nextAlarm) {
if (nextAlarm != null) {
- mAlarmStatusView.setText(formatNextAlarm(mContext, nextAlarm));
+ String alarm = formatNextAlarm(mContext, nextAlarm);
+ mAlarmStatusView.setText(alarm);
+ mAlarmStatusView.setContentDescription(
+ getResources().getString(R.string.keyguard_accessibility_next_alarm, alarm));
mAlarmStatusView.setVisibility(View.VISIBLE);
} else {
mAlarmStatusView.setVisibility(View.GONE);
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index ca07c87..ef0c9bb 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -67,6 +67,6 @@
android:src="@drawable/ic_lock_24dp"
android:scaleType="center"
android:tint="#ffffffff"
- android:contentDescription="@string/accessibility_unlock_button" />
+ android:contentDescription="@string/accessibility_unlock_button_not_secured" />
</com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 40870bf..dea14e9 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -105,4 +105,5 @@
<color name="search_panel_card_color">#ffffff</color>
<color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
+ <color name="doze_small_icon_background_color">#ff434343</color>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 42d9734..52dc000 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -189,6 +189,9 @@
<!-- Doze: interval between pulses when following the notification light -->
<integer name="doze_notification_pulse_interval">30000</integer>
+ <!-- Doze: alpha to apply to small icons when dozing -->
+ <integer name="doze_small_icon_alpha">222</integer><!-- 87% of 0xff -->
+
<!-- Volume: time to delay dismissing the volume panel after a click is performed -->
<integer name="volume_panel_dismiss_delay">200</integer>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 6418930..4e93cd8 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -34,5 +34,6 @@
<item type="id" name="alpha_animator_start_value_tag"/>
<item type="id" name="top_inset_animator_start_value_tag"/>
<item type="id" name="height_animator_start_value_tag"/>
+ <item type="id" name="doze_saved_filter_tag"/>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8f05f7b..9ff67bb 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -213,8 +213,6 @@
<string name="accessibility_camera_button">Camera</string>
<!-- Content description of the phone button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_phone_button">Phone</string>
- <!-- Content description of the unlock button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
- <string name="accessibility_unlock_button">Unlock</string>
<!-- Click action label for accessibility for the unlock button. [CHAR LIMIT=NONE] -->
<string name="unlock_label">unlock</string>
<!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] -->
@@ -222,6 +220,17 @@
<!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] -->
<string name="camera_label">open camera</string>
+ <!-- Content description of the lock icon when device is secured (lock closed) and trust not managed (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_unlock_button_secured">Device secured.</string>
+ <!-- Content description of the lock icon when device is not secured (lock open) and trust not managed (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_unlock_button_not_secured">Device not secured.</string>
+ <!-- Content description of the lock icon when device is secured (lock closed) and trust managed (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_unlock_button_secured_trust_managed">Device secured, trust agent active.</string>
+ <!-- Content description of the lock icon when device is not secured (lock open) and trust managed (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_unlock_button_not_secured_trust_managed">Device not secured, trust agent active.</string>
+ <!-- Content description of the lock icon when face unlock is running (face icon) and trust managed (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_unlock_button_face_unlock_running">Face detection running, trust agent active.</string>
+
<!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_ime_switch_button">Switch input method button.</string>
<!-- Content description of the compatibility zoom button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 74c0328..fe1e5db 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -76,6 +76,7 @@
private PendingIntent mNotificationPulseIntent;
private int mMultipulseCount;
private int mNotificationPulseInterval;
+ private boolean mPowerSaveActive;
public DozeService() {
if (DEBUG) Log.d(mTag, "new DozeService()");
@@ -94,6 +95,7 @@
pw.print(" mNotificationLightOn: "); pw.println(mNotificationLightOn);
pw.print(" mMultipulseCount: "); pw.println(mMultipulseCount);
pw.print(" mNotificationPulseInterval: "); pw.println(mNotificationPulseInterval);
+ pw.print(" mPowerSaveActive: "); pw.println(mPowerSaveActive);
}
@Override
@@ -141,7 +143,13 @@
@Override
public void onDreamingStarted() {
super.onDreamingStarted();
- if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze());
+ mPowerSaveActive = mHost != null && mHost.isPowerSaveActive();
+ if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze() + " mPowerSaveActive="
+ + mPowerSaveActive);
+ if (mPowerSaveActive) {
+ finishToSavePower();
+ return;
+ }
mDreaming = true;
listenForPulseSignals(true);
requestDoze();
@@ -232,6 +240,11 @@
}
}
+ private void finishToSavePower() {
+ Log.w(mTag, "Exiting ambient mode due to low power battery saver");
+ finish();
+ }
+
private void listenForPulseSignals(boolean listen) {
if (DEBUG) Log.d(mTag, "listenForPulseSignals: " + listen);
mSigMotionSensor.setListening(listen);
@@ -329,6 +342,14 @@
mNotificationLightOn = on;
rescheduleNotificationPulse();
}
+
+ @Override
+ public void onPowerSaveChanged(boolean active) {
+ mPowerSaveActive = active;
+ if (mPowerSaveActive && mDreaming) {
+ finishToSavePower();
+ }
+ }
};
public interface Host {
@@ -337,11 +358,13 @@
void requestDoze(DozeService dozeService);
void requestPulse(int pulses, boolean delayed, DozeService dozeService);
void dozingStopped(DozeService dozeService);
+ boolean isPowerSaveActive();
public interface Callback {
void onNewNotifications();
void onBuzzBeepBlinked();
void onNotificationLight(boolean on);
+ void onPowerSaveChanged(boolean active);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index c7198fe..d39f64e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -143,7 +143,7 @@
mBackgroundColor = new ColorDrawable(0);
// Copy the ripple drawable since we are going to be manipulating it
mBackground = (RippleDrawable)
- getResources().getDrawable(R.drawable.recents_task_view_header_bg);
+ getContext().getDrawable(R.drawable.recents_task_view_header_bg);
mBackground = (RippleDrawable) mBackground.mutate().getConstantState().newDrawable();
mBackground.setColor(ColorStateList.valueOf(0));
mBackground.setDrawableByLayerId(mBackground.getId(0), mBackgroundColor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 9ac20a6..7d64325 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -120,6 +120,15 @@
return false;
}
+ @Override
+ public void setDark(boolean dark, boolean fade) {
+ super.setDark(dark, fade);
+ final NotificationContentView showing = getShowingLayout();
+ if (showing != null) {
+ showing.setDark(dark, fade);
+ }
+ }
+
public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
mRowMinHeight = rowMinHeight;
mRowMaxHeight = rowMaxHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index a030f61..548e7d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -17,15 +17,20 @@
package com.android.systemui.statusbar;
import android.content.Context;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import com.android.systemui.R;
@@ -37,6 +42,8 @@
public class NotificationContentView extends FrameLayout {
private static final long ANIMATION_DURATION_LENGTH = 170;
+ private static final Paint INVERT_PAINT = createInvertPaint();
+ private static final ColorFilter NO_COLOR_FILTER = new ColorFilter();
private final Rect mClipBounds = new Rect();
@@ -50,6 +57,7 @@
private final Interpolator mLinearInterpolator = new LinearInterpolator();
private boolean mContractedVisible = true;
+ private boolean mDark;
private final Paint mFadePaint = new Paint();
@@ -192,4 +200,49 @@
public boolean isContentExpandable() {
return mExpandedChild != null;
}
+
+ public void setDark(boolean dark, boolean fade) {
+ if (mDark == dark) return;
+ mDark = dark;
+ setImageViewDark(dark, fade, com.android.internal.R.id.right_icon);
+ setImageViewDark(dark, fade, com.android.internal.R.id.icon);
+ }
+
+ private void setImageViewDark(boolean dark, boolean fade, int imageViewId) {
+ // TODO: implement fade
+ final ImageView v = (ImageView) mContractedChild.findViewById(imageViewId);
+ final Drawable d = v.getBackground();
+ if (dark) {
+ v.setLayerType(LAYER_TYPE_HARDWARE, INVERT_PAINT);
+ if (d != null) {
+ v.setTag(R.id.doze_saved_filter_tag, d.getColorFilter() != null ? d.getColorFilter()
+ : NO_COLOR_FILTER);
+ d.setColorFilter(getResources().getColor(R.color.doze_small_icon_background_color),
+ PorterDuff.Mode.SRC_ATOP);
+ v.setImageAlpha(getResources().getInteger(R.integer.doze_small_icon_alpha));
+ }
+ } else {
+ v.setLayerType(LAYER_TYPE_NONE, null);
+ if (d != null) {
+ final ColorFilter filter = (ColorFilter) v.getTag(R.id.doze_saved_filter_tag);
+ if (filter != null) {
+ d.setColorFilter(filter == NO_COLOR_FILTER ? null : filter);
+ v.setTag(R.id.doze_saved_filter_tag, null);
+ }
+ v.setImageAlpha(0xff);
+ }
+ }
+ }
+
+ private static Paint createInvertPaint() {
+ final Paint p = new Paint();
+ final float[] invert = {
+ -1f, 0f, 0f, 1f, 1f,
+ 0f, -1f, 0f, 1f, 1f,
+ 0f, 0f, -1f, 1f, 1f,
+ 0f, 0f, 0f, 1f, 0f
+ };
+ p.setColorFilter(new ColorMatrixColorFilter(new ColorMatrix(invert)));
+ return p;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 44d8d23..cb2d40a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -377,11 +377,20 @@
boolean trustManaged = mUnlockMethodCache.isTrustManaged();
mTrustDrawable.setTrustManaged(trustManaged);
- // TODO: Update content description depending on state
updateLockIconClickability();
+ updateLockIconContentDescription(mUnlockMethodCache.isFaceUnlockRunning(),
+ mUnlockMethodCache.isMethodInsecure(), trustManaged);
}
-
+ private void updateLockIconContentDescription(boolean faceUnlockRunning, boolean insecure,
+ boolean trustManaged) {
+ mLockIcon.setContentDescription(getResources().getString(
+ faceUnlockRunning ? R.string.accessibility_unlock_button_face_unlock_running
+ : insecure && !trustManaged ? R.string.accessibility_unlock_button_not_secured
+ : insecure ? R.string.accessibility_unlock_button_not_secured_trust_managed
+ : !trustManaged ? R.string.accessibility_unlock_button_secured
+ : R.string.accessibility_unlock_button_secured_trust_managed));
+ }
public KeyguardAffordanceView getPhoneView() {
return mPhoneImageView;
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 b3042b9..80c7c56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -752,6 +752,9 @@
@Override
public void onPowerSaveChanged() {
mHandler.post(mCheckBarModes);
+ if (mDozeServiceHost != null) {
+ mDozeServiceHost.firePowerSaveChanged(mBatteryController.isPowerSave());
+ }
}
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
@@ -3920,6 +3923,12 @@
private DozeService mCurrentDozeService;
+ public void firePowerSaveChanged(boolean active) {
+ for (Callback callback : mCallbacks) {
+ callback.onPowerSaveChanged(active);
+ }
+ }
+
public void fireBuzzBeepBlinked() {
for (Callback callback : mCallbacks) {
callback.onBuzzBeepBlinked();
@@ -3970,6 +3979,11 @@
mHandler.obtainMessage(H.DOZING_STOPPED, dozeService).sendToTarget();
}
+ @Override
+ public boolean isPowerSaveActive() {
+ return mBatteryController != null && mBatteryController.isPowerSave();
+ }
+
private void handleRequestDoze(DozeService dozeService) {
mCurrentDozeService = dozeService;
if (!mDozing) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 73358c8..9652ebd 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -267,6 +267,7 @@
private Boolean mAllowExitTransitionOverlap;
private Boolean mAllowEnterTransitionOverlap;
private long mBackgroundFadeDurationMillis = -1;
+ private Boolean mSharedElementsUseOverlay;
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -3546,6 +3547,10 @@
R.styleable.Window_windowTransitionBackgroundFadeDuration,
DEFAULT_BACKGROUND_FADE_DURATION_MS);
}
+ if (mSharedElementsUseOverlay == null) {
+ mSharedElementsUseOverlay = getWindowStyle().getBoolean(
+ R.styleable.Window_windowSharedElementsUseOverlay, true);
+ }
}
}
}
@@ -4024,6 +4029,16 @@
mBackgroundFadeDurationMillis = fadeDurationMillis;
}
+ @Override
+ public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) {
+ mSharedElementsUseOverlay = sharedElementsUseOverlay;
+ }
+
+ @Override
+ public boolean getSharedElementsUseOverlay() {
+ return (mSharedElementsUseOverlay == null) ? true : mSharedElementsUseOverlay;
+ }
+
private static final class DrawableFeatureState {
DrawableFeatureState(int _featureId) {
featureId = _featureId;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 54afe99..1005bd7 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4761,7 +4761,9 @@
result.setType(networkType);
return result;
} else {
- return new NetworkInfo(networkType, 0, "Unknown", "");
+ NetworkInfo result = new NetworkInfo(networkType);
+ result.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
+ return result;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 24b7cb3..fcbe71e 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -773,8 +773,8 @@
if (newThumbnail != null) {
if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
"Setting thumbnail of " + this + " to " + newThumbnail);
- task.setLastThumbnail(newThumbnail);
- if (isPersistable()) {
+ boolean thumbnailUpdated = task.setLastThumbnail(newThumbnail);
+ if (thumbnailUpdated && isPersistable()) {
mStackSupervisor.mService.notifyTaskPersisterLocked(task, false);
}
}
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index 0ba62c5..098b0b6 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -94,6 +94,9 @@
}
mResult.set(msg.what);
+ // Make sure we don't have time timeout still hanging around.
+ removeMessages(FORCE_QUIT);
+
// If this is a timeout we won't be automatically closed, so go
// ahead and explicitly dismiss ourselves just in case.
dismiss();
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 2a8c6fb..d35e09f 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -386,15 +386,23 @@
setNextAffiliate(null);
}
- void setLastThumbnail(Bitmap thumbnail) {
- mLastThumbnail = thumbnail;
- if (thumbnail == null) {
- if (mLastThumbnailFile != null) {
- mLastThumbnailFile.delete();
+ /**
+ * Sets the last thumbnail.
+ * @return whether the thumbnail was set
+ */
+ boolean setLastThumbnail(Bitmap thumbnail) {
+ if (mLastThumbnail != thumbnail) {
+ mLastThumbnail = thumbnail;
+ if (thumbnail == null) {
+ if (mLastThumbnailFile != null) {
+ mLastThumbnailFile.delete();
+ }
+ } else {
+ mService.mTaskPersister.saveImage(thumbnail, mFilename);
}
- } else {
- mService.mTaskPersister.saveImage(thumbnail, mFilename);
+ return true;
}
+ return false;
}
void getLastThumbnail(TaskThumbnail thumbs) {
@@ -403,7 +411,8 @@
if (mLastThumbnail == null) {
thumbs.mainThumbnail = mService.mTaskPersister.getThumbnail(mFilename);
}
- if (mLastThumbnailFile.exists()) {
+ // Only load the thumbnail file if we don't have a thumbnail
+ if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) {
try {
thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,
ParcelFileDescriptor.MODE_READ_ONLY);
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index ddd0865..9f4ed89 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -639,8 +639,7 @@
log("Checking " + url.toString() + " on " +
mNetworkAgentInfo.networkInfo.getExtraInfo());
}
- url = mNetworkAgentInfo.network.getBoundURL(url);
- urlConnection = (HttpURLConnection) url.openConnection();
+ urlConnection = (HttpURLConnection) mNetworkAgentInfo.network.openConnection(url);
urlConnection.setInstanceFollowRedirects(false);
urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index a231945..4e8c46f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -112,6 +112,10 @@
private final HdmiCecStandbyModeHandler mStandbyHandler;
+ // If true, do not do routing control/send active source for internal source.
+ // Set to true when the device was woken up by <Text/Image View On>.
+ private boolean mSkipRoutingControl;
+
// Set of physical addresses of CEC switches on the CEC bus. Managed independently from
// other CEC devices since they might not have logical address.
private final ArraySet<Integer> mCecSwitches = new ArraySet<Integer>();
@@ -134,6 +138,7 @@
mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
mAddress, mService.getVendorId()));
mCecSwitches.add(mService.getPhysicalAddress()); // TV is a CEC switch too.
+ mSkipRoutingControl = (reason == HdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE);
launchRoutingControl(reason != HdmiControlService.INITIATED_BY_ENABLE_CEC &&
reason != HdmiControlService.INITIATED_BY_BOOT_UP);
launchDeviceDiscovery();
@@ -207,7 +212,10 @@
// Seq #18
if (mService.isControlEnabled() && mActiveSource.logicalAddress != mAddress) {
updateActiveSource(mAddress, mService.getPhysicalAddress());
- // TODO: Check if this comes from <Text/Image View On> - if true, do nothing.
+ if (mSkipRoutingControl) {
+ mSkipRoutingControl = false;
+ return;
+ }
HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
mAddress, mService.getPhysicalAddress());
mService.sendCecCommand(activeSource);
@@ -304,11 +312,13 @@
invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
return;
}
- // TODO: Return immediately if the operation is triggered by <Text/Image View On>
- // and this is the first notification about the active input after power-on
- // (switch to HDMI didn't happen so far but is expected to happen soon).
int oldPath = getActivePortId() != Constants.INVALID_PORT_ID
? mService.portIdToPath(getActivePortId()) : getDeviceInfo().getPhysicalAddress();
+ setActivePath(oldPath);
+ if (mSkipRoutingControl) {
+ mSkipRoutingControl = false;
+ return;
+ }
int newPath = mService.portIdToPath(portId);
HdmiCecMessage routingChange =
HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath);
@@ -566,8 +576,6 @@
if (mService.isPowerStandbyOrTransient() && mAutoWakeup) {
mService.wakeUp();
}
- // TODO: Connect to Hardware input manager to invoke TV App with the appropriate channel
- // that represents the source device.
return true;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 4c88ce0..8b345cf 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -17,7 +17,6 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiDeviceInfo;
-import android.util.Slog;
import android.util.SparseArray;
/**
@@ -52,6 +51,7 @@
}
final SparseArray<ValidationInfo> mValidationInfo = new SparseArray<>();
+ private final HdmiLogger mSpamSafeLogger = new HdmiLogger(TAG);
public HdmiCecMessageValidator(HdmiControlService service) {
mService = service;
@@ -183,32 +183,32 @@
int opcode = message.getOpcode();
ValidationInfo info = mValidationInfo.get(opcode);
if (info == null) {
- Slog.w(TAG, "No validation information for the message: " + message);
+ mSpamSafeLogger.warning("No validation information for the message: " + message);
return true;
}
// Check the source field.
if (message.getSource() == Constants.ADDR_UNREGISTERED &&
(info.addressType & SRC_UNREGISTERED) == 0) {
- Slog.w(TAG, "Unexpected source: " + message);
+ mSpamSafeLogger.warning("Unexpected source: " + message);
return false;
}
// Check the destination field.
if (message.getDestination() == Constants.ADDR_BROADCAST) {
if ((info.addressType & DEST_BROADCAST) == 0) {
- Slog.w(TAG, "Unexpected broadcast message: " + message);
+ mSpamSafeLogger.warning("Unexpected broadcast message: " + message);
return false;
}
} else { // Direct addressing.
if ((info.addressType & DEST_DIRECT) == 0) {
- Slog.w(TAG, "Unexpected direct message: " + message);
+ mSpamSafeLogger.warning("Unexpected direct message: " + message);
return false;
}
}
// Check the parameter type.
if (!info.parameterValidator.isValid(message.getParams())) {
- Slog.w(TAG, "Unexpected parameters: " + message);
+ mSpamSafeLogger.warning("Unexpected parameters: " + message);
return false;
}
return true;
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 888ceec3..3dabc11 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -43,6 +43,7 @@
import android.hardware.hdmi.IHdmiDeviceEventListener;
import android.hardware.hdmi.IHdmiHotplugEventListener;
import android.hardware.hdmi.IHdmiInputChangeListener;
+import android.hardware.hdmi.IHdmiMhlScratchpadCommandListener;
import android.hardware.hdmi.IHdmiRecordListener;
import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
import android.hardware.hdmi.IHdmiVendorCommandListener;
@@ -159,41 +160,32 @@
// Type of logical devices hosted in the system. Stored in the unmodifiable list.
private final List<Integer> mLocalDevices;
- // List of listeners registered by callers that want to get notified of
- // hotplug events.
- @GuardedBy("mLock")
- private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>();
+ private final HdmiLogger mSpamSafeLogger = new HdmiLogger(TAG);
// List of records for hotplug event listener to handle the the caller killed in action.
@GuardedBy("mLock")
private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords =
new ArrayList<>();
- // List of listeners registered by callers that want to get notified of
- // device status events.
- @GuardedBy("mLock")
- private final ArrayList<IHdmiDeviceEventListener> mDeviceEventListeners = new ArrayList<>();
-
- // List of records for device event listener to handle the the caller killed in action.
+ // List of records for device event listener to handle the caller killed in action.
@GuardedBy("mLock")
private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords =
new ArrayList<>();
- // List of records for vendor command listener to handle the the caller killed in action.
+ // List of records for vendor command listener to handle the caller killed in action.
@GuardedBy("mLock")
private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords =
new ArrayList<>();
+ // List of records for MHL Scratchpad command listener to handle the caller killed in action.
@GuardedBy("mLock")
- private IHdmiInputChangeListener mInputChangeListener;
+ private final ArrayList<HdmiMhlScratchpadCommandListenerRecord>
+ mScratchpadCommandListenerRecords = new ArrayList<>();
@GuardedBy("mLock")
private InputChangeListenerRecord mInputChangeListenerRecord;
@GuardedBy("mLock")
- private IHdmiRecordListener mRecordListener;
-
- @GuardedBy("mLock")
private HdmiRecordListenerRecord mRecordListenerRecord;
// Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol
@@ -214,10 +206,6 @@
@GuardedBy("mLock")
private List<HdmiDeviceInfo> mMhlDevices;
- // List of listeners registered by callers that want to get notified of
- // system audio mode changes.
- private final ArrayList<IHdmiSystemAudioModeChangeListener>
- mSystemAudioModeChangeListeners = new ArrayList<>();
// List of records for system audio mode change to handle the the caller killed in action.
private final ArrayList<SystemAudioModeChangeListenerRecord>
mSystemAudioModeChangeListenerRecords = new ArrayList<>();
@@ -227,6 +215,9 @@
private final SettingsObserver mSettingsObserver;
+ private final HdmiControlBroadcastReceiver
+ mHdmiControlBroadcastReceiver = new HdmiControlBroadcastReceiver();
+
@Nullable
private HdmiCecController mCecController;
@@ -248,9 +239,6 @@
private HdmiCecMessageValidator mMessageValidator;
- private final HdmiControlBroadcastReceiver
- mHdmiControlBroadcastReceiver = new HdmiControlBroadcastReceiver();
-
@ServiceThreadOnly
private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY;
@@ -648,7 +636,7 @@
if (mMessageValidator.isValid(command)) {
mCecController.sendCommand(command, callback);
} else {
- Slog.e(TAG, "Invalid message type:" + command);
+ mSpamSafeLogger.error("Invalid message type:" + command);
if (callback != null) {
callback.onSendCompleted(Constants.SEND_RESULT_FAILURE);
}
@@ -709,7 +697,7 @@
}
if (message.getDestination() != Constants.ADDR_BROADCAST) {
- Slog.w(TAG, "Unhandled cec command:" + message);
+ mSpamSafeLogger.warning("Unhandled cec command:" + message);
}
return false;
}
@@ -788,8 +776,11 @@
}
void announceSystemAudioModeChange(boolean enabled) {
- for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) {
- invokeSystemAudioModeChange(listener, enabled);
+ synchronized (mLock) {
+ for (SystemAudioModeChangeListenerRecord record :
+ mSystemAudioModeChangeListenerRecords) {
+ invokeSystemAudioModeChangeLocked(record.mListener, enabled);
+ }
}
}
@@ -914,7 +905,6 @@
public void binderDied() {
synchronized (mLock) {
mHotplugEventListenerRecords.remove(this);
- mHotplugEventListeners.remove(mListener);
}
}
}
@@ -930,7 +920,6 @@
public void binderDied() {
synchronized (mLock) {
mDeviceEventListenerRecords.remove(this);
- mDeviceEventListeners.remove(mListener);
}
}
}
@@ -946,7 +935,6 @@
public void binderDied() {
synchronized (mLock) {
mSystemAudioModeChangeListenerRecords.remove(this);
- mSystemAudioModeChangeListeners.remove(mListener);
}
}
}
@@ -969,14 +957,33 @@
}
private class HdmiRecordListenerRecord implements IBinder.DeathRecipient {
+ private final IHdmiRecordListener mListener;
+
+ public HdmiRecordListenerRecord(IHdmiRecordListener listener) {
+ mListener = listener;
+ }
+
@Override
public void binderDied() {
synchronized (mLock) {
- mRecordListener = null;
+ mRecordListenerRecord = null;
}
}
}
+ private class HdmiMhlScratchpadCommandListenerRecord implements IBinder.DeathRecipient {
+ private final IHdmiMhlScratchpadCommandListener mListener;
+
+ public HdmiMhlScratchpadCommandListenerRecord(IHdmiMhlScratchpadCommandListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void binderDied() {
+ mScratchpadCommandListenerRecords.remove(this);
+ }
+ }
+
private void enforceAccessPermission() {
getContext().enforceCallingOrSelfPermission(PERMISSION, TAG);
}
@@ -1120,34 +1127,19 @@
@Override
public void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
enforceAccessPermission();
- runOnServiceThread(new Runnable() {
- @Override
- public void run() {
- HdmiControlService.this.addHotplugEventListener(listener);
- }
- });
+ HdmiControlService.this.addHotplugEventListener(listener);
}
@Override
public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) {
enforceAccessPermission();
- runOnServiceThread(new Runnable() {
- @Override
- public void run() {
- HdmiControlService.this.removeHotplugEventListener(listener);
- }
- });
+ HdmiControlService.this.removeHotplugEventListener(listener);
}
@Override
public void addDeviceEventListener(final IHdmiDeviceEventListener listener) {
enforceAccessPermission();
- runOnServiceThread(new Runnable() {
- @Override
- public void run() {
- HdmiControlService.this.addDeviceEventListener(listener);
- }
- });
+ HdmiControlService.this.addDeviceEventListener(listener);
}
@Override
@@ -1288,12 +1280,7 @@
public void addVendorCommandListener(final IHdmiVendorCommandListener listener,
final int deviceType) {
enforceAccessPermission();
- runOnServiceThread(new Runnable() {
- @Override
- public void run() {
- HdmiControlService.this.addVendorCommandListener(listener, deviceType);
- }
- });
+ HdmiControlService.this.addVendorCommandListener(listener, deviceType);
}
@Override
@@ -1382,6 +1369,38 @@
}
});
}
+
+ @Override
+ public void sendScratchpadCommand(final int portId, final int offset, final int length,
+ final byte[] data) {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ if (mMhlController == null) {
+ Slog.w(TAG, "No Mhl controller available.");
+ return;
+ }
+ if (!isControlEnabled()) {
+ Slog.w(TAG, "Hdmi control is disabled.");
+ return ;
+ }
+ HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId);
+ if (device == null) {
+ Slog.w(TAG, "Invalid port id:" + portId);
+ return;
+ }
+ mMhlController.sendScratchpadCommand(portId, offset, length, data);
+ }
+ });
+ }
+
+ @Override
+ public void addHdmiMhlScratchpadCommandListener(
+ IHdmiMhlScratchpadCommandListener listener) {
+ enforceAccessPermission();
+ HdmiControlService.this.addHdmiMhlScratchpadCommandListener(listener);
+ }
}
@ServiceThreadOnly
@@ -1418,7 +1437,6 @@
}
synchronized (mLock) {
mHotplugEventListenerRecords.add(record);
- mHotplugEventListeners.add(listener);
}
}
@@ -1431,7 +1449,6 @@
break;
}
}
- mHotplugEventListeners.remove(listener);
}
}
@@ -1444,16 +1461,15 @@
return;
}
synchronized (mLock) {
- mDeviceEventListeners.add(listener);
mDeviceEventListenerRecords.add(record);
}
}
void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) {
synchronized (mLock) {
- for (IHdmiDeviceEventListener listener : mDeviceEventListeners) {
+ for (DeviceEventListenerRecord record : mDeviceEventListenerRecords) {
try {
- listener.onStatusChanged(device, status);
+ record.mListener.onStatusChanged(device, status);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to report device event:" + e);
}
@@ -1471,7 +1487,6 @@
return;
}
synchronized (mLock) {
- mSystemAudioModeChangeListeners.add(listener);
mSystemAudioModeChangeListenerRecords.add(record);
}
}
@@ -1486,37 +1501,41 @@
break;
}
}
- mSystemAudioModeChangeListeners.remove(listener);
}
}
private final class InputChangeListenerRecord implements IBinder.DeathRecipient {
+ private final IHdmiInputChangeListener mListener;
+
+ public InputChangeListenerRecord(IHdmiInputChangeListener listener) {
+ mListener = listener;
+ }
+
@Override
public void binderDied() {
synchronized (mLock) {
- mInputChangeListener = null;
+ mInputChangeListenerRecord = null;
}
}
}
private void setInputChangeListener(IHdmiInputChangeListener listener) {
synchronized (mLock) {
- mInputChangeListenerRecord = new InputChangeListenerRecord();
+ mInputChangeListenerRecord = new InputChangeListenerRecord(listener);
try {
listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0);
} catch (RemoteException e) {
Slog.w(TAG, "Listener already died");
return;
}
- mInputChangeListener = listener;
}
}
void invokeInputChangeListener(HdmiDeviceInfo info) {
synchronized (mLock) {
- if (mInputChangeListener != null) {
+ if (mInputChangeListenerRecord != null) {
try {
- mInputChangeListener.onChanged(info);
+ mInputChangeListenerRecord.mListener.onChanged(info);
} catch (RemoteException e) {
Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e);
}
@@ -1526,21 +1545,20 @@
private void setHdmiRecordListener(IHdmiRecordListener listener) {
synchronized (mLock) {
- mRecordListenerRecord = new HdmiRecordListenerRecord();
+ mRecordListenerRecord = new HdmiRecordListenerRecord(listener);
try {
listener.asBinder().linkToDeath(mRecordListenerRecord, 0);
} catch (RemoteException e) {
Slog.w(TAG, "Listener already died.", e);
}
- mRecordListener = listener;
}
}
byte[] invokeRecordRequestListener(int recorderAddress) {
synchronized (mLock) {
- if (mRecordListener != null) {
+ if (mRecordListenerRecord != null) {
try {
- return mRecordListener.getOneTouchRecordSource(recorderAddress);
+ return mRecordListenerRecord.mListener.getOneTouchRecordSource(recorderAddress);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to start record.", e);
}
@@ -1551,9 +1569,9 @@
void invokeOneTouchRecordResult(int result) {
synchronized (mLock) {
- if (mRecordListener != null) {
+ if (mRecordListenerRecord != null) {
try {
- mRecordListener.onOneTouchRecordResult(result);
+ mRecordListenerRecord.mListener.onOneTouchRecordResult(result);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e);
}
@@ -1563,9 +1581,9 @@
void invokeTimerRecordingResult(int result) {
synchronized (mLock) {
- if (mRecordListener != null) {
+ if (mRecordListenerRecord != null) {
try {
- mRecordListener.onTimerRecordingResult(result);
+ mRecordListenerRecord.mListener.onTimerRecordingResult(result);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to call onTimerRecordingResult.", e);
}
@@ -1575,9 +1593,9 @@
void invokeClearTimerRecordingResult(int result) {
synchronized (mLock) {
- if (mRecordListener != null) {
+ if (mRecordListenerRecord != null) {
try {
- mRecordListener.onClearTimerRecordingResult(result);
+ mRecordListenerRecord.mListener.onClearTimerRecordingResult(result);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e);
}
@@ -1593,7 +1611,7 @@
}
}
- private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener,
+ private void invokeSystemAudioModeChangeLocked(IHdmiSystemAudioModeChangeListener listener,
boolean enabled) {
try {
listener.onStatusChanged(enabled);
@@ -1605,8 +1623,8 @@
private void announceHotplugEvent(int portId, boolean connected) {
HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected);
synchronized (mLock) {
- for (IHdmiHotplugEventListener listener : mHotplugEventListeners) {
- invokeHotplugEventListenerLocked(listener, event);
+ for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) {
+ invokeHotplugEventListenerLocked(record.mListener, event);
}
}
}
@@ -1805,6 +1823,34 @@
}
}
+ private void addHdmiMhlScratchpadCommandListener(IHdmiMhlScratchpadCommandListener listener) {
+ HdmiMhlScratchpadCommandListenerRecord record =
+ new HdmiMhlScratchpadCommandListenerRecord(listener);
+ try {
+ listener.asBinder().linkToDeath(record, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Listener already died.");
+ return;
+ }
+
+ synchronized (mLock) {
+ mScratchpadCommandListenerRecords.add(record);
+ }
+ }
+
+ void invokeScratchpadCommandListeners(int portId, int offest, int length, byte[] data) {
+ synchronized (mLock) {
+ for (HdmiMhlScratchpadCommandListenerRecord record :
+ mScratchpadCommandListenerRecords) {
+ try {
+ record.mListener.onReceived(portId, offest, length, data);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to notify scratchpad command", e);
+ }
+ }
+ }
+ }
+
boolean isProhibitMode() {
synchronized (mLock) {
return mProhibitMode;
diff --git a/services/core/java/com/android/server/hdmi/HdmiLogger.java b/services/core/java/com/android/server/hdmi/HdmiLogger.java
new file mode 100644
index 0000000..36159cb
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiLogger.java
@@ -0,0 +1,84 @@
+/*
+ * 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 com.android.server.hdmi;
+
+import android.os.SystemClock;
+import android.util.Pair;
+import android.util.Slog;
+
+import java.util.HashMap;
+
+/**
+ * A logger that prevents spammy log. For the same log message, it logs once every 20seconds.
+ * This class is not thread-safe.
+ */
+final class HdmiLogger {
+ // Logging duration for same error message.
+ private static final long ERROR_LOG_DURATTION_MILLIS = 20 * 1000; // 20s
+
+ // Key (String): log message.
+ // Value (Pair(Long, Integer)): a pair of last log time millis and the number of logMessage.
+ // Cache for warning.
+ private final HashMap<String, Pair<Long, Integer>> mWarningTimingCache = new HashMap<>();
+ // Cache for error.
+ private final HashMap<String, Pair<Long, Integer>> mErrorTimingCache = new HashMap<>();
+
+ private final String mTag;
+
+ HdmiLogger(String tag) {
+ mTag = tag;
+ }
+
+ void warning(String logMessage) {
+ long curTime = SystemClock.uptimeMillis();
+ Pair<Long, Integer> timing = mWarningTimingCache.get(logMessage);
+ if (shouldLogNow(timing, curTime)) {
+ Slog.w(mTag, buildMessage(logMessage, timing));
+ mWarningTimingCache.put(logMessage, new Pair<>(curTime, 1));
+ } else {
+ increaseLogCount(mWarningTimingCache, logMessage);
+ }
+ }
+
+ void error(String logMessage) {
+ long curTime = SystemClock.uptimeMillis();
+ Pair<Long, Integer> timing = mErrorTimingCache.get(logMessage);
+ if (shouldLogNow(timing, curTime)) {
+ Slog.e(mTag, buildMessage(logMessage, timing));
+ mErrorTimingCache.put(logMessage, new Pair<>(curTime, 1));
+ } else {
+ increaseLogCount(mErrorTimingCache, logMessage);
+ }
+ }
+
+ private String buildMessage(String message, Pair<Long, Integer> timing) {
+ return new StringBuilder()
+ .append("[").append(timing.second).append("]:").append(message)
+ .toString();
+ }
+
+ private void increaseLogCount(HashMap<String, Pair<Long, Integer>> cache, String message) {
+ Pair<Long, Integer> timing = cache.get(message);
+ if (timing != null) {
+ cache.put(message, new Pair<>(timing.first, timing.second + 1));
+ }
+ }
+
+ private boolean shouldLogNow(Pair<Long, Integer> timing, long curTime) {
+ return timing == null || curTime - timing.first > ERROR_LOG_DURATTION_MILLIS;
+ }
+}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 14457ec..6771cce 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -162,6 +162,7 @@
JobStatus jobStatus = new JobStatus(job, uId);
cancelJob(uId, job.getId());
startTrackingJob(jobStatus);
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
return JobScheduler.RESULT_SUCCESS;
}
@@ -507,7 +508,9 @@
case MSG_JOB_EXPIRED:
synchronized (mJobs) {
JobStatus runNow = (JobStatus) message.obj;
- if (!mPendingJobs.contains(runNow)) {
+ // runNow can be null, which is a controller's way of indicating that its
+ // state is such that all ready jobs should be run immediately.
+ if (runNow != null && !mPendingJobs.contains(runNow)) {
mPendingJobs.add(runNow);
}
}
diff --git a/services/core/java/com/android/server/job/StateChangedListener.java b/services/core/java/com/android/server/job/StateChangedListener.java
index 90c203a..97dfad3 100644
--- a/services/core/java/com/android/server/job/StateChangedListener.java
+++ b/services/core/java/com/android/server/job/StateChangedListener.java
@@ -33,7 +33,8 @@
/**
* Called by the controller to notify the JobManager that regardless of the state of the task,
* it must be run immediately.
- * @param jobStatus The state of the task which is to be run immediately.
+ * @param jobStatus The state of the task which is to be run immediately. <strong>null
+ * indicates to the scheduler that any ready jobs should be flushed.</strong>
*/
public void onRunJobNow(JobStatus jobStatus);
}
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index 538a252..309e034 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -84,15 +84,15 @@
@Override
public void maybeStartTrackingJob(JobStatus taskStatus) {
+ final boolean isOnStablePower = mChargeTracker.isOnStablePower();
if (taskStatus.hasChargingConstraint()) {
- final boolean isOnStablePower = mChargeTracker.isOnStablePower();
synchronized (mTrackedTasks) {
mTrackedTasks.add(taskStatus);
taskStatus.chargingConstraintSatisfied.set(isOnStablePower);
}
- if (isOnStablePower) {
- mStateChangedListener.onControllerStateChanged();
- }
+ }
+ if (isOnStablePower) {
+ mChargeTracker.setStableChargingAlarm();
}
}
@@ -119,9 +119,15 @@
}
}
}
+ // Let the scheduler know that state has changed. This may or may not result in an
+ // execution.
if (reportChange) {
mStateChangedListener.onControllerStateChanged();
}
+ // Also tell the scheduler that any ready jobs should be flushed.
+ if (stablePower) {
+ mStateChangedListener.onRunJobNow(null);
+ }
}
public class ChargingTracker extends BroadcastReceiver {
@@ -196,9 +202,7 @@
}
// Set up an alarm for ACTION_CHARGING_STABLE - we don't want to kick off tasks
// here if the user unplugs the phone immediately.
- mAlarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + STABLE_CHARGING_THRESHOLD_MILLIS,
- mStableChargingTriggerIntent);
+ setStableChargingAlarm();
mCharging = true;
} else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
if (DEBUG) {
@@ -211,7 +215,7 @@
}else if (ACTION_CHARGING_STABLE.equals(action)) {
// Here's where we actually do the notify for a task being ready.
if (DEBUG) {
- Slog.d(TAG, "Battery connected fired @ " + SystemClock.elapsedRealtime()
+ Slog.d(TAG, "Stable charging fired @ " + SystemClock.elapsedRealtime()
+ " charging: " + mCharging);
}
if (mCharging) { // Should never receive this intent if mCharging is false.
@@ -219,6 +223,17 @@
}
}
}
+
+ void setStableChargingAlarm() {
+ final long alarmTriggerElapsed =
+ SystemClock.elapsedRealtime() + STABLE_CHARGING_THRESHOLD_MILLIS;
+ if (DEBUG) {
+ Slog.d(TAG, "Setting stable alarm to go off in " +
+ (STABLE_CHARGING_THRESHOLD_MILLIS / 1000) + "s");
+ }
+ mAlarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTriggerElapsed,
+ mStableChargingTriggerIntent);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b57a090..32f3707 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5801,6 +5801,29 @@
SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
}
+ private static void convertCropForSurfaceFlinger(Rect crop, int rot, int dw, int dh) {
+ if (rot == Surface.ROTATION_90) {
+ final int tmp = crop.top;
+ crop.top = dw - crop.right;
+ crop.right = crop.bottom;
+ crop.bottom = dw - crop.left;
+ crop.left = tmp;
+ } else if (rot == Surface.ROTATION_180) {
+ int tmp = crop.top;
+ crop.top = dh - crop.bottom;
+ crop.bottom = dh - tmp;
+ tmp = crop.right;
+ crop.right = dw - crop.left;
+ crop.left = dw - tmp;
+ } else if (rot == Surface.ROTATION_270) {
+ final int tmp = crop.top;
+ crop.top = crop.left;
+ crop.left = dh - crop.bottom;
+ crop.bottom = crop.right;
+ crop.right = dh - tmp;
+ }
+ }
+
/**
* Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
* In portrait mode, it grabs the upper region of the screen based on the vertical dimension
@@ -5962,21 +5985,31 @@
// Constrain frame to the screen size.
frame.intersect(0, 0, dw, dh);
- // Constrain thumbnail to smaller of screen width or height. Assumes aspect
- // of thumbnail is the same as the screen (in landscape) or square.
- scale = Math.max(width / (float) frame.width(), height / (float) frame.height());
- dw = (int)(dw * scale);
- dh = (int)(dh * scale);
+
+ // Tell surface flinger what part of the image to crop. Take the top
+ // right part of the application, and crop the larger dimension to fit.
+ Rect crop = new Rect(frame);
+ if (width / (float) frame.width() < height / (float) frame.height()) {
+ int cropWidth = (int)((float)width / (float)height * frame.height());
+ crop.right = crop.left + cropWidth;
+ } else {
+ int cropHeight = (int)((float)height / (float)width * frame.width());
+ crop.bottom = crop.top + cropHeight;
+ }
// The screenshot API does not apply the current screen rotation.
rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
- final int tmp = dw;
- dw = dh;
- dh = tmp;
+ final int tmp = width;
+ width = height;
+ height = tmp;
rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
}
+ // Surfaceflinger is not aware of orientation, so convert our logical
+ // crop to surfaceflinger's portrait orientation.
+ convertCropForSurfaceFlinger(crop, rot, dw, dh);
+
if (DEBUG_SCREENSHOT) {
Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
+ maxLayer + " appToken=" + appToken);
@@ -5995,7 +6028,7 @@
if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG,
"Taking screenshot while rotating");
- rawss = SurfaceControl.screenshot(new Rect(), dw, dh, minLayer, maxLayer,
+ rawss = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer,
inRotation);
if (rawss == null) {
Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh
@@ -6012,11 +6045,8 @@
if (DEBUG_SCREENSHOT) {
bm.eraseColor(0xFF000000);
}
- frame.scale(scale);
Matrix matrix = new Matrix();
- ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
- // TODO: Test for RTL vs. LTR and use frame.right-width instead of -frame.left
- matrix.postTranslate(-FloatMath.ceil(frame.left), -FloatMath.ceil(frame.top));
+ ScreenRotationAnimation.createRotationMatrix(rot, width, height, matrix);
Canvas canvas = new Canvas(bm);
canvas.drawBitmap(rawss, matrix, null);
canvas.setBitmap(null);
@@ -6042,6 +6072,7 @@
}
rawss.recycle();
+
return bm;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 4b60c9f..5938819 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -267,6 +267,9 @@
if (mDeviceOwner != null) {
out.startTag(null, TAG_DEVICE_OWNER);
out.attribute(null, ATTR_PACKAGE, mDeviceOwner.packageName);
+ if (mDeviceOwner.name != null) {
+ out.attribute(null, ATTR_NAME, mDeviceOwner.name);
+ }
out.endTag(null, TAG_DEVICE_OWNER);
}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 4ff3899..f25fc62 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -8,11 +8,13 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
+ services.core \
+ services.devicepolicy \
easymocklib \
guava \
mockito-target
-LOCAL_JAVA_LIBRARIES := android.test.runner services
+LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksServicesTests
diff --git a/telecomm/java/android/telecomm/Conference.java b/telecomm/java/android/telecomm/Conference.java
index 34b9dae..44accb7 100644
--- a/telecomm/java/android/telecomm/Conference.java
+++ b/telecomm/java/android/telecomm/Conference.java
@@ -163,6 +163,7 @@
* @return True if the connection was successfully removed.
*/
public void removeConnection(Connection connection) {
+ Log.d(this, "removing %s from %s", connection, mChildConnections);
if (connection != null && mChildConnections.remove(connection)) {
connection.resetConference();
for (Listener l : mListeners) {
@@ -177,7 +178,7 @@
public void destroy() {
Log.d(this, "destroying conference : %s", this);
// Tear down the children.
- for (Connection connection : new ArrayList<>(mChildConnections)) {
+ for (Connection connection : mChildConnections) {
Log.d(this, "removing connection %s", connection);
removeConnection(connection);
}
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index c307a25..3aa4baf 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -914,10 +914,11 @@
*/
public final boolean setConference(Conference conference) {
// We check to see if it is already part of another conference.
- if (mConference == null && mConnectionService != null &&
- mConnectionService.containsConference(conference)) {
+ if (mConference == null) {
mConference = conference;
- fireConferenceChanged();
+ if (mConnectionService != null && mConnectionService.containsConference(conference)) {
+ fireConferenceChanged();
+ }
return true;
}
return false;
@@ -929,6 +930,7 @@
*/
public final void resetConference() {
if (mConference != null) {
+ Log.d(this, "Conference reset");
mConference = null;
fireConferenceChanged();
}
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index c805978..b77bb18 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -84,6 +84,7 @@
private final ConnectionServiceAdapter mAdapter = new ConnectionServiceAdapter();
private boolean mAreAccountsInitialized = false;
+ private Conference sNullConference;
private final IBinder mBinder = new IConnectionService.Stub() {
@Override
@@ -561,17 +562,29 @@
private void disconnect(String callId) {
Log.d(this, "disconnect %s", callId);
- findConnectionForAction(callId, "disconnect").onDisconnect();
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "disconnect").onDisconnect();
+ } else {
+ findConferenceForAction(callId, "disconnect").onDisconnect();
+ }
}
private void hold(String callId) {
Log.d(this, "hold %s", callId);
- findConnectionForAction(callId, "hold").onHold();
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "hold").onHold();
+ } else {
+ findConferenceForAction(callId, "hold").onHold();
+ }
}
private void unhold(String callId) {
Log.d(this, "unhold %s", callId);
- findConnectionForAction(callId, "unhold").onUnhold();
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "unhold").onUnhold();
+ } else {
+ findConferenceForAction(callId, "unhold").onUnhold();
+ }
}
private void onAudioStateChanged(String callId, AudioState audioState) {
@@ -616,7 +629,10 @@
return;
}
- // TODO: Find existing conference call and invoke split(connection).
+ Conference conference = connection.getConference();
+ if (conference != null) {
+ conference.onSeparate(connection);
+ }
}
private void onPostDialContinue(String callId, boolean proceed) {
@@ -885,4 +901,19 @@
}
return sNullConnection;
}
+
+ private Conference findConferenceForAction(String conferenceId, String action) {
+ if (mConferenceById.containsKey(conferenceId)) {
+ return mConferenceById.get(conferenceId);
+ }
+ Log.w(this, "%s - Cannot find conference %s", action, conferenceId);
+ return getNullConference();
+ }
+
+ private Conference getNullConference() {
+ if (sNullConference == null) {
+ sNullConference = new Conference(null) {};
+ }
+ return sNullConference;
+ }
}
diff --git a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
index 41c6360..cb63646 100644
--- a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
@@ -197,6 +197,7 @@
void setIsConferenced(String callId, String conferenceCallId) {
for (IConnectionServiceAdapter adapter : mAdapters) {
try {
+ Log.d(this, "sending connection %s with conference %s", callId, conferenceCallId);
adapter.setIsConferenced(callId, conferenceCallId);
} catch (RemoteException ignored) {
}
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index dcd0b79..767ecf9 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -21,6 +21,8 @@
import android.os.Parcelable;
import android.telecomm.VideoProfile;
+import com.android.internal.telephony.PhoneConstants;
+
/**
* Parcelable object to handle IMS call profile.
* It is created from GSMA IR.92/IR.94, 3GPP TS 24.229/TS 26.114/TS26.111.
@@ -337,6 +339,38 @@
}
/**
+ * Translate presentation value to OIR value
+ * @param presentation
+ * @return OIR valuse
+ */
+ public static int presentationToOIR(int presentation) {
+ switch (presentation) {
+ case PhoneConstants.PRESENTATION_RESTRICTED:
+ return ImsCallProfile.OIR_PRESENTATION_RESTRICTED;
+ case PhoneConstants.PRESENTATION_ALLOWED:
+ return ImsCallProfile.OIR_PRESENTATION_NOT_RESTRICTED;
+ default:
+ return ImsCallProfile.OIR_DEFAULT;
+ }
+ }
+
+ /**
+ * Translate OIR value to presentation value
+ * @param oir value
+ * @return presentation value
+ */
+ public static int OIRToPresentation(int oir) {
+ switch(oir) {
+ case ImsCallProfile.OIR_PRESENTATION_RESTRICTED:
+ return PhoneConstants.PRESENTATION_RESTRICTED;
+ case ImsCallProfile.OIR_PRESENTATION_NOT_RESTRICTED:
+ return PhoneConstants.PRESENTATION_ALLOWED;
+ default:
+ return PhoneConstants.PRESENTATION_UNKNOWN;
+ }
+ }
+
+ /**
* Determines if a video state is set in a video state bit-mask.
*
* @param videoState The video state bit mask.
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
index 08d7667..d402699 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
@@ -54,7 +54,7 @@
for (int i = 0; i < rowIndices.length; i++)
rowIndices[i] = i * REGION_SIZE;
- mScript = new ScriptC_errorCalculator(mRS, resources, R.raw.errorcalculator);
+ mScript = new ScriptC_errorCalculator(mRS);
mScript.set_HEIGHT(height);
mScript.set_WIDTH(width);
mScript.set_REGION_SIZE(REGION_SIZE);
diff --git a/tests/RenderScriptTests/FountainFbo/Android.mk b/tests/RenderScriptTests/FountainFbo/Android.mk
index 4535eb1..c0f3323 100644
--- a/tests/RenderScriptTests/FountainFbo/Android.mk
+++ b/tests/RenderScriptTests/FountainFbo/Android.mk
@@ -25,5 +25,6 @@
# LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := RsFountainFbo
+LOCAL_SDK_VERSION := 14
include $(BUILD_PACKAGE)
diff --git a/tests/Split/AndroidManifest.xml b/tests/Split/AndroidManifest.xml
index d5552de..0de8344 100644
--- a/tests/Split/AndroidManifest.xml
+++ b/tests/Split/AndroidManifest.xml
@@ -16,9 +16,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.example.split">
- <application android:label="@string/app_title">
- <activity android:name="ActivityMain"
+ <application android:label="@string/app_title"
android:icon="@mipmap/ic_app">
+ <activity android:name="ActivityMain">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index eead68c..b44e2d1 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -561,15 +561,17 @@
return NO_ERROR;
}
-#if 0
- printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
- file->getSourceFile().string(),
- file->getGroupEntry().toDirName(String8()).string(),
- mLeaf.string(), mPath.string());
-#endif
+ // Check if the version is automatically applied. This is a common source of
+ // error.
+ ConfigDescription withoutVersion = file->getGroupEntry().toParams();
+ withoutVersion.version = 0;
+ AaptConfig::applyVersionForCompatibility(&withoutVersion);
- SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
- getPrintableSource().string());
+ const sp<AaptFile>& originalFile = mFiles.valueAt(index);
+ SourcePos(file->getSourceFile(), -1)
+ .error("Duplicate file.\n%s: Original is here. %s",
+ originalFile->getPrintableSource().string(),
+ (withoutVersion.version != 0) ? "The version qualifier may be implied." : "");
return UNKNOWN_ERROR;
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 869a6fc..1d93b89 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1399,7 +1399,8 @@
sp<ApkSplit>& split = splits.editItemAt(i);
sp<AaptFile> flattenedTable = new AaptFile(String8("resources.arsc"),
AaptGroupEntry(), String8());
- err = table.flatten(bundle, split->getResourceFilter(), flattenedTable);
+ err = table.flatten(bundle, split->getResourceFilter(),
+ flattenedTable, split->isBase());
if (err != NO_ERROR) {
fprintf(stderr, "Failed to generate resource table for split '%s'\n",
split->getPrintableName().string());
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 49d8699..b3c364b 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2074,10 +2074,11 @@
return mNumLocal > 0;
}
-sp<AaptFile> ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter)
+sp<AaptFile> ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+ const bool isBase)
{
sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8());
- status_t err = flatten(bundle, filter, data);
+ status_t err = flatten(bundle, filter, data, isBase);
return err == NO_ERROR ? data : NULL;
}
@@ -2699,7 +2700,9 @@
return err;
}
-status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest)
+status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+ const sp<AaptFile>& dest,
+ const bool isBase)
{
const ConfigDescription nullConfig;
@@ -2768,6 +2771,13 @@
configTypeName = "2value";
}
+ // mipmaps don't get filtered, so they will
+ // allways end up in the base. Make sure they
+ // don't end up in a split.
+ if (typeName == mipmap16 && !isBase) {
+ continue;
+ }
+
const bool filterable = (typeName != mipmap16);
const size_t N = t->getOrderedConfigs().size();
@@ -2871,10 +2881,12 @@
return amt;
}
- status_t err = flattenLibraryTable(data, libraryPackages);
- if (err != NO_ERROR) {
- fprintf(stderr, "ERROR: failed to write library table\n");
- return err;
+ if (isBase) {
+ status_t err = flattenLibraryTable(data, libraryPackages);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: failed to write library table\n");
+ return err;
+ }
}
// Build the type chunks inside of this package.
@@ -2890,6 +2902,7 @@
continue;
}
const bool filterable = (typeName != mipmap16);
+ const bool skipEntireType = (typeName == mipmap16 && !isBase);
const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0;
@@ -2927,6 +2940,11 @@
if (cl->getPublic()) {
typeSpecFlags[ei] |= htodl(ResTable_typeSpec::SPEC_PUBLIC);
}
+
+ if (skipEntireType) {
+ continue;
+ }
+
const size_t CN = cl->getEntries().size();
for (size_t ci=0; ci<CN; ci++) {
if (filterable && !filter->match(cl->getEntries().keyAt(ci))) {
@@ -2943,6 +2961,10 @@
}
}
+ if (skipEntireType) {
+ continue;
+ }
+
// We need to write one type chunk for each configuration for
// which we have entries in this type.
const size_t NC = t->getUniqueConfigs().size();
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index d4f47ef..3721de4 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -165,7 +165,8 @@
size_t numLocalResources() const;
bool hasResources() const;
- sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter);
+ sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+ const bool isBase);
static inline uint32_t makeResId(uint32_t packageId,
uint32_t typeId,
@@ -206,7 +207,8 @@
void addLocalization(const String16& name, const String8& locale, const SourcePos& src);
status_t validateLocalizations(void);
- status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest);
+ status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+ const sp<AaptFile>& dest, const bool isBase);
status_t flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs);
void writePublicDefinitions(const String16& package, FILE* fp);
diff --git a/tools/aapt/tests/ResourceFilter_test.cpp b/tools/aapt/tests/ResourceFilter_test.cpp
index 30697bb..b55379e 100644
--- a/tools/aapt/tests/ResourceFilter_test.cpp
+++ b/tools/aapt/tests/ResourceFilter_test.cpp
@@ -126,3 +126,38 @@
EXPECT_TRUE(filter.match(config));
}
+TEST(StrongResourceFilterTest, MatchesDensities) {
+ ConfigDescription config;
+ config.density = 160;
+ config.version = 4;
+ std::set<ConfigDescription> configs;
+ configs.insert(config);
+
+ StrongResourceFilter filter(configs);
+
+ ConfigDescription expectedConfig;
+ expectedConfig.density = 160;
+ expectedConfig.version = 4;
+ ASSERT_TRUE(filter.match(expectedConfig));
+}
+
+TEST(StrongResourceFilterTest, MatchOnlyMdpiAndExcludeAllOthers) {
+ std::set<ConfigDescription> configsToMatch;
+ ConfigDescription config;
+ config.density = 160;
+ config.version = 4;
+ configsToMatch.insert(config);
+
+ std::set<ConfigDescription> configsToNotMatch;
+ config.density = 480;
+ configsToNotMatch.insert(config);
+
+ AndResourceFilter filter;
+ filter.addFilter(new InverseResourceFilter(new StrongResourceFilter(configsToNotMatch)));
+ filter.addFilter(new StrongResourceFilter(configsToMatch));
+
+ ConfigDescription expectedConfig;
+ expectedConfig.density = 160;
+ expectedConfig.version = 4;
+ ASSERT_TRUE(filter.match(expectedConfig));
+}