summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/animation/AnimatorInflater.java15
-rw-r--r--core/java/android/animation/FloatKeyframeSet.java9
-rw-r--r--core/java/android/animation/IntKeyframeSet.java9
-rw-r--r--core/java/android/animation/KeyframeSet.java19
-rw-r--r--core/java/android/animation/Keyframes.java94
-rw-r--r--core/java/android/animation/LayoutTransition.java14
-rw-r--r--core/java/android/animation/ObjectAnimator.java41
-rw-r--r--core/java/android/animation/PathKeyframes.java254
-rw-r--r--core/java/android/animation/PropertyValuesHolder.java240
-rw-r--r--core/java/android/app/Activity.java4
-rw-r--r--core/java/android/app/AppOpsManager.java5
-rw-r--r--core/java/android/app/ApplicationPackageManager.java29
-rw-r--r--core/java/android/app/BackStackRecord.java763
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java10
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java6
-rw-r--r--core/java/android/app/Fragment.java583
-rw-r--r--core/java/android/app/FragmentManager.java13
-rw-r--r--core/java/android/app/FragmentTransaction.java17
-rw-r--r--core/java/android/app/INotificationManager.aidl5
-rw-r--r--core/java/android/app/Notification.java151
-rw-r--r--core/java/android/app/NotificationManager.java13
-rw-r--r--core/java/android/app/VoiceInteractor.java3
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java12
-rw-r--r--core/java/android/app/usage/UsageEvents.java4
-rw-r--r--core/java/android/app/usage/UsageStats.java16
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java10
-rw-r--r--core/java/android/content/Context.java56
-rw-r--r--core/java/android/content/Intent.java104
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl17
-rw-r--r--core/java/android/content/pm/KeySet.aidl19
-rw-r--r--core/java/android/content/pm/KeySet.java60
-rw-r--r--core/java/android/content/pm/PackageManager.java7
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java7
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java2
-rw-r--r--core/java/android/hardware/display/DisplayManager.java12
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java46
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl10
-rw-r--r--core/java/android/hardware/display/IVirtualDisplayCallback.aidl (renamed from core/java/android/hardware/display/IVirtualDisplayCallbacks.aidl)8
-rw-r--r--core/java/android/hardware/display/VirtualDisplay.java12
-rw-r--r--core/java/android/net/ConnectivityManager.java17
-rw-r--r--core/java/android/net/IConnectivityManager.aidl1
-rw-r--r--core/java/android/net/Network.java31
-rw-r--r--core/java/android/net/NetworkInfo.java8
-rw-r--r--core/java/android/os/INetworkManagementService.aidl5
-rw-r--r--core/java/android/os/IUserManager.aidl1
-rw-r--r--core/java/android/os/UserManager.java16
-rw-r--r--core/java/android/os/storage/IMountService.java8
-rw-r--r--core/java/android/preference/CheckBoxPreference.java1
-rw-r--r--core/java/android/preference/SwitchPreference.java2
-rw-r--r--core/java/android/preference/TwoStatePreference.java29
-rw-r--r--core/java/android/provider/Settings.java29
-rw-r--r--core/java/android/security/IKeystoreService.java62
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java95
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java9
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java77
-rw-r--r--core/java/android/transition/ChangeBounds.java92
-rw-r--r--core/java/android/transition/TransitionUtils.java27
-rw-r--r--core/java/android/util/Spline.java325
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java58
-rw-r--r--core/java/android/view/PointerIcon.java12
-rw-r--r--core/java/android/view/ViewRootImpl.java38
-rw-r--r--core/java/android/view/Window.java61
-rw-r--r--core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl19
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java10
-rw-r--r--core/java/android/view/inputmethod/CursorAnchorInfo.java93
-rw-r--r--core/java/android/view/inputmethod/InputConnection.java30
-rw-r--r--core/java/android/view/inputmethod/InputConnectionWrapper.java13
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java10
-rw-r--r--core/java/android/widget/AbsListView.java10
-rw-r--r--core/java/android/widget/AdapterView.java2
-rw-r--r--core/java/android/widget/Editor.java29
-rw-r--r--core/java/android/widget/RemoteViews.java6
-rw-r--r--core/java/android/widget/TextView.java8
-rw-r--r--core/java/android/widget/Toolbar.java11
-rw-r--r--core/java/android/widget/VideoView.java4
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java4
-rw-r--r--core/java/com/android/internal/app/ToolbarActionBar.java26
-rw-r--r--core/java/com/android/internal/view/IInputConnectionWrapper.java2
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java9
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java8
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java19
81 files changed, 3066 insertions, 950 deletions
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index e57be83..f4e4671 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -370,14 +370,23 @@ public class AnimatorInflater {
+ " propertyXName or propertyYName is needed for PathData");
} else {
Path path = PathParser.createPathFromPathData(pathData);
- Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, !getFloats);
+ PathKeyframes keyframeSet = KeyframeSet.ofPath(path);
+ Keyframes xKeyframes;
+ Keyframes yKeyframes;
+ if (getFloats) {
+ xKeyframes = keyframeSet.createXFloatKeyframes();
+ yKeyframes = keyframeSet.createYFloatKeyframes();
+ } else {
+ xKeyframes = keyframeSet.createXIntKeyframes();
+ yKeyframes = keyframeSet.createYIntKeyframes();
+ }
PropertyValuesHolder x = null;
PropertyValuesHolder y = null;
if (propertyXName != null) {
- x = PropertyValuesHolder.ofKeyframe(propertyXName, keyframes[0]);
+ x = PropertyValuesHolder.ofKeyframes(propertyXName, xKeyframes);
}
if (propertyYName != null) {
- y = PropertyValuesHolder.ofKeyframe(propertyYName, keyframes[1]);
+ y = PropertyValuesHolder.ofKeyframes(propertyYName, yKeyframes);
}
if (x == null) {
oa.setValues(y);
diff --git a/core/java/android/animation/FloatKeyframeSet.java b/core/java/android/animation/FloatKeyframeSet.java
index 2d87e13..12e5862 100644
--- a/core/java/android/animation/FloatKeyframeSet.java
+++ b/core/java/android/animation/FloatKeyframeSet.java
@@ -30,7 +30,7 @@ import java.util.ArrayList;
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
* Object equivalents of these primitive types.</p>
*/
-class FloatKeyframeSet extends KeyframeSet {
+class FloatKeyframeSet extends KeyframeSet implements Keyframes.FloatKeyframes {
private float firstValue;
private float lastValue;
private float deltaValue;
@@ -58,10 +58,11 @@ class FloatKeyframeSet extends KeyframeSet {
}
@Override
- void invalidateCache() {
+ public void invalidateCache() {
firstTime = true;
}
+ @Override
public float getFloatValue(float fraction) {
if (mNumKeyframes == 2) {
if (firstTime) {
@@ -135,5 +136,9 @@ class FloatKeyframeSet extends KeyframeSet {
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
}
+ @Override
+ public Class getType() {
+ return Float.class;
+ }
}
diff --git a/core/java/android/animation/IntKeyframeSet.java b/core/java/android/animation/IntKeyframeSet.java
index ce47e2b..7a5b0ec 100644
--- a/core/java/android/animation/IntKeyframeSet.java
+++ b/core/java/android/animation/IntKeyframeSet.java
@@ -30,7 +30,7 @@ import java.util.ArrayList;
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
* Object equivalents of these primitive types.</p>
*/
-class IntKeyframeSet extends KeyframeSet {
+class IntKeyframeSet extends KeyframeSet implements Keyframes.IntKeyframes {
private int firstValue;
private int lastValue;
private int deltaValue;
@@ -58,10 +58,11 @@ class IntKeyframeSet extends KeyframeSet {
}
@Override
- void invalidateCache() {
+ public void invalidateCache() {
firstTime = true;
}
+ @Override
public int getIntValue(float fraction) {
if (mNumKeyframes == 2) {
if (firstTime) {
@@ -134,5 +135,9 @@ class IntKeyframeSet extends KeyframeSet {
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).intValue();
}
+ @Override
+ public Class getType() {
+ return Integer.class;
+ }
}
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index a3db3a1..fc9bbb1 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -21,6 +21,7 @@ import java.util.Arrays;
import android.animation.Keyframe.IntKeyframe;
import android.animation.Keyframe.FloatKeyframe;
import android.animation.Keyframe.ObjectKeyframe;
+import android.graphics.Path;
import android.util.Log;
/**
@@ -28,7 +29,7 @@ import android.util.Log;
* values between those keyframes for a given animation. The class internal to the animation
* package because it is an implementation detail of how Keyframes are stored and used.
*/
-class KeyframeSet {
+class KeyframeSet implements Keyframes {
int mNumKeyframes;
@@ -52,7 +53,12 @@ class KeyframeSet {
* If subclass has variables that it calculates based on the Keyframes, it should reset them
* when this method is called because Keyframe contents might have changed.
*/
- void invalidateCache() {
+ @Override
+ public void invalidateCache() {
+ }
+
+ public ArrayList<Keyframe> getKeyframes() {
+ return mKeyframes;
}
public static KeyframeSet ofInt(int... values) {
@@ -144,6 +150,10 @@ class KeyframeSet {
return new KeyframeSet(keyframes);
}
+ public static PathKeyframes ofPath(Path path) {
+ return new PathKeyframes(path);
+ }
+
/**
* Sets the TypeEvaluator to be used when calculating animated values. This object
* is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet,
@@ -157,6 +167,11 @@ class KeyframeSet {
}
@Override
+ public Class getType() {
+ return mFirstKeyframe.getType();
+ }
+
+ @Override
public KeyframeSet clone() {
ArrayList<Keyframe> keyframes = mKeyframes;
int numKeyframes = mKeyframes.size();
diff --git a/core/java/android/animation/Keyframes.java b/core/java/android/animation/Keyframes.java
new file mode 100644
index 0000000..6611c6c
--- /dev/null
+++ b/core/java/android/animation/Keyframes.java
@@ -0,0 +1,94 @@
+/*
+ * 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.animation;
+
+import java.util.ArrayList;
+
+/**
+ * This interface abstracts a collection of Keyframe objects and is called by
+ * ValueAnimator to calculate values between those keyframes for a given animation.
+ */
+interface Keyframes extends Cloneable {
+
+ /**
+ * Sets the TypeEvaluator to be used when calculating animated values. This object
+ * is required only for Keyframes that are not either IntKeyframes or FloatKeyframes,
+ * both of which assume their own evaluator to speed up calculations with those primitive
+ * types.
+ *
+ * @param evaluator The TypeEvaluator to be used to calculate animated values.
+ */
+ void setEvaluator(TypeEvaluator evaluator);
+
+ /**
+ * @return The value type contained by the contained Keyframes.
+ */
+ Class getType();
+
+ /**
+ * Gets the animated value, given the elapsed fraction of the animation (interpolated by the
+ * animation's interpolator) and the evaluator used to calculate in-between values. This
+ * function maps the input fraction to the appropriate keyframe interval and a fraction
+ * between them and returns the interpolated value. Note that the input fraction may fall
+ * outside the [0-1] bounds, if the animation's interpolator made that happen (e.g., a
+ * spring interpolation that might send the fraction past 1.0). We handle this situation by
+ * just using the two keyframes at the appropriate end when the value is outside those bounds.
+ *
+ * @param fraction The elapsed fraction of the animation
+ * @return The animated value.
+ */
+ Object getValue(float fraction);
+
+ /**
+ * If subclass has variables that it calculates based on the Keyframes, it should reset them
+ * when this method is called because Keyframe contents might have changed.
+ */
+ void invalidateCache();
+
+ /**
+ * @return A list of all Keyframes contained by this. This may return null if this is
+ * not made up of Keyframes.
+ */
+ ArrayList<Keyframe> getKeyframes();
+
+ Keyframes clone();
+
+ /**
+ * A specialization of Keyframes that has integer primitive value calculation.
+ */
+ public interface IntKeyframes extends Keyframes {
+
+ /**
+ * Works like {@link #getValue(float)}, but returning a primitive.
+ * @param fraction The elapsed fraction of the animation
+ * @return The animated value.
+ */
+ int getIntValue(float fraction);
+ }
+
+ /**
+ * A specialization of Keyframes that has float primitive value calculation.
+ */
+ public interface FloatKeyframes extends Keyframes {
+
+ /**
+ * Works like {@link #getValue(float)}, but returning a primitive.
+ * @param fraction The elapsed fraction of the animation
+ * @return The animated value.
+ */
+ float getFloatValue(float fraction);
+ }
+}
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 188408d..5790682 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -899,11 +899,15 @@ public class LayoutTransition {
PropertyValuesHolder[] oldValues = valueAnim.getValues();
for (int i = 0; i < oldValues.length; ++i) {
PropertyValuesHolder pvh = oldValues[i];
- KeyframeSet keyframeSet = pvh.mKeyframeSet;
- if (keyframeSet.mFirstKeyframe == null ||
- keyframeSet.mLastKeyframe == null ||
- !keyframeSet.mFirstKeyframe.getValue().equals(
- keyframeSet.mLastKeyframe.getValue())) {
+ if (pvh.mKeyframes instanceof KeyframeSet) {
+ KeyframeSet keyframeSet = (KeyframeSet) pvh.mKeyframes;
+ if (keyframeSet.mFirstKeyframe == null ||
+ keyframeSet.mLastKeyframe == null ||
+ !keyframeSet.mFirstKeyframe.getValue().equals(
+ keyframeSet.mLastKeyframe.getValue())) {
+ valuesDiffer = true;
+ }
+ } else if (!pvh.mKeyframes.getValue(0).equals(pvh.mKeyframes.getValue(1))) {
valuesDiffer = true;
}
}
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index a4ac73f..500634c 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -239,9 +239,11 @@ public final class ObjectAnimator extends ValueAnimator {
*/
public static ObjectAnimator ofInt(Object target, String xPropertyName, String yPropertyName,
Path path) {
- Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, true);
- PropertyValuesHolder x = PropertyValuesHolder.ofKeyframe(xPropertyName, keyframes[0]);
- PropertyValuesHolder y = PropertyValuesHolder.ofKeyframe(yPropertyName, keyframes[1]);
+ PathKeyframes keyframes = KeyframeSet.ofPath(path);
+ PropertyValuesHolder x = PropertyValuesHolder.ofKeyframes(xPropertyName,
+ keyframes.createXIntKeyframes());
+ PropertyValuesHolder y = PropertyValuesHolder.ofKeyframes(yPropertyName,
+ keyframes.createYIntKeyframes());
return ofPropertyValuesHolder(target, x, y);
}
@@ -278,9 +280,11 @@ public final class ObjectAnimator extends ValueAnimator {
*/
public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> xProperty,
Property<T, Integer> yProperty, Path path) {
- Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, true);
- PropertyValuesHolder x = PropertyValuesHolder.ofKeyframe(xProperty, keyframes[0]);
- PropertyValuesHolder y = PropertyValuesHolder.ofKeyframe(yProperty, keyframes[1]);
+ PathKeyframes keyframes = KeyframeSet.ofPath(path);
+ PropertyValuesHolder x = PropertyValuesHolder.ofKeyframes(xProperty,
+ keyframes.createXIntKeyframes());
+ PropertyValuesHolder y = PropertyValuesHolder.ofKeyframes(yProperty,
+ keyframes.createYIntKeyframes());
return ofPropertyValuesHolder(target, x, y);
}
@@ -429,9 +433,11 @@ public final class ObjectAnimator extends ValueAnimator {
*/
public static ObjectAnimator ofFloat(Object target, String xPropertyName, String yPropertyName,
Path path) {
- Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, false);
- PropertyValuesHolder x = PropertyValuesHolder.ofKeyframe(xPropertyName, keyframes[0]);
- PropertyValuesHolder y = PropertyValuesHolder.ofKeyframe(yPropertyName, keyframes[1]);
+ PathKeyframes keyframes = KeyframeSet.ofPath(path);
+ PropertyValuesHolder x = PropertyValuesHolder.ofKeyframes(xPropertyName,
+ keyframes.createXFloatKeyframes());
+ PropertyValuesHolder y = PropertyValuesHolder.ofKeyframes(yPropertyName,
+ keyframes.createYFloatKeyframes());
return ofPropertyValuesHolder(target, x, y);
}
@@ -469,9 +475,11 @@ public final class ObjectAnimator extends ValueAnimator {
*/
public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> xProperty,
Property<T, Float> yProperty, Path path) {
- Keyframe[][] keyframes = PropertyValuesHolder.createKeyframes(path, false);
- PropertyValuesHolder x = PropertyValuesHolder.ofKeyframe(xProperty, keyframes[0]);
- PropertyValuesHolder y = PropertyValuesHolder.ofKeyframe(yProperty, keyframes[1]);
+ PathKeyframes keyframes = KeyframeSet.ofPath(path);
+ PropertyValuesHolder x = PropertyValuesHolder.ofKeyframes(xProperty,
+ keyframes.createXFloatKeyframes());
+ PropertyValuesHolder y = PropertyValuesHolder.ofKeyframes(yProperty,
+ keyframes.createYFloatKeyframes());
return ofPropertyValuesHolder(target, x, y);
}
@@ -652,6 +660,10 @@ public final class ObjectAnimator extends ValueAnimator {
* uses a type other than <code>PointF</code>, <code>converter</code> can be used to change
* from <code>PointF</code> to the type associated with the <code>Property</code>.
*
+ * <p>The PointF passed to <code>converter</code> or <code>property</code>, if
+ * <code>converter</code> is <code>null</code>, is reused on each animation frame and should
+ * not be stored by the setter or TypeConverter.</p>
+ *
* @param target The object whose property is to be animated.
* @param property The property being animated. Should not be null.
* @param converter Converts a PointF to the type associated with the setter. May be
@@ -809,10 +821,9 @@ public final class ObjectAnimator extends ValueAnimator {
Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
for (int i = 0; i < mValues.length; ++i) {
PropertyValuesHolder pvh = mValues[i];
- ArrayList<Keyframe> keyframes = pvh.mKeyframeSet.mKeyframes;
Log.d(LOG_TAG, " Values[" + i + "]: " +
- pvh.getPropertyName() + ", " + keyframes.get(0).getValue() + ", " +
- keyframes.get(pvh.mKeyframeSet.mNumKeyframes - 1).getValue());
+ pvh.getPropertyName() + ", " + pvh.mKeyframes.getValue(0) + ", " +
+ pvh.mKeyframes.getValue(1));
}
}
super.start();
diff --git a/core/java/android/animation/PathKeyframes.java b/core/java/android/animation/PathKeyframes.java
new file mode 100644
index 0000000..70eed90
--- /dev/null
+++ b/core/java/android/animation/PathKeyframes.java
@@ -0,0 +1,254 @@
+/*
+ * 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.animation;
+
+import android.graphics.Path;
+import android.graphics.PointF;
+import android.util.MathUtils;
+
+import java.util.ArrayList;
+
+/**
+ * PathKeyframes relies on approximating the Path as a series of line segments.
+ * The line segments are recursively divided until there is less than 1/2 pixel error
+ * between the lines and the curve. Each point of the line segment is converted
+ * to a Keyframe and a linear interpolation between Keyframes creates a good approximation
+ * of the curve.
+ * <p>
+ * PathKeyframes is optimized to reduce the number of objects created when there are
+ * many keyframes for a curve.
+ * </p>
+ * <p>
+ * Typically, the returned type is a PointF, but the individual components can be extracted
+ * as either an IntKeyframes or FloatKeyframes.
+ * </p>
+ */
+class PathKeyframes implements Keyframes {
+ private static final int FRACTION_OFFSET = 0;
+ private static final int X_OFFSET = 1;
+ private static final int Y_OFFSET = 2;
+ private static final int NUM_COMPONENTS = 3;
+ private static final ArrayList<Keyframe> EMPTY_KEYFRAMES = new ArrayList<Keyframe>();
+
+ private PointF mTempPointF = new PointF();
+ private float[] mKeyframeData;
+
+ public PathKeyframes(Path path) {
+ this(path, 0.5f);
+ }
+
+ public PathKeyframes(Path path, float error) {
+ if (path == null || path.isEmpty()) {
+ throw new IllegalArgumentException("The path must not be null or empty");
+ }
+ mKeyframeData = path.approximate(error);
+ }
+
+ @Override
+ public ArrayList<Keyframe> getKeyframes() {
+ return EMPTY_KEYFRAMES;
+ }
+
+ @Override
+ public Object getValue(float fraction) {
+ fraction = MathUtils.constrain(fraction, 0, 1);
+
+ int numPoints = mKeyframeData.length / 3;
+
+ if (fraction == 0) {
+ return pointForIndex(0);
+ } else if (fraction == 1) {
+ return pointForIndex(numPoints - 1);
+ } else {
+ // Binary search for the correct section
+ int low = 0;
+ int high = numPoints - 1;
+
+ while (low <= high) {
+ int mid = (low + high) / 2;
+ float midFraction = mKeyframeData[(mid * NUM_COMPONENTS) + FRACTION_OFFSET];
+
+ if (fraction < midFraction) {
+ high = mid - 1;
+ } else if (fraction > midFraction) {
+ low = mid + 1;
+ } else {
+ return pointForIndex(mid);
+ }
+ }
+
+ // now high is below the fraction and low is above the fraction
+ int startBase = (high * NUM_COMPONENTS);
+ int endBase = (low * NUM_COMPONENTS);
+
+ float startFraction = mKeyframeData[startBase + FRACTION_OFFSET];
+ float endFraction = mKeyframeData[endBase + FRACTION_OFFSET];
+
+ float intervalFraction = (fraction - startFraction)/(endFraction - startFraction);
+
+ float startX = mKeyframeData[startBase + X_OFFSET];
+ float endX = mKeyframeData[endBase + X_OFFSET];
+ float startY = mKeyframeData[startBase + Y_OFFSET];
+ float endY = mKeyframeData[endBase + Y_OFFSET];
+
+ float x = interpolate(intervalFraction, startX, endX);
+ float y = interpolate(intervalFraction, startY, endY);
+
+ mTempPointF.set(x, y);
+ return mTempPointF;
+ }
+ }
+
+ @Override
+ public void invalidateCache() {
+ }
+
+ @Override
+ public void setEvaluator(TypeEvaluator evaluator) {
+ }
+
+ @Override
+ public Class getType() {
+ return PointF.class;
+ }
+
+ @Override
+ public Keyframes clone() {
+ Keyframes clone = null;
+ try {
+ clone = (Keyframes) super.clone();
+ } catch (CloneNotSupportedException e) {}
+ return clone;
+ }
+
+ private PointF pointForIndex(int index) {
+ int base = (index * NUM_COMPONENTS);
+ int xOffset = base + X_OFFSET;
+ int yOffset = base + Y_OFFSET;
+ mTempPointF.set(mKeyframeData[xOffset], mKeyframeData[yOffset]);
+ return mTempPointF;
+ }
+
+ private static float interpolate(float fraction, float startValue, float endValue) {
+ float diff = endValue - startValue;
+ return startValue + (diff * fraction);
+ }
+
+ /**
+ * Returns a FloatKeyframes for the X component of the Path.
+ * @return a FloatKeyframes for the X component of the Path.
+ */
+ public FloatKeyframes createXFloatKeyframes() {
+ return new FloatKeyframesBase() {
+ @Override
+ public float getFloatValue(float fraction) {
+ PointF pointF = (PointF) PathKeyframes.this.getValue(fraction);
+ return pointF.x;
+ }
+ };
+ }
+
+ /**
+ * Returns a FloatKeyframes for the Y component of the Path.
+ * @return a FloatKeyframes for the Y component of the Path.
+ */
+ public FloatKeyframes createYFloatKeyframes() {
+ return new FloatKeyframesBase() {
+ @Override
+ public float getFloatValue(float fraction) {
+ PointF pointF = (PointF) PathKeyframes.this.getValue(fraction);
+ return pointF.y;
+ }
+ };
+ }
+
+ /**
+ * Returns an IntKeyframes for the X component of the Path.
+ * @return an IntKeyframes for the X component of the Path.
+ */
+ public IntKeyframes createXIntKeyframes() {
+ return new IntKeyframesBase() {
+ @Override
+ public int getIntValue(float fraction) {
+ PointF pointF = (PointF) PathKeyframes.this.getValue(fraction);
+ return Math.round(pointF.x);
+ }
+ };
+ }
+
+ /**
+ * Returns an IntKeyframeSet for the Y component of the Path.
+ * @return an IntKeyframeSet for the Y component of the Path.
+ */
+ public IntKeyframes createYIntKeyframes() {
+ return new IntKeyframesBase() {
+ @Override
+ public int getIntValue(float fraction) {
+ PointF pointF = (PointF) PathKeyframes.this.getValue(fraction);
+ return Math.round(pointF.y);
+ }
+ };
+ }
+
+ private abstract static class SimpleKeyframes implements Keyframes {
+ @Override
+ public void setEvaluator(TypeEvaluator evaluator) {
+ }
+
+ @Override
+ public void invalidateCache() {
+ }
+
+ @Override
+ public ArrayList<Keyframe> getKeyframes() {
+ return EMPTY_KEYFRAMES;
+ }
+
+ @Override
+ public Keyframes clone() {
+ Keyframes clone = null;
+ try {
+ clone = (Keyframes) super.clone();
+ } catch (CloneNotSupportedException e) {}
+ return clone;
+ }
+ }
+
+ private abstract static class IntKeyframesBase extends SimpleKeyframes implements IntKeyframes {
+ @Override
+ public Class getType() {
+ return Integer.class;
+ }
+
+ @Override
+ public Object getValue(float fraction) {
+ return getIntValue(fraction);
+ }
+ }
+
+ private abstract static class FloatKeyframesBase extends SimpleKeyframes
+ implements FloatKeyframes {
+ @Override
+ public Class getType() {
+ return Float.class;
+ }
+
+ @Override
+ public Object getValue(float fraction) {
+ return getFloatValue(fraction);
+ }
+ }
+}
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 73b83ef..d372933 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -18,7 +18,6 @@ package android.animation;
import android.graphics.Path;
import android.graphics.PointF;
-import android.util.FloatMath;
import android.util.FloatProperty;
import android.util.IntProperty;
import android.util.Log;
@@ -26,6 +25,7 @@ import android.util.Property;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -75,7 +75,7 @@ public class PropertyValuesHolder implements Cloneable {
/**
* The set of keyframes (time/value pairs) that define this animation.
*/
- KeyframeSet mKeyframeSet = null;
+ Keyframes mKeyframes = null;
// type evaluators for the primitive types handled by this implementation
@@ -219,11 +219,9 @@ public class PropertyValuesHolder implements Cloneable {
* @see ObjectAnimator#ofPropertyValuesHolder(Object, PropertyValuesHolder...)
*/
public static PropertyValuesHolder ofMultiInt(String propertyName, Path path) {
- Keyframe[] keyframes = createKeyframes(path);
- KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(keyframes);
- TypeEvaluator<PointF> evaluator = new PointFEvaluator(new PointF());
+ Keyframes keyframes = KeyframeSet.ofPath(path);
PointFToIntArray converter = new PointFToIntArray();
- return new MultiIntValuesHolder(propertyName, converter, evaluator, keyframeSet);
+ return new MultiIntValuesHolder(propertyName, converter, null, keyframes);
}
/**
@@ -339,11 +337,9 @@ public class PropertyValuesHolder implements Cloneable {
* @see ObjectAnimator#ofPropertyValuesHolder(Object, PropertyValuesHolder...)
*/
public static PropertyValuesHolder ofMultiFloat(String propertyName, Path path) {
- Keyframe[] keyframes = createKeyframes(path);
- KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(keyframes);
- TypeEvaluator<PointF> evaluator = new PointFEvaluator(new PointF());
+ Keyframes keyframes = KeyframeSet.ofPath(path);
PointFToFloatArray converter = new PointFToFloatArray();
- return new MultiFloatValuesHolder(propertyName, converter, evaluator, keyframeSet);
+ return new MultiFloatValuesHolder(propertyName, converter, null, keyframes);
}
/**
@@ -415,6 +411,10 @@ public class PropertyValuesHolder implements Cloneable {
* <code>TypeConverter</code> to convert from <code>PointF</code> to the target
* type.
*
+ * <p>The PointF passed to <code>converter</code> or <code>property</code>, if
+ * <code>converter</code> is <code>null</code>, is reused on each animation frame and should
+ * not be stored by the setter or TypeConverter.</p>
+ *
* @param propertyName The name of the property being animated.
* @param converter Converts a PointF to the type associated with the setter. May be
* null if conversion is unnecessary.
@@ -423,9 +423,9 @@ public class PropertyValuesHolder implements Cloneable {
*/
public static PropertyValuesHolder ofObject(String propertyName,
TypeConverter<PointF, ?> converter, Path path) {
- Keyframe[] keyframes = createKeyframes(path);
- PropertyValuesHolder pvh = ofKeyframe(propertyName, keyframes);
- pvh.setEvaluator(new PointFEvaluator(new PointF()));
+ PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
+ pvh.mKeyframes = KeyframeSet.ofPath(path);
+ pvh.mValueType = PointF.class;
pvh.setConverter(converter);
return pvh;
}
@@ -484,6 +484,10 @@ public class PropertyValuesHolder implements Cloneable {
* <code>TypeConverter</code> to convert from <code>PointF</code> to the target
* type.
*
+ * <p>The PointF passed to <code>converter</code> or <code>property</code>, if
+ * <code>converter</code> is <code>null</code>, is reused on each animation frame and should
+ * not be stored by the setter or TypeConverter.</p>
+ *
* @param property The property being animated. Should not be null.
* @param converter Converts a PointF to the type associated with the setter. May be
* null if conversion is unnecessary.
@@ -492,9 +496,9 @@ public class PropertyValuesHolder implements Cloneable {
*/
public static <V> PropertyValuesHolder ofObject(Property<?, V> property,
TypeConverter<PointF, V> converter, Path path) {
- Keyframe[] keyframes = createKeyframes(path);
- PropertyValuesHolder pvh = ofKeyframe(property, keyframes);
- pvh.setEvaluator(new PointFEvaluator(new PointF()));
+ PropertyValuesHolder pvh = new PropertyValuesHolder(property);
+ pvh.mKeyframes = KeyframeSet.ofPath(path);
+ pvh.mValueType = PointF.class;
pvh.setConverter(converter);
return pvh;
}
@@ -520,17 +524,7 @@ public class PropertyValuesHolder implements Cloneable {
*/
public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) {
KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
- if (keyframeSet instanceof IntKeyframeSet) {
- return new IntPropertyValuesHolder(propertyName, (IntKeyframeSet) keyframeSet);
- } else if (keyframeSet instanceof FloatKeyframeSet) {
- return new FloatPropertyValuesHolder(propertyName, (FloatKeyframeSet) keyframeSet);
- }
- else {
- PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
- pvh.mKeyframeSet = keyframeSet;
- pvh.mValueType = ((Keyframe)values[0]).getType();
- return pvh;
- }
+ return ofKeyframes(propertyName, keyframeSet);
}
/**
@@ -551,15 +545,32 @@ public class PropertyValuesHolder implements Cloneable {
*/
public static PropertyValuesHolder ofKeyframe(Property property, Keyframe... values) {
KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
- if (keyframeSet instanceof IntKeyframeSet) {
- return new IntPropertyValuesHolder(property, (IntKeyframeSet) keyframeSet);
- } else if (keyframeSet instanceof FloatKeyframeSet) {
- return new FloatPropertyValuesHolder(property, (FloatKeyframeSet) keyframeSet);
+ return ofKeyframes(property, keyframeSet);
+ }
+
+ static PropertyValuesHolder ofKeyframes(String propertyName, Keyframes keyframes) {
+ if (keyframes instanceof Keyframes.IntKeyframes) {
+ return new IntPropertyValuesHolder(propertyName, (Keyframes.IntKeyframes) keyframes);
+ } else if (keyframes instanceof Keyframes.FloatKeyframes) {
+ return new FloatPropertyValuesHolder(propertyName,
+ (Keyframes.FloatKeyframes) keyframes);
+ } else {
+ PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
+ pvh.mKeyframes = keyframes;
+ pvh.mValueType = keyframes.getType();
+ return pvh;
}
- else {
+ }
+
+ static PropertyValuesHolder ofKeyframes(Property property, Keyframes keyframes) {
+ if (keyframes instanceof Keyframes.IntKeyframes) {
+ return new IntPropertyValuesHolder(property, (Keyframes.IntKeyframes) keyframes);
+ } else if (keyframes instanceof Keyframes.FloatKeyframes) {
+ return new FloatPropertyValuesHolder(property, (Keyframes.FloatKeyframes) keyframes);
+ } else {
PropertyValuesHolder pvh = new PropertyValuesHolder(property);
- pvh.mKeyframeSet = keyframeSet;
- pvh.mValueType = ((Keyframe)values[0]).getType();
+ pvh.mKeyframes = keyframes;
+ pvh.mValueType = keyframes.getType();
return pvh;
}
}
@@ -579,7 +590,7 @@ public class PropertyValuesHolder implements Cloneable {
*/
public void setIntValues(int... values) {
mValueType = int.class;
- mKeyframeSet = KeyframeSet.ofInt(values);
+ mKeyframes = KeyframeSet.ofInt(values);
}
/**
@@ -597,7 +608,7 @@ public class PropertyValuesHolder implements Cloneable {
*/
public void setFloatValues(float... values) {
mValueType = float.class;
- mKeyframeSet = KeyframeSet.ofFloat(values);
+ mKeyframes = KeyframeSet.ofFloat(values);
}
/**
@@ -612,7 +623,7 @@ public class PropertyValuesHolder implements Cloneable {
for (int i = 0; i < numKeyframes; ++i) {
keyframes[i] = (Keyframe)values[i];
}
- mKeyframeSet = new KeyframeSet(keyframes);
+ mKeyframes = new KeyframeSet(keyframes);
}
/**
@@ -630,9 +641,9 @@ public class PropertyValuesHolder implements Cloneable {
*/
public void setObjectValues(Object... values) {
mValueType = values[0].getClass();
- mKeyframeSet = KeyframeSet.ofObject(values);
+ mKeyframes = KeyframeSet.ofObject(values);
if (mEvaluator != null) {
- mKeyframeSet.setEvaluator(mEvaluator);
+ mKeyframes.setEvaluator(mEvaluator);
}
}
@@ -775,12 +786,15 @@ public class PropertyValuesHolder implements Cloneable {
* @param target The object on which the setter (and possibly getter) exist.
*/
void setupSetterAndGetter(Object target) {
- mKeyframeSet.invalidateCache();
+ mKeyframes.invalidateCache();
if (mProperty != null) {
// check to make sure that mProperty is on the class of target
try {
Object testValue = null;
- for (Keyframe kf : mKeyframeSet.mKeyframes) {
+ ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+ int keyframeCount = keyframes == null ? 0 : keyframes.size();
+ for (int i = 0; i < keyframeCount; i++) {
+ Keyframe kf = keyframes.get(i);
if (!kf.hasValue() || kf.valueWasSetOnStart()) {
if (testValue == null) {
testValue = convertBack(mProperty.get(target));
@@ -800,7 +814,10 @@ public class PropertyValuesHolder implements Cloneable {
if (mSetter == null) {
setupSetter(targetClass);
}
- for (Keyframe kf : mKeyframeSet.mKeyframes) {
+ ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+ int keyframeCount = keyframes == null ? 0 : keyframes.size();
+ for (int i = 0; i < keyframeCount; i++) {
+ Keyframe kf = keyframes.get(i);
if (!kf.hasValue() || kf.valueWasSetOnStart()) {
if (mGetter == null) {
setupGetter(targetClass);
@@ -873,7 +890,10 @@ public class PropertyValuesHolder implements Cloneable {
* @param target The object which holds the start values that should be set.
*/
void setupStartValue(Object target) {
- setupValue(target, mKeyframeSet.mKeyframes.get(0));
+ ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+ if (!keyframes.isEmpty()) {
+ setupValue(target, keyframes.get(0));
+ }
}
/**
@@ -885,7 +905,10 @@ public class PropertyValuesHolder implements Cloneable {
* @param target The object which holds the start values that should be set.
*/
void setupEndValue(Object target) {
- setupValue(target, mKeyframeSet.mKeyframes.get(mKeyframeSet.mKeyframes.size() - 1));
+ ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes();
+ if (!keyframes.isEmpty()) {
+ setupValue(target, keyframes.get(keyframes.size() - 1));
+ }
}
@Override
@@ -894,7 +917,7 @@ public class PropertyValuesHolder implements Cloneable {
PropertyValuesHolder newPVH = (PropertyValuesHolder) super.clone();
newPVH.mPropertyName = mPropertyName;
newPVH.mProperty = mProperty;
- newPVH.mKeyframeSet = mKeyframeSet.clone();
+ newPVH.mKeyframes = mKeyframes.clone();
newPVH.mEvaluator = mEvaluator;
return newPVH;
} catch (CloneNotSupportedException e) {
@@ -941,7 +964,7 @@ public class PropertyValuesHolder implements Cloneable {
if (mEvaluator != null) {
// KeyframeSet knows how to evaluate the common types - only give it a custom
// evaluator if one has been set on this class
- mKeyframeSet.setEvaluator(mEvaluator);
+ mKeyframes.setEvaluator(mEvaluator);
}
}
@@ -957,7 +980,7 @@ public class PropertyValuesHolder implements Cloneable {
*/
public void setEvaluator(TypeEvaluator evaluator) {
mEvaluator = evaluator;
- mKeyframeSet.setEvaluator(evaluator);
+ mKeyframes.setEvaluator(evaluator);
}
/**
@@ -967,7 +990,7 @@ public class PropertyValuesHolder implements Cloneable {
* @param fraction The elapsed, interpolated fraction of the animation.
*/
void calculateValue(float fraction) {
- Object value = mKeyframeSet.getValue(fraction);
+ Object value = mKeyframes.getValue(fraction);
mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
}
@@ -1025,7 +1048,7 @@ public class PropertyValuesHolder implements Cloneable {
@Override
public String toString() {
- return mPropertyName + ": " + mKeyframeSet.toString();
+ return mPropertyName + ": " + mKeyframes.toString();
}
/**
@@ -1059,21 +1082,21 @@ public class PropertyValuesHolder implements Cloneable {
long mJniSetter;
private IntProperty mIntProperty;
- IntKeyframeSet mIntKeyframeSet;
+ Keyframes.IntKeyframes mIntKeyframes;
int mIntAnimatedValue;
- public IntPropertyValuesHolder(String propertyName, IntKeyframeSet keyframeSet) {
+ public IntPropertyValuesHolder(String propertyName, Keyframes.IntKeyframes keyframes) {
super(propertyName);
mValueType = int.class;
- mKeyframeSet = keyframeSet;
- mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
+ mKeyframes = keyframes;
+ mIntKeyframes = keyframes;
}
- public IntPropertyValuesHolder(Property property, IntKeyframeSet keyframeSet) {
+ public IntPropertyValuesHolder(Property property, Keyframes.IntKeyframes keyframes) {
super(property);
mValueType = int.class;
- mKeyframeSet = keyframeSet;
- mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
+ mKeyframes = keyframes;
+ mIntKeyframes = keyframes;
if (property instanceof IntProperty) {
mIntProperty = (IntProperty) mProperty;
}
@@ -1095,12 +1118,12 @@ public class PropertyValuesHolder implements Cloneable {
@Override
public void setIntValues(int... values) {
super.setIntValues(values);
- mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
+ mIntKeyframes = (Keyframes.IntKeyframes) mKeyframes;
}
@Override
void calculateValue(float fraction) {
- mIntAnimatedValue = mIntKeyframeSet.getIntValue(fraction);
+ mIntAnimatedValue = mIntKeyframes.getIntValue(fraction);
}
@Override
@@ -1111,7 +1134,7 @@ public class PropertyValuesHolder implements Cloneable {
@Override
public IntPropertyValuesHolder clone() {
IntPropertyValuesHolder newPVH = (IntPropertyValuesHolder) super.clone();
- newPVH.mIntKeyframeSet = (IntKeyframeSet) newPVH.mKeyframeSet;
+ newPVH.mIntKeyframes = (Keyframes.IntKeyframes) newPVH.mKeyframes;
return newPVH;
}
@@ -1196,21 +1219,21 @@ public class PropertyValuesHolder implements Cloneable {
long mJniSetter;
private FloatProperty mFloatProperty;
- FloatKeyframeSet mFloatKeyframeSet;
+ Keyframes.FloatKeyframes mFloatKeyframes;
float mFloatAnimatedValue;
- public FloatPropertyValuesHolder(String propertyName, FloatKeyframeSet keyframeSet) {
+ public FloatPropertyValuesHolder(String propertyName, Keyframes.FloatKeyframes keyframes) {
super(propertyName);
mValueType = float.class;
- mKeyframeSet = keyframeSet;
- mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
+ mKeyframes = keyframes;
+ mFloatKeyframes = keyframes;
}
- public FloatPropertyValuesHolder(Property property, FloatKeyframeSet keyframeSet) {
+ public FloatPropertyValuesHolder(Property property, Keyframes.FloatKeyframes keyframes) {
super(property);
mValueType = float.class;
- mKeyframeSet = keyframeSet;
- mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
+ mKeyframes = keyframes;
+ mFloatKeyframes = keyframes;
if (property instanceof FloatProperty) {
mFloatProperty = (FloatProperty) mProperty;
}
@@ -1232,12 +1255,12 @@ public class PropertyValuesHolder implements Cloneable {
@Override
public void setFloatValues(float... values) {
super.setFloatValues(values);
- mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
+ mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
}
@Override
void calculateValue(float fraction) {
- mFloatAnimatedValue = mFloatKeyframeSet.getFloatValue(fraction);
+ mFloatAnimatedValue = mFloatKeyframes.getFloatValue(fraction);
}
@Override
@@ -1248,7 +1271,7 @@ public class PropertyValuesHolder implements Cloneable {
@Override
public FloatPropertyValuesHolder clone() {
FloatPropertyValuesHolder newPVH = (FloatPropertyValuesHolder) super.clone();
- newPVH.mFloatKeyframeSet = (FloatKeyframeSet) newPVH.mKeyframeSet;
+ newPVH.mFloatKeyframes = (Keyframes.FloatKeyframes) newPVH.mKeyframes;
return newPVH;
}
@@ -1340,10 +1363,10 @@ public class PropertyValuesHolder implements Cloneable {
}
public MultiFloatValuesHolder(String propertyName, TypeConverter converter,
- TypeEvaluator evaluator, KeyframeSet keyframeSet) {
+ TypeEvaluator evaluator, Keyframes keyframes) {
super(propertyName);
setConverter(converter);
- mKeyframeSet = keyframeSet;
+ mKeyframes = keyframes;
setEvaluator(evaluator);
}
@@ -1443,10 +1466,10 @@ public class PropertyValuesHolder implements Cloneable {
}
public MultiIntValuesHolder(String propertyName, TypeConverter converter,
- TypeEvaluator evaluator, KeyframeSet keyframeSet) {
+ TypeEvaluator evaluator, Keyframes keyframes) {
super(propertyName);
setConverter(converter);
- mKeyframeSet = keyframeSet;
+ mKeyframes = keyframes;
setEvaluator(evaluator);
}
@@ -1532,77 +1555,6 @@ public class PropertyValuesHolder implements Cloneable {
}
}
- /* Path interpolation relies on approximating the Path as a series of line segments.
- The line segments are recursively divided until there is less than 1/2 pixel error
- between the lines and the curve. Each point of the line segment is converted
- to a Keyframe and a linear interpolation between Keyframes creates a good approximation
- of the curve.
-
- The fraction for each Keyframe is the length along the Path to the point, divided by
- the total Path length. Two points may have the same fraction in the case of a move
- command causing a disjoint Path.
-
- The value for each Keyframe is either the point as a PointF or one of the x or y
- coordinates as an int or float. In the latter case, two Keyframes are generated for
- each point that have the same fraction. */
-
- /**
- * Returns separate Keyframes arrays for the x and y coordinates along a Path. If
- * isInt is true, the Keyframes will be IntKeyframes, otherwise they will be FloatKeyframes.
- * The element at index 0 are the x coordinate Keyframes and element at index 1 are the
- * y coordinate Keyframes. The returned values can be linearly interpolated and get less
- * than 1/2 pixel error.
- */
- static Keyframe[][] createKeyframes(Path path, boolean isInt) {
- if (path == null || path.isEmpty()) {
- throw new IllegalArgumentException("The path must not be null or empty");
- }
- float[] pointComponents = path.approximate(0.5f);
-
- int numPoints = pointComponents.length / 3;
-
- Keyframe[][] keyframes = new Keyframe[2][];
- keyframes[0] = new Keyframe[numPoints];
- keyframes[1] = new Keyframe[numPoints];
- int componentIndex = 0;
- for (int i = 0; i < numPoints; i++) {
- float fraction = pointComponents[componentIndex++];
- float x = pointComponents[componentIndex++];
- float y = pointComponents[componentIndex++];
- if (isInt) {
- keyframes[0][i] = Keyframe.ofInt(fraction, Math.round(x));
- keyframes[1][i] = Keyframe.ofInt(fraction, Math.round(y));
- } else {
- keyframes[0][i] = Keyframe.ofFloat(fraction, x);
- keyframes[1][i] = Keyframe.ofFloat(fraction, y);
- }
- }
- return keyframes;
- }
-
- /**
- * Returns PointF Keyframes for a Path. The resulting points can be linearly interpolated
- * with less than 1/2 pixel in error.
- */
- private static Keyframe[] createKeyframes(Path path) {
- if (path == null || path.isEmpty()) {
- throw new IllegalArgumentException("The path must not be null or empty");
- }
- float[] pointComponents = path.approximate(0.5f);
-
- int numPoints = pointComponents.length / 3;
-
- Keyframe[] keyframes = new Keyframe[numPoints];
- int componentIndex = 0;
- for (int i = 0; i < numPoints; i++) {
- float fraction = pointComponents[componentIndex++];
- float x = pointComponents[componentIndex++];
- float y = pointComponents[componentIndex++];
- keyframes[i] = Keyframe.ofObject(fraction, new PointF(x, y));
- }
- return keyframes;
- }
-
/**
* Convert from PointF to float[] for multi-float setters along a Path.
*/
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2503d17..8ab344e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1236,18 +1236,22 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * @hide
* Check whether this activity is running as part of a voice interaction with the user.
* If true, it should perform its interaction with the user through the
* {@link VoiceInteractor} returned by {@link #getVoiceInteractor}.
*/
+ @SystemApi
public boolean isVoiceInteraction() {
return mVoiceInteractor != null;
}
/**
+ * @hide
* Retrieve the active {@link VoiceInteractor} that the user is going through to
* interact with this activity.
*/
+ @SystemApi
public VoiceInteractor getVoiceInteractor() {
return mVoiceInteractor;
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 66928ca..ba9c9d6 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -220,6 +220,9 @@ public class AppOpsManager {
/** Continually monitoring location data with a relatively high power request. */
public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION
= "android:monitor_location_high_power";
+ /** Access to {@link android.app.usage.UsageStatsManager}. */
+ public static final String OPSTR_GET_USAGE_STATS
+ = "android:get_usage_stats";
/** Activate a VPN connection without user intervention. @hide */
@SystemApi
public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
@@ -331,7 +334,7 @@ public class AppOpsManager {
null,
OPSTR_MONITOR_LOCATION,
OPSTR_MONITOR_HIGH_POWER_LOCATION,
- null,
+ OPSTR_GET_USAGE_STATS,
null,
null,
null,
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 9342ae5..6843827 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1494,57 +1494,52 @@ final class ApplicationPackageManager extends PackageManager {
return false;
}
+ /** @hide */
@Override
public KeySet getKeySetByAlias(String packageName, String alias) {
Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(alias);
- IBinder keySetToken;
+ KeySet ks;
try {
- keySetToken = mPM.getKeySetByAlias(packageName, alias);
+ ks = mPM.getKeySetByAlias(packageName, alias);
} catch (RemoteException e) {
return null;
}
- if (keySetToken == null) {
- return null;
- }
- return new KeySet(keySetToken);
+ return ks;
}
+ /** @hide */
@Override
public KeySet getSigningKeySet(String packageName) {
Preconditions.checkNotNull(packageName);
- IBinder keySetToken;
+ KeySet ks;
try {
- keySetToken = mPM.getSigningKeySet(packageName);
+ ks = mPM.getSigningKeySet(packageName);
} catch (RemoteException e) {
return null;
}
- if (keySetToken == null) {
- return null;
- }
- return new KeySet(keySetToken);
+ return ks;
}
-
+ /** @hide */
@Override
public boolean isSignedBy(String packageName, KeySet ks) {
Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(ks);
- IBinder keySetToken = ks.getToken();
try {
- return mPM.isPackageSignedByKeySet(packageName, keySetToken);
+ return mPM.isPackageSignedByKeySet(packageName, ks);
} catch (RemoteException e) {
return false;
}
}
+ /** @hide */
@Override
public boolean isSignedByExactly(String packageName, KeySet ks) {
Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(ks);
- IBinder keySetToken = ks.getToken();
try {
- return mPM.isPackageSignedByKeySetExactly(packageName, keySetToken);
+ return mPM.isPackageSignedByKeySetExactly(packageName, ks);
} catch (RemoteException e) {
return false;
}
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 67863a5..59f010c 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -23,15 +23,17 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.transition.Transition;
-import android.transition.TransitionInflater;
import android.transition.TransitionManager;
import android.transition.TransitionSet;
+import android.transition.TransitionUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.LogWriter;
import android.util.Pair;
+import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -42,8 +44,6 @@ final class BackStackState implements Parcelable {
final int[] mOps;
final int mTransition;
final int mTransitionStyle;
- final int mCustomTransition;
- final int mSceneRoot;
final String mName;
final int mIndex;
final int mBreadCrumbTitleRes;
@@ -96,8 +96,6 @@ final class BackStackState implements Parcelable {
mBreadCrumbTitleText = bse.mBreadCrumbTitleText;
mBreadCrumbShortTitleRes = bse.mBreadCrumbShortTitleRes;
mBreadCrumbShortTitleText = bse.mBreadCrumbShortTitleText;
- mCustomTransition = bse.mCustomTransition;
- mSceneRoot = bse.mSceneRoot;
mSharedElementSourceNames = bse.mSharedElementSourceNames;
mSharedElementTargetNames = bse.mSharedElementTargetNames;
}
@@ -112,8 +110,6 @@ final class BackStackState implements Parcelable {
mBreadCrumbTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mBreadCrumbShortTitleRes = in.readInt();
mBreadCrumbShortTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mCustomTransition = in.readInt();
- mSceneRoot = in.readInt();
mSharedElementSourceNames = in.createStringArrayList();
mSharedElementTargetNames = in.createStringArrayList();
}
@@ -164,8 +160,6 @@ final class BackStackState implements Parcelable {
bse.mBreadCrumbTitleText = mBreadCrumbTitleText;
bse.mBreadCrumbShortTitleRes = mBreadCrumbShortTitleRes;
bse.mBreadCrumbShortTitleText = mBreadCrumbShortTitleText;
- bse.mCustomTransition = mCustomTransition;
- bse.mSceneRoot = mSceneRoot;
bse.mSharedElementSourceNames = mSharedElementSourceNames;
bse.mSharedElementTargetNames = mSharedElementTargetNames;
bse.bumpBackStackNesting(1);
@@ -186,8 +180,6 @@ final class BackStackState implements Parcelable {
TextUtils.writeToParcel(mBreadCrumbTitleText, dest, 0);
dest.writeInt(mBreadCrumbShortTitleRes);
TextUtils.writeToParcel(mBreadCrumbShortTitleText, dest, 0);
- dest.writeInt(mCustomTransition);
- dest.writeInt(mSceneRoot);
dest.writeStringList(mSharedElementSourceNames);
dest.writeStringList(mSharedElementTargetNames);
}
@@ -254,8 +246,6 @@ final class BackStackRecord extends FragmentTransaction implements
int mBreadCrumbShortTitleRes;
CharSequence mBreadCrumbShortTitleText;
- int mCustomTransition;
- int mSceneRoot;
ArrayList<String> mSharedElementSourceNames;
ArrayList<String> mSharedElementTargetNames;
@@ -573,13 +563,6 @@ final class BackStackRecord extends FragmentTransaction implements
}
@Override
- public FragmentTransaction setCustomTransition(int sceneRootId, int transitionId) {
- mSceneRoot = sceneRootId;
- mCustomTransition = transitionId;
- return this;
- }
-
- @Override
public FragmentTransaction addSharedElement(View sharedElement, String name) {
String transitionName = sharedElement.getTransitionName();
if (transitionName == null) {
@@ -760,8 +743,15 @@ final class BackStackRecord extends FragmentTransaction implements
bumpBackStackNesting(1);
- TransitionState state = beginTransition(mSharedElementSourceNames,
- mSharedElementTargetNames);
+ SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
+ SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
+
+ calculateFragments(firstOutFragments, lastInFragments);
+
+ TransitionState state = null;
+ if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) {
+ state = beginTransition(firstOutFragments, lastInFragments, false);
+ }
Op op = mHead;
while (op != null) {
@@ -854,144 +844,608 @@ final class BackStackRecord extends FragmentTransaction implements
}
if (state != null) {
- updateTransitionEndState(state, mSharedElementTargetNames);
+ updateTransitionEndState(state, firstOutFragments, lastInFragments, false);
}
}
- private TransitionState beginTransition(ArrayList<String> sourceNames,
- ArrayList<String> targetNames) {
- if (mCustomTransition <= 0 || mSceneRoot <= 0) {
- return null;
+ private static void setFirstOut(SparseArray<Fragment> fragments, Fragment fragment) {
+ if (fragment != null) {
+ int containerId = fragment.mContainerId;
+ if (containerId != 0 && !fragment.isHidden() && fragment.isAdded() &&
+ fragment.getView() != null && fragments.get(containerId) == null) {
+ fragments.put(containerId, fragment);
+ }
+ }
+ }
+
+ private void setLastIn(SparseArray<Fragment> fragments, Fragment fragment) {
+ if (fragment != null) {
+ int containerId = fragment.mContainerId;
+ if (containerId != 0) {
+ fragments.put(containerId, fragment);
+ }
+ }
+ }
+
+ /**
+ * Finds the first removed fragment and last added fragments when going forward.
+ * If none of the fragments have transitions, then both lists will be empty.
+ *
+ * @param firstOutFragments The list of first fragments to be removed, keyed on the
+ * container ID. This list will be modified by the method.
+ * @param lastInFragments The list of last fragments to be added, keyed on the
+ * container ID. This list will be modified by the method.
+ */
+ private void calculateFragments(SparseArray<Fragment> firstOutFragments,
+ SparseArray<Fragment> lastInFragments) {
+ Op op = mHead;
+ while (op != null) {
+ switch (op.cmd) {
+ case OP_ADD:
+ setLastIn(lastInFragments, op.fragment);
+ break;
+ case OP_REPLACE: {
+ Fragment f = op.fragment;
+ if (mManager.mAdded != null) {
+ for (int i = 0; i < mManager.mAdded.size(); i++) {
+ Fragment old = mManager.mAdded.get(i);
+ if (f == null || old.mContainerId == f.mContainerId) {
+ if (old == f) {
+ f = null;
+ } else {
+ setFirstOut(firstOutFragments, old);
+ }
+ }
+ }
+ }
+ setLastIn(lastInFragments, f);
+ break;
+ }
+ case OP_REMOVE:
+ setFirstOut(firstOutFragments, op.fragment);
+ break;
+ case OP_HIDE:
+ setFirstOut(firstOutFragments, op.fragment);
+ break;
+ case OP_SHOW:
+ setLastIn(lastInFragments, op.fragment);
+ break;
+ case OP_DETACH:
+ setFirstOut(firstOutFragments, op.fragment);
+ break;
+ case OP_ATTACH:
+ setLastIn(lastInFragments, op.fragment);
+ break;
+ }
+
+ op = op.next;
+ }
+
+ if (!haveTransitions(firstOutFragments, lastInFragments, false)) {
+ firstOutFragments.clear();
+ lastInFragments.clear();
+ }
+ }
+
+ /**
+ * @return true if custom transitions exist on any fragment in firstOutFragments or
+ * lastInFragments or false otherwise.
+ */
+ private static boolean haveTransitions(SparseArray<Fragment> firstOutFragments,
+ SparseArray<Fragment> lastInFragments, boolean isBack) {
+ for (int i = firstOutFragments.size() - 1; i >= 0; i--) {
+ Fragment f = firstOutFragments.valueAt(i);
+ if (isBack) {
+ if (f.getReturnTransition() != null ||
+ f.getSharedElementReturnTransition() != null) {
+ return true;
+ }
+ } else if (f.getExitTransition() != null) {
+ return true;
+ }
+ }
+
+ for (int i = lastInFragments.size() - 1; i >= 0; i--) {
+ Fragment f = lastInFragments.valueAt(i);
+ if (isBack) {
+ if (f.getReenterTransition() != null) {
+ return true;
+ }
+ } else if (f.getEnterTransition() != null ||
+ f.getSharedElementEnterTransition() != null) {
+ return true;
+ }
}
- View rootView = mManager.mContainer.findViewById(mSceneRoot);
- if (!(rootView instanceof ViewGroup)) {
- throw new IllegalArgumentException("SceneRoot is not a ViewGroup");
+ return false;
+ }
+
+ /**
+ * Finds the first removed fragment and last added fragments when popping the back stack.
+ * If none of the fragments have transitions, then both lists will be empty.
+ *
+ * @param firstOutFragments The list of first fragments to be removed, keyed on the
+ * container ID. This list will be modified by the method.
+ * @param lastInFragments The list of last fragments to be added, keyed on the
+ * container ID. This list will be modified by the method.
+ */
+ public void calculateBackFragments(SparseArray<Fragment> firstOutFragments,
+ SparseArray<Fragment> lastInFragments) {
+ Op op = mHead;
+ while (op != null) {
+ switch (op.cmd) {
+ case OP_ADD:
+ setFirstOut(firstOutFragments, op.fragment);
+ break;
+ case OP_REPLACE:
+ if (op.removed != null) {
+ for (int i = op.removed.size() - 1; i >= 0; i--) {
+ setLastIn(lastInFragments, op.removed.get(i));
+ }
+ }
+ setFirstOut(firstOutFragments, op.fragment);
+ break;
+ case OP_REMOVE:
+ setLastIn(lastInFragments, op.fragment);
+ break;
+ case OP_HIDE:
+ setLastIn(lastInFragments, op.fragment);
+ break;
+ case OP_SHOW:
+ setFirstOut(firstOutFragments, op.fragment);
+ break;
+ case OP_DETACH:
+ setLastIn(lastInFragments, op.fragment);
+ break;
+ case OP_ATTACH:
+ setFirstOut(firstOutFragments, op.fragment);
+ break;
+ }
+
+ op = op.next;
}
+
+ if (!haveTransitions(firstOutFragments, lastInFragments, true)) {
+ firstOutFragments.clear();
+ lastInFragments.clear();
+ }
+ }
+
+ /**
+ * When custom fragment transitions are used, this sets up the state for each transition
+ * and begins the transition. A different transition is started for each fragment container
+ * and consists of up to 3 different transitions: the exit transition, a shared element
+ * transition and an enter transition.
+ *
+ * <p>The exit transition operates against the leaf nodes of the first fragment
+ * with a view that was removed. If no such fragment was removed, then no exit
+ * transition is executed. The exit transition comes from the outgoing fragment.</p>
+ *
+ * <p>The enter transition operates against the last fragment that was added. If
+ * that fragment does not have a view or no fragment was added, then no enter
+ * transition is executed. The enter transition comes from the incoming fragment.</p>
+ *
+ * <p>The shared element transition operates against all views and comes either
+ * from the outgoing fragment or the incoming fragment, depending on whether this
+ * is going forward or popping the back stack. When going forward, the incoming
+ * fragment's enter shared element transition is used, but when going back, the
+ * outgoing fragment's return shared element transition is used. Shared element
+ * transitions only operate if there is both an incoming and outgoing fragment.</p>
+ *
+ * @param firstOutFragments The list of first fragments to be removed, keyed on the
+ * container ID.
+ * @param lastInFragments The list of last fragments to be added, keyed on the
+ * container ID.
+ * @param isBack true if this is popping the back stack or false if this is a
+ * forward operation.
+ * @return The TransitionState used to complete the operation of the transition
+ * in {@link #updateTransitionEndState(android.app.BackStackRecord.TransitionState,
+ * android.util.SparseArray, android.util.SparseArray, boolean)}.
+ */
+ private TransitionState beginTransition(SparseArray<Fragment> firstOutFragments,
+ SparseArray<Fragment> lastInFragments, boolean isBack) {
TransitionState state = new TransitionState();
- // get Transition scene root and create Transitions
- state.sceneRoot = (ViewGroup) rootView;
- state.sceneRoot.captureTransitioningViews(state.transitioningViews);
-
- state.exitTransition = TransitionInflater.from(mManager.mActivity)
- .inflateTransition(mCustomTransition);
- state.sharedElementTransition = TransitionInflater.from(mManager.mActivity)
- .inflateTransition(mCustomTransition);
- state.enterTransition = TransitionInflater.from(mManager.mActivity)
- .inflateTransition(mCustomTransition);
+
// Adding a non-existent target view makes sure that the transitions don't target
// any views by default. They'll only target the views we tell add. If we don't
// add any, then no views will be targeted.
- View nonExistentView = new View(mManager.mActivity);
- state.enterTransition.addTarget(nonExistentView);
- state.exitTransition.addTarget(nonExistentView);
- state.sharedElementTransition.addTarget(nonExistentView);
-
- setSharedElementEpicenter(state.enterTransition, state);
-
- state.excludingTransition = new TransitionSet()
- .addTransition(state.exitTransition)
- .addTransition(state.enterTransition);
+ state.nonExistentView = new View(mManager.mActivity);
+
+ ArrayMap<String, View> tempViews1 = new ArrayMap<String, View>();
+ ArrayMap<String, View> tempViews2 = new ArrayMap<String, View>();
+ ArrayList<String> tempNames = new ArrayList<String>();
+ ArrayList<View> tempViewList = new ArrayList<View>();
+
+ // Go over all leaving fragments.
+ for (int i = 0; i < firstOutFragments.size(); i++) {
+ int containerId = firstOutFragments.keyAt(i);
+ configureTransitions(containerId, state, isBack, firstOutFragments,
+ lastInFragments, tempViews1, tempViews2, tempNames, tempViewList);
+ }
- if (sourceNames != null) {
- // Map shared elements.
- state.sceneRoot.findNamedViews(state.namedViews);
- state.namedViews.retainAll(sourceNames);
- View epicenterView = state.namedViews.get(sourceNames.get(0));
- if (epicenterView != null) {
- // The epicenter is only the first shared element.
- setEpicenter(state.exitTransition, epicenterView);
- setEpicenter(state.sharedElementTransition, epicenterView);
+ // Now go over all entering fragments that didn't have a leaving fragment.
+ for (int i = 0; i < lastInFragments.size(); i++) {
+ int containerId = lastInFragments.keyAt(i);
+ if (firstOutFragments.get(containerId) == null) {
+ configureTransitions(containerId, state, isBack, firstOutFragments,
+ lastInFragments, tempViews1, tempViews2, tempNames, tempViewList);
}
- state.transitioningViews.removeAll(state.namedViews.values());
- state.excludingTransition.addTransition(state.sharedElementTransition);
- addTransitioningViews(state.sharedElementTransition, state.namedViews.values());
}
- // Adds the (maybe) exiting views, not including the shared element.
- // If some stay, that's ok.
- addTransitioningViews(state.exitTransition, state.transitioningViews);
+ if (state.overallTransitions.size() == 0) {
+ state = null;
+ }
+ return state;
+ }
- // Prepare for shared element name mapping. This could be chained in the case
- // of popping several back stack states.
- state.excludingTransition.setNameOverrides(new ArrayMap<String, String>());
- setNameOverrides(state, sourceNames, targetNames);
+ private static Transition getEnterTransition(Fragment inFragment, boolean isBack) {
+ if (inFragment == null) {
+ return null;
+ }
+ return isBack ? inFragment.getReenterTransition() : inFragment.getEnterTransition();
+ }
- // Don't include any subtree in the views that are hidden when capturing the
- // view hierarchy transitions. They should be as if not there.
- excludeHiddenFragments(state, true);
+ private static Transition getExitTransition(Fragment outFragment, boolean isBack) {
+ if (outFragment == null) {
+ return null;
+ }
+ return isBack ? outFragment.getReturnTransition() : outFragment.getExitTransition();
+ }
- TransitionManager.beginDelayedTransition(state.sceneRoot, state.excludingTransition);
- return state;
+ private static Transition getSharedElementTransition(Fragment inFragment, Fragment outFragment,
+ boolean isBack) {
+ if (inFragment == null || outFragment == null) {
+ return null;
+ }
+ return isBack ? outFragment.getSharedElementReturnTransition() :
+ inFragment.getSharedElementEnterTransition();
}
- private void updateTransitionEndState(TransitionState state, ArrayList<String> names) {
- // Find all views that are entering.
- ArrayList<View> enteringViews = new ArrayList<View>();
- state.sceneRoot.captureTransitioningViews(enteringViews);
- enteringViews.removeAll(state.transitioningViews);
-
- if (names != null) {
- // find all shared elements.
- state.namedViews.clear();
- state.sceneRoot.findNamedViews(state.namedViews);
- state.namedViews.retainAll(names);
- if (!state.namedViews.isEmpty()) {
- enteringViews.removeAll(state.namedViews.values());
- addTransitioningViews(state.sharedElementTransition, state.namedViews.values());
- // now we know the epicenter of the entering transition.
- state.mEnteringEpicenterView = state.namedViews.get(names.get(0));
+ private static Transition captureExitingViews(Transition exitTransition, Fragment outFragment,
+ ArrayList<View> viewList) {
+ if (exitTransition != null) {
+ View root = outFragment.getView();
+ viewList.clear();
+ root.captureTransitioningViews(viewList);
+ if (viewList.isEmpty()) {
+ exitTransition = null;
+ } else {
+ addTransitioningViews(exitTransition, viewList);
+ }
+ }
+ return exitTransition;
+ }
+
+ private ArrayMap<String, View> remapSharedElements(TransitionState state, Fragment outFragment,
+ ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) {
+ if (mSharedElementSourceNames != null) {
+ outFragment.getView().findNamedViews(namedViews);
+ if (isBack) {
+ namedViews.retainAll(mSharedElementTargetNames);
+ } else {
+ namedViews = remapNames(mSharedElementSourceNames, mSharedElementTargetNames,
+ namedViews, tempViews2);
}
}
- // Add all entering views to the enter transition.
- addTransitioningViews(state.enterTransition, enteringViews);
+ if (isBack) {
+ outFragment.mEnterTransitionListener.remapSharedElements(
+ mSharedElementTargetNames, namedViews);
+ setBackNameOverrides(state, namedViews, false);
+ } else {
+ outFragment.mExitTransitionListener.remapSharedElements(
+ mSharedElementTargetNames, namedViews);
+ setNameOverrides(state, namedViews, false);
+ }
- // Don't allow capturing state for the newly-hidden fragments.
- excludeHiddenFragments(state, false);
+ return namedViews;
+ }
- // Allow capturing state for the newly-shown fragments
- includeVisibleFragments(state.excludingTransition);
+ /**
+ * Prepares the enter transition by adding a non-existent view to the transition's target list
+ * and setting it epicenter callback. By adding a non-existent view to the target list,
+ * we can prevent any view from being targeted at the beginning of the transition.
+ * We will add to the views before the end state of the transition is captured so that the
+ * views will appear. At the start of the transition, we clear the list of targets so that
+ * we can restore the state of the transition and use it again.
+ */
+ private void prepareEnterTransition(TransitionState state, final Transition enterTransition,
+ final View container, final Fragment inFragment) {
+ if (enterTransition != null) {
+ final ArrayList<View> enteringViews = new ArrayList<View>();
+ final View nonExistentView = state.nonExistentView;
+ enterTransition.addTarget(state.nonExistentView);
+ enterTransition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ transition.removeListener(this);
+ transition.removeTarget(nonExistentView);
+ int numViews = enteringViews.size();
+ for (int i = 0; i < numViews; i++) {
+ transition.removeTarget(enteringViews.get(i));
+ }
+ }
+ });
+ container.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ container.getViewTreeObserver().removeOnPreDrawListener(this);
+ View view = inFragment.getView();
+ if (view != null) {
+ view.captureTransitioningViews(enteringViews);
+ addTransitioningViews(enterTransition, enteringViews);
+ }
+ return true;
+ }
+ });
+ setSharedElementEpicenter(enterTransition, state);
+ }
}
- private void addTransitioningViews(Transition transition, Collection<View> views) {
- if (views.isEmpty()) {
- // Add a view so that we can modify the valid views at the end of the
- // fragment transaction.
- transition.addTarget(new View(mManager.mActivity));
+ private static Transition mergeTransitions(Transition enterTransition,
+ Transition exitTransition, Transition sharedElementTransition, Fragment inFragment,
+ boolean isBack) {
+ boolean overlap = true;
+ if (enterTransition != null && exitTransition != null) {
+ overlap = isBack ? inFragment.getAllowReturnTransitionOverlap() :
+ inFragment.getAllowEnterTransitionOverlap();
+ }
+
+ Transition transition;
+ if (overlap) {
+ transition = TransitionUtils.mergeTransitions(enterTransition, exitTransition,
+ sharedElementTransition);
} else {
- for (View view : views) {
- transition.addTarget(view);
+ TransitionSet staggered = new TransitionSet()
+ .addTransition(exitTransition)
+ .addTransition(enterTransition)
+ .setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
+ transition = TransitionUtils.mergeTransitions(staggered, sharedElementTransition);
+ }
+ return transition;
+ }
+
+ /**
+ * Configures custom transitions for a specific fragment container.
+ *
+ * @param containerId The container ID of the fragments to configure the transition for.
+ * @param state The Transition State to be shared with {@link #updateTransitionEndState(
+ * android.app.BackStackRecord.TransitionState, android.util.SparseArray,
+ * android.util.SparseArray, boolean)} later.
+ * @param firstOutFragments The list of first fragments to be removed, keyed on the
+ * container ID.
+ * @param lastInFragments The list of last fragments to be added, keyed on the
+ * container ID.
+ * @param isBack true if this is popping the back stack or false if this is a
+ * forward operation.
+ * @param tempViews1 A temporary mapping of names to Views, used to avoid allocation
+ * inside a loop.
+ * @param tempViews2 A temporary mapping of names to Views, used to avoid allocation
+ * inside a loop.
+ * @param tempNames A temporary list of Strings, used to avoid allocation inside a loop.
+ * @param tempViewList A temporary list of Views, used to avoid allocation inside a loop.
+ */
+ private void configureTransitions(int containerId, TransitionState state, boolean isBack,
+ SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments,
+ ArrayMap<String, View> tempViews1, ArrayMap<String, View> tempViews2,
+ ArrayList<String> tempNames, ArrayList<View> tempViewList) {
+ ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.findViewById(containerId);
+ if (sceneRoot != null) {
+ Fragment inFragment = lastInFragments.get(containerId);
+ Fragment outFragment = firstOutFragments.get(containerId);
+
+ Transition enterTransition = getEnterTransition(inFragment, isBack);
+ Transition sharedElementTransition = getSharedElementTransition(inFragment, outFragment,
+ isBack);
+ Transition exitTransition = getExitTransition(outFragment, isBack);
+ exitTransition = captureExitingViews(exitTransition, outFragment, tempViewList);
+
+ ArrayMap<String, View> namedViews = tempViews1;
+ namedViews.clear();
+ if (sharedElementTransition != null) {
+ namedViews = remapSharedElements(state,
+ outFragment, namedViews, tempViews2, isBack);
+ }
+
+ // Notify the start of the transition.
+ SharedElementListener listener = isBack ?
+ outFragment.mEnterTransitionListener :
+ inFragment.mEnterTransitionListener;
+ tempNames.clear();
+ tempNames.addAll(namedViews.keySet());
+ tempViewList.clear();
+ tempViewList.addAll(namedViews.values());
+ listener.setSharedElementStart(tempNames, tempViewList, null);
+
+ // Set the epicenter of the exit transition
+ if (mSharedElementTargetNames != null && exitTransition != null) {
+ View epicenterView = namedViews.get(mSharedElementTargetNames.get(0));
+ if (epicenterView != null) {
+ setEpicenter(exitTransition, epicenterView);
+ }
+ }
+
+ prepareEnterTransition(state, enterTransition, sceneRoot, inFragment);
+
+ Transition transition = mergeTransitions(enterTransition, exitTransition,
+ sharedElementTransition, inFragment, isBack);
+
+ if (transition != null) {
+ state.overallTransitions.put(containerId, transition);
+ transition.setNameOverrides(state.nameOverrides);
+ // We want to exclude hidden views later, so we need a non-null list in the
+ // transition now.
+ transition.excludeTarget(state.nonExistentView, true);
+ // Now exclude all currently hidden fragments.
+ excludeHiddenFragments(state, containerId, transition);
+ cleanupHiddenFragments(transition, state);
+ TransitionManager.beginDelayedTransition(sceneRoot, transition);
}
}
}
- private void excludeHiddenFragments(TransitionState state, boolean forceExclude) {
- if (mManager.mAdded != null) {
- for (int i = 0; i < mManager.mAdded.size(); i++) {
- Fragment fragment = mManager.mAdded.get(i);
- if (fragment.mView != null && fragment.mHidden
- && (forceExclude || !state.hiddenViews.contains(fragment.mView))) {
- state.excludingTransition.excludeTarget(fragment.mView, true);
- state.hiddenViews.add(fragment.mView);
+ /**
+ * Remaps a name-to-View map, substituting different names for keys.
+ *
+ * @param inMap A list of keys found in the map, in the order in toGoInMap
+ * @param toGoInMap A list of keys to use for the new map, in the order of inMap
+ * @param namedViews The current mapping
+ * @param tempMap A temporary mapping that will be filled with the new values.
+ * @return tempMap after it has been mapped with the new names as keys.
+ */
+ private static ArrayMap<String, View> remapNames(ArrayList<String> inMap,
+ ArrayList<String> toGoInMap, ArrayMap<String, View> namedViews,
+ ArrayMap<String, View> tempMap) {
+ tempMap.clear();
+ if (!namedViews.isEmpty()) {
+ int numKeys = inMap.size();
+ for (int i = 0; i < numKeys; i++) {
+ View view = namedViews.get(inMap.get(i));
+ if (view != null) {
+ tempMap.put(toGoInMap.get(i), view);
}
}
}
- if (forceExclude && state.hiddenViews.isEmpty()) {
- state.excludingTransition.excludeTarget(new View(mManager.mActivity), true);
+ return tempMap;
+ }
+
+ /**
+ * After making all fragment changes, this updates the custom transitions to take into
+ * account the entering views and any remapping.
+ *
+ * @param state The transition State as returned from {@link #beginTransition(
+ * android.util.SparseArray, android.util.SparseArray, boolean)}.
+ * @param outFragments The list of first fragments to be removed, keyed on the
+ * container ID.
+ * @param inFragments The list of last fragments to be added, keyed on the
+ * container ID.
+ * @param isBack true if this is popping the back stack or false if this is a
+ * forward operation.
+ */
+ private void updateTransitionEndState(TransitionState state, SparseArray<Fragment> outFragments,
+ SparseArray<Fragment> inFragments, boolean isBack) {
+ ArrayMap<String, View> tempViews1 = new ArrayMap<String, View>();
+ ArrayMap<String, View> tempViews2 = new ArrayMap<String, View>();
+ ArrayList<String> tempNames = new ArrayList<String>();
+ ArrayList<View> tempViews = new ArrayList<View>();
+
+ int numInFragments = inFragments.size();
+ for (int i = 0; i < numInFragments; i++) {
+ Fragment inFragment = inFragments.valueAt(i);
+ tempViews1.clear();
+ ArrayMap<String, View> namedViews = mapEnteringSharedElements(inFragment, tempViews1,
+ tempViews2, isBack);
+ // remap shared elements and set the name mapping used in the shared element transition.
+ if (isBack) {
+ inFragment.mExitTransitionListener.remapSharedElements(
+ mSharedElementTargetNames, namedViews);
+ setBackNameOverrides(state, namedViews, true);
+ } else {
+ inFragment.mEnterTransitionListener.remapSharedElements(
+ mSharedElementTargetNames, namedViews);
+ setNameOverrides(state, namedViews, true);
+ }
+
+ if (mSharedElementTargetNames != null && !namedViews.isEmpty()) {
+ // now we know the epicenter of the entering transition.
+ View epicenter = namedViews.get(mSharedElementTargetNames.get(0));
+ if (epicenter != null) {
+ state.enteringEpicenterView = epicenter;
+ }
+ }
+
+ int containerId = inFragments.keyAt(i);
+ SharedElementListener sharedElementListener = isBack ?
+ outFragments.get(containerId).mEnterTransitionListener :
+ inFragment.mEnterTransitionListener;
+ tempNames.clear();
+ tempNames.addAll(namedViews.keySet());
+ tempViews.clear();
+ tempViews.addAll(namedViews.values());
+ sharedElementListener.setSharedElementEnd(tempNames, tempViews, null);
}
+
+ // Don't include any newly-hidden fragments in the transition.
+ excludeHiddenFragments(state);
}
- private void includeVisibleFragments(Transition transition) {
+ private ArrayMap<String, View> mapEnteringSharedElements(Fragment inFragment,
+ ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) {
+ View root = inFragment.getView();
+ if (root != null) {
+ if (mSharedElementSourceNames != null) {
+ root.findNamedViews(namedViews);
+ if (isBack) {
+ namedViews = remapNames(mSharedElementSourceNames,
+ mSharedElementTargetNames, namedViews, tempViews2);
+ } else {
+ namedViews.retainAll(mSharedElementTargetNames);
+ }
+ }
+ }
+ return namedViews;
+ }
+
+ private static void cleanupHiddenFragments(Transition transition, TransitionState state) {
+ final ArrayList<View> hiddenViews = state.hiddenFragmentViews;
+ transition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ transition.removeListener(this);
+ int numViews = hiddenViews.size();
+ for (int i = 0; i < numViews; i++) {
+ transition.excludeTarget(hiddenViews.get(i), false);
+ }
+ }
+ });
+ }
+
+ private void excludeHiddenFragments(TransitionState state, int containerId,
+ Transition transition) {
if (mManager.mAdded != null) {
for (int i = 0; i < mManager.mAdded.size(); i++) {
Fragment fragment = mManager.mAdded.get(i);
- if (fragment.mView != null && !fragment.mHidden) {
- transition.excludeTarget(fragment.mView, false);
+ if (fragment.mView != null && fragment.mContainer != null &&
+ fragment.mContainerId == containerId) {
+ if (fragment.mHidden) {
+ if (!state.hiddenFragmentViews.contains(fragment.mView)) {
+ transition.excludeTarget(fragment.mView, true);
+ state.hiddenFragmentViews.add(fragment.mView);
+ }
+ } else {
+ transition.excludeTarget(fragment.mView, false);
+ state.hiddenFragmentViews.remove(fragment.mView);
+ }
}
}
}
}
+ private void excludeHiddenFragments(TransitionState state) {
+ int numTransitions = state.overallTransitions.size();
+ for (int i = 0; i < numTransitions; i++) {
+ Transition transition = state.overallTransitions.valueAt(i);
+ int containerId = state.overallTransitions.keyAt(i);
+ excludeHiddenFragments(state, containerId, transition);
+ }
+ }
+
+ private static void addTransitioningViews(Transition transition, final Collection<View> views) {
+ for (View view : views) {
+ transition.addTarget(view);
+ }
+
+ transition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ transition.removeListener(this);
+ for (View view : views) {
+ transition.removeTarget(view);
+ }
+ }
+ });
+ }
+
private static void setEpicenter(Transition transition, View view) {
final Rect epicenter = new Rect();
view.getBoundsOnScreen(epicenter);
@@ -1010,16 +1464,17 @@ final class BackStackRecord extends FragmentTransaction implements
@Override
public Rect onGetEpicenter(Transition transition) {
- if (mEpicenter == null && state.mEnteringEpicenterView != null) {
+ if (mEpicenter == null && state.enteringEpicenterView != null) {
mEpicenter = new Rect();
- state.mEnteringEpicenterView.getBoundsOnScreen(mEpicenter);
+ state.enteringEpicenterView.getBoundsOnScreen(mEpicenter);
}
return mEpicenter;
}
});
}
- public TransitionState popFromBackStack(boolean doStateMove, TransitionState state) {
+ public TransitionState popFromBackStack(boolean doStateMove, TransitionState state,
+ SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "popFromBackStack: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
@@ -1029,8 +1484,10 @@ final class BackStackRecord extends FragmentTransaction implements
}
if (state == null) {
- state = beginTransition(mSharedElementTargetNames, mSharedElementSourceNames);
- } else {
+ if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) {
+ state = beginTransition(firstOutFragments, lastInFragments, true);
+ }
+ } else if (!doStateMove) {
setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames);
}
@@ -1110,7 +1567,7 @@ final class BackStackRecord extends FragmentTransaction implements
mManager.moveToState(mManager.mCurState,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true);
if (state != null) {
- updateTransitionEndState(state, mSharedElementSourceNames);
+ updateTransitionEndState(state, firstOutFragments, lastInFragments, true);
state = null;
}
}
@@ -1122,15 +1579,17 @@ final class BackStackRecord extends FragmentTransaction implements
return state;
}
- private static void setNameOverride(Transition transition, String source, String target) {
- ArrayMap<String, String> overrides = transition.getNameOverrides();
- for (int index = 0; index < overrides.size(); index++) {
- if (source.equals(overrides.valueAt(index))) {
- overrides.setValueAt(index, target);
- return;
+ private static void setNameOverride(ArrayMap<String, String> overrides,
+ String source, String target) {
+ if (source != null && target != null && !source.equals(target)) {
+ for (int index = 0; index < overrides.size(); index++) {
+ if (source.equals(overrides.valueAt(index))) {
+ overrides.setValueAt(index, target);
+ return;
+ }
}
+ overrides.put(source, target);
}
- overrides.put(source, target);
}
private static void setNameOverrides(TransitionState state, ArrayList<String> sourceNames,
@@ -1139,7 +1598,36 @@ final class BackStackRecord extends FragmentTransaction implements
for (int i = 0; i < sourceNames.size(); i++) {
String source = sourceNames.get(i);
String target = targetNames.get(i);
- setNameOverride(state.excludingTransition, source, target);
+ setNameOverride(state.nameOverrides, source, target);
+ }
+ }
+ }
+
+ private void setBackNameOverrides(TransitionState state, ArrayMap<String, View> namedViews,
+ boolean isEnd) {
+ int count = mSharedElementTargetNames.size();
+ for (int i = 0; i < count; i++) {
+ String source = mSharedElementSourceNames.get(i);
+ String originalTarget = mSharedElementTargetNames.get(i);
+ String target = namedViews.get(originalTarget).getTransitionName();
+ if (isEnd) {
+ setNameOverride(state.nameOverrides, source, target);
+ } else {
+ setNameOverride(state.nameOverrides, target, source);
+ }
+ }
+ }
+
+ private void setNameOverrides(TransitionState state, ArrayMap<String, View> namedViews,
+ boolean isEnd) {
+ int count = namedViews.size();
+ for (int i = 0; i < count; i++) {
+ String source = namedViews.keyAt(i);
+ String target = namedViews.valueAt(i).getTransitionName();
+ if (isEnd) {
+ setNameOverride(state.nameOverrides, source, target);
+ } else {
+ setNameOverride(state.nameOverrides, target, source);
}
}
}
@@ -1161,14 +1649,11 @@ final class BackStackRecord extends FragmentTransaction implements
}
public class TransitionState {
- public ArrayList<View> hiddenViews = new ArrayList<View>();
- public ArrayList<View> transitioningViews = new ArrayList<View>();
- public ArrayMap<String, View> namedViews = new ArrayMap<String, View>();
- public Transition exitTransition;
- public Transition sharedElementTransition;
- public Transition enterTransition;
- public TransitionSet excludingTransition;
- public ViewGroup sceneRoot;
- public View mEnteringEpicenterView;
+ public SparseArray<Transition> overallTransitions = new SparseArray<Transition>();
+ public ArrayMap<String, String> nameOverrides = new ArrayMap<String, String>();
+ public ArrayList<View> hiddenFragmentViews = new ArrayList<View>();
+
+ public View enteringEpicenterView;
+ public View nonExistentView;
}
}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 5a6898d..47d3fd6 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -194,10 +194,12 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
@Override
public boolean onPreDraw() {
getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
- Bundle state = captureSharedElementState();
- setSharedElementMatrices();
- moveSharedElementsToOverlay();
- mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
+ if (mResultReceiver != null) {
+ Bundle state = captureSharedElementState();
+ setSharedElementMatrices();
+ moveSharedElementsToOverlay();
+ mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
+ }
return true;
}
});
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index f31800d..3760b96 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -19,6 +19,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Intent;
+import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
@@ -222,10 +223,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
delayCancel();
moveSharedElementsToOverlay();
if (getDecor().getBackground() == null) {
- ColorDrawable black = new ColorDrawable(0xFF000000);
- black.setAlpha(0);
- getWindow().setBackgroundDrawable(black);
- black.setAlpha(255);
+ getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
}
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
mAllSharedElementNames, resultCode, data);
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 2ff3d57..dbee81e 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -23,10 +23,14 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionSet;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.AttributeSet;
@@ -58,11 +62,11 @@ final class FragmentState implements Parcelable {
final boolean mRetainInstance;
final boolean mDetached;
final Bundle mArguments;
-
+
Bundle mSavedFragmentState;
-
+
Fragment mInstance;
-
+
public FragmentState(Fragment frag) {
mClassName = frag.getClass().getName();
mIndex = frag.mIndex;
@@ -74,7 +78,7 @@ final class FragmentState implements Parcelable {
mDetached = frag.mDetached;
mArguments = frag.mArguments;
}
-
+
public FragmentState(Parcel in) {
mClassName = in.readString();
mIndex = in.readInt();
@@ -87,18 +91,18 @@ final class FragmentState implements Parcelable {
mArguments = in.readBundle();
mSavedFragmentState = in.readBundle();
}
-
+
public Fragment instantiate(Activity activity, Fragment parent) {
if (mInstance != null) {
return mInstance;
}
-
+
if (mArguments != null) {
mArguments.setClassLoader(activity.getClassLoader());
}
-
+
mInstance = Fragment.instantiate(activity, mClassName, mArguments);
-
+
if (mSavedFragmentState != null) {
mSavedFragmentState.setClassLoader(activity.getClassLoader());
mInstance.mSavedFragmentState = mSavedFragmentState;
@@ -117,7 +121,7 @@ final class FragmentState implements Parcelable {
return mInstance;
}
-
+
public int describeContents() {
return 0;
}
@@ -134,13 +138,13 @@ final class FragmentState implements Parcelable {
dest.writeBundle(mArguments);
dest.writeBundle(mSavedFragmentState);
}
-
+
public static final Parcelable.Creator<FragmentState> CREATOR
= new Parcelable.Creator<FragmentState>() {
public FragmentState createFromParcel(Parcel in) {
return new FragmentState(in);
}
-
+
public FragmentState[] newArray(int size) {
return new FragmentState[size];
}
@@ -299,17 +303,17 @@ final class FragmentState implements Parcelable {
* how you can determine if a fragment placed in a container is no longer
* running in a layout with that container and avoid creating its view hierarchy
* in that case.)
- *
+ *
* <p>The attributes of the &lt;fragment&gt; tag are used to control the
* LayoutParams provided when attaching the fragment's view to the parent
* container. They can also be parsed by the fragment in {@link #onInflate}
* as parameters.
- *
+ *
* <p>The fragment being instantiated must have some kind of unique identifier
* so that it can be re-associated with a previous instance if the parent
* activity needs to be destroyed and recreated. This can be provided these
* ways:
- *
+ *
* <ul>
* <li>If nothing is explicitly supplied, the view ID of the container will
* be used.
@@ -318,7 +322,7 @@ final class FragmentState implements Parcelable {
* <li><code>android:id</code> can be used in &lt;fragment&gt; to provide
* a specific identifier for the fragment.
* </ul>
- *
+ *
* <a name="BackStack"></a>
* <h3>Back Stack</h3>
*
@@ -347,7 +351,7 @@ final class FragmentState implements Parcelable {
public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener {
private static final ArrayMap<String, Class<?>> sClassMap =
new ArrayMap<String, Class<?>>();
-
+
static final int INVALID_STATE = -1; // Invalid state used as a null value.
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
@@ -355,9 +359,11 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
static final int STOPPED = 3; // Fully created, not started.
static final int STARTED = 4; // Created and started, not resumed.
static final int RESUMED = 5; // Created started and resumed.
-
+
+ private static final Transition USE_DEFAULT_TRANSITION = new TransitionSet();
+
int mState = INITIALIZING;
-
+
// Non-null if the fragment's view hierarchy is currently animating away,
// meaning we need to wait a bit on completely destroying it. This is the
// animation that is running.
@@ -370,13 +376,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
// When instantiated from saved state, this is the saved state.
Bundle mSavedFragmentState;
SparseArray<Parcelable> mSavedViewState;
-
+
// Index into active fragment array.
int mIndex = -1;
-
+
// Internal unique name for this fragment;
String mWho;
-
+
// Construction arguments;
Bundle mArguments;
@@ -391,25 +397,25 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
// True if the fragment is in the list of added fragments.
boolean mAdded;
-
+
// If set this fragment is being removed from its activity.
boolean mRemoving;
// True if the fragment is in the resumed state.
boolean mResumed;
-
+
// Set to true if this fragment was instantiated from a layout file.
boolean mFromLayout;
-
+
// Set to true when the view has actually been inflated in its layout.
boolean mInLayout;
// True if this fragment has been restored from previously saved state.
boolean mRestored;
-
+
// Number of active back stack entries this fragment is in.
int mBackStackNesting;
-
+
// The fragment manager we are associated with. Set as soon as the
// fragment is used in a transaction; cleared after it has been removed
// from all transactions.
@@ -428,29 +434,29 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
// was dynamically added to the view hierarchy, or the ID supplied in
// layout.
int mFragmentId;
-
+
// When a fragment is being dynamically added to the view hierarchy, this
// is the identifier of the parent container it is being added to.
int mContainerId;
-
+
// The optional named tag for this fragment -- usually used to find
// fragments that are not part of the layout.
String mTag;
-
+
// Set to true when the app has requested that this fragment be hidden
// from the user.
boolean mHidden;
-
+
// Set to true when the app has requested that this fragment be detached.
boolean mDetached;
// If set this fragment would like its instance retained across
// configuration changes.
boolean mRetainInstance;
-
+
// If set this fragment is being retained across the current config change.
boolean mRetaining;
-
+
// If set this fragment has menu items to contribute.
boolean mHasMenu;
@@ -459,16 +465,16 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
// Used to verify that subclasses call through to super class.
boolean mCalled;
-
+
// If app has requested a specific animation, this is the one to use.
int mNextAnim;
-
+
// The parent container of the fragment after dynamically added to UI.
ViewGroup mContainer;
-
+
// The View generated for this fragment.
View mView;
-
+
// Whether this fragment should defer starting until after other fragments
// have been started and their loaders are finished.
boolean mDeferStart;
@@ -479,7 +485,19 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
LoaderManagerImpl mLoaderManager;
boolean mLoadersStarted;
boolean mCheckedForLoaderManager;
-
+
+ private Transition mEnterTransition = null;
+ private Transition mReturnTransition = USE_DEFAULT_TRANSITION;
+ private Transition mExitTransition = null;
+ private Transition mReenterTransition = USE_DEFAULT_TRANSITION;
+ private Transition mSharedElementEnterTransition = null;
+ private Transition mSharedElementReturnTransition = USE_DEFAULT_TRANSITION;
+ private Boolean mAllowReturnTransitionOverlap;
+ private Boolean mAllowEnterTransitionOverlap;
+
+ SharedElementListener mEnterTransitionListener = SharedElementListener.NULL_LISTENER;
+ SharedElementListener mExitTransitionListener = SharedElementListener.NULL_LISTENER;
+
/**
* State information that has been retrieved from a fragment instance
* through {@link FragmentManager#saveFragmentInstanceState(Fragment)
@@ -543,7 +561,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* will not be called when the fragment is re-instantiated; instead,
* arguments can be supplied by the caller with {@link #setArguments}
* and later retrieved by the Fragment with {@link #getArguments}.
- *
+ *
* <p>Applications should generally not implement a constructor. The
* first place application code an run where the fragment is ready to
* be used is in {@link #onAttach(Activity)}, the point where the fragment
@@ -609,7 +627,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
+ " empty constructor that is public", e);
}
}
-
+
final void restoreViewState(Bundle savedInstanceState) {
if (mSavedViewState != null) {
mView.restoreHierarchyState(mSavedViewState);
@@ -649,7 +667,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
@Override final public int hashCode() {
return super.hashCode();
}
-
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
@@ -669,7 +687,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
sb.append('}');
return sb.toString();
}
-
+
/**
* Return the identifier this fragment is known by. This is either
* the android:id value supplied in a layout or the container view ID
@@ -678,14 +696,14 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
final public int getId() {
return mFragmentId;
}
-
+
/**
* Get the tag name of the fragment, if specified.
*/
final public String getTag() {
return mTag;
}
-
+
/**
* Supply the construction arguments for this fragment. This can only
* be called before the fragment has been attached to its activity; that
@@ -760,7 +778,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
final public Activity getActivity() {
return mActivity;
}
-
+
/**
* Return <code>getActivity().getResources()</code>.
*/
@@ -770,7 +788,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
return mActivity.getResources();
}
-
+
/**
* Return a localized, styled CharSequence from the application's package's
* default string table.
@@ -870,7 +888,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
final public boolean isRemoving() {
return mRemoving;
}
-
+
/**
* Return true if the layout is included as part of an activity view
* hierarchy via the &lt;fragment&gt; tag. This will always be true when
@@ -889,7 +907,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
final public boolean isResumed() {
return mResumed;
}
-
+
/**
* Return true if the fragment is currently visible to the user. This means
* it: (1) has been added, (2) has its view attached to the window, and
@@ -899,7 +917,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
return isAdded() && !isHidden() && mView != null
&& mView.getWindowToken() != null && mView.getVisibility() == View.VISIBLE;
}
-
+
/**
* Return true if the fragment has been hidden. By default fragments
* are shown. You can find out about changes to this state with
@@ -910,7 +928,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
final public boolean isHidden() {
return mHidden;
}
-
+
/**
* Called when the hidden state (as returned by {@link #isHidden()} of
* the fragment has changed. Fragments start out not hidden; this will
@@ -920,7 +938,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
*/
public void onHiddenChanged(boolean hidden) {
}
-
+
/**
* Control whether a fragment instance is retained across Activity
* re-creation (such as from a configuration change). This can only
@@ -942,16 +960,16 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
mRetainInstance = retain;
}
-
+
final public boolean getRetainInstance() {
return mRetainInstance;
}
-
+
/**
* Report that this fragment would like to participate in populating
* the options menu by receiving a call to {@link #onCreateOptionsMenu}
* and related methods.
- *
+ *
* @param hasMenu If true, the fragment has menu items to contribute.
*/
public void setHasOptionsMenu(boolean hasMenu) {
@@ -1034,7 +1052,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public void startActivity(Intent intent) {
startActivity(intent, null);
}
-
+
/**
* Call {@link Activity#startActivity(Intent, Bundle)} from the fragment's
* containing Activity.
@@ -1081,13 +1099,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
mActivity.startActivityFromFragment(this, intent, requestCode, options);
}
}
-
+
/**
* Receive the result from a previous call to
* {@link #startActivityForResult(Intent, int)}. This follows the
* related Activity API as described there in
* {@link Activity#onActivityResult(int, int, Intent)}.
- *
+ *
* @param requestCode The integer request code originally supplied to
* startActivityForResult(), allowing you to identify who this
* result came from.
@@ -1098,7 +1116,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
*/
public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
-
+
/**
* @hide Hack so that DialogFragment can make its Dialog before creating
* its views, and the view construction can use the dialog's context for
@@ -1115,7 +1133,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
return mActivity.getLayoutInflater();
}
}
-
+
/**
* @deprecated Use {@link #onInflate(Activity, AttributeSet, Bundle)} instead.
*/
@@ -1131,7 +1149,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* tag in a layout file. Note this is <em>before</em> the fragment's
* {@link #onAttach(Activity)} has been called; all you should do here is
* parse the attributes and save them away.
- *
+ *
* <p>This is called every time the fragment is inflated, even if it is
* being inflated into a new instance with saved state. It typically makes
* sense to re-parse the parameters each time, to allow them to change with
@@ -1169,8 +1187,33 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
onInflate(attrs, savedInstanceState);
mCalled = true;
+
+ TypedArray a = activity.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.Fragment);
+ mEnterTransition = loadTransition(activity, a, mEnterTransition, null,
+ com.android.internal.R.styleable.Fragment_fragmentEnterTransition);
+ mReturnTransition = loadTransition(activity, a, mReturnTransition, USE_DEFAULT_TRANSITION,
+ com.android.internal.R.styleable.Fragment_fragmentReturnTransition);
+ mExitTransition = loadTransition(activity, a, mExitTransition, null,
+ com.android.internal.R.styleable.Fragment_fragmentExitTransition);
+ mReenterTransition = loadTransition(activity, a, mReenterTransition, USE_DEFAULT_TRANSITION,
+ com.android.internal.R.styleable.Fragment_fragmentReenterTransition);
+ mSharedElementEnterTransition = loadTransition(activity, a, mSharedElementEnterTransition,
+ null, com.android.internal.R.styleable.Fragment_fragmentSharedElementEnterTransition);
+ mSharedElementReturnTransition = loadTransition(activity, a, mSharedElementReturnTransition,
+ USE_DEFAULT_TRANSITION,
+ com.android.internal.R.styleable.Fragment_fragmentSharedElementReturnTransition);
+ if (mAllowEnterTransitionOverlap == null) {
+ mAllowEnterTransitionOverlap = a.getBoolean(
+ com.android.internal.R.styleable.Fragment_fragmentAllowEnterTransitionOverlap, true);
+ }
+ if (mAllowReturnTransitionOverlap == null) {
+ mAllowReturnTransitionOverlap = a.getBoolean(
+ com.android.internal.R.styleable.Fragment_fragmentAllowReturnTransitionOverlap, true);
+ }
+ a.recycle();
}
-
+
/**
* Called when a fragment is first attached to its activity.
* {@link #onCreate(Bundle)} will be called after this.
@@ -1178,25 +1221,25 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public void onAttach(Activity activity) {
mCalled = true;
}
-
+
/**
* Called when a fragment loads an animation.
*/
public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
return null;
}
-
+
/**
* Called to do initial creation of a fragment. This is called after
* {@link #onAttach(Activity)} and before
* {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
- *
+ *
* <p>Note that this can be called while the fragment's activity is
* still in the process of being created. As such, you can not rely
* on things like the activity's content view hierarchy being initialized
* at this point. If you want to do work once the activity itself is
* created, see {@link #onActivityCreated(Bundle)}.
- *
+ *
* @param savedInstanceState If the fragment is being re-created from
* a previous saved state, this is the state.
*/
@@ -1209,10 +1252,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* This is optional, and non-graphical fragments can return null (which
* is the default implementation). This will be called between
* {@link #onCreate(Bundle)} and {@link #onActivityCreated(Bundle)}.
- *
+ *
* <p>If you return a View from here, you will later be called in
* {@link #onDestroyView} when the view is being released.
- *
+ *
* @param inflater The LayoutInflater object that can be used to inflate
* any views in the fragment,
* @param container If non-null, this is the parent view that the fragment's
@@ -1220,7 +1263,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* but this can be used to generate the LayoutParams of the view.
* @param savedInstanceState If non-null, this fragment is being re-constructed
* from a previous saved state as given here.
- *
+ *
* @return Return the View for the fragment's UI, or null.
*/
@Nullable
@@ -1241,18 +1284,18 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
*/
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
}
-
+
/**
* Get the root view for the fragment's layout (the one returned by {@link #onCreateView}),
* if provided.
- *
+ *
* @return The fragment's root view, or null if it has no layout.
*/
@Nullable
public View getView() {
return mView;
}
-
+
/**
* Called when the fragment's activity has been created and this
* fragment's view hierarchy instantiated. It can be used to do final
@@ -1292,7 +1335,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
*/
public void onStart() {
mCalled = true;
-
+
if (!mLoadersStarted) {
mLoadersStarted = true;
if (!mCheckedForLoaderManager) {
@@ -1304,7 +1347,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
}
}
}
-
+
/**
* Called when the fragment is visible to the user and actively running.
* This is generally
@@ -1314,7 +1357,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public void onResume() {
mCalled = true;
}
-
+
/**
* Called to ask the fragment to save its current dynamic state, so it
* can later be reconstructed in a new instance of its process is
@@ -1336,11 +1379,11 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
*/
public void onSaveInstanceState(Bundle outState) {
}
-
+
public void onConfigurationChanged(Configuration newConfig) {
mCalled = true;
}
-
+
/**
* Called when the Fragment is no longer resumed. This is generally
* tied to {@link Activity#onPause() Activity.onPause} of the containing
@@ -1349,7 +1392,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public void onPause() {
mCalled = true;
}
-
+
/**
* Called when the Fragment is no longer started. This is generally
* tied to {@link Activity#onStop() Activity.onStop} of the containing
@@ -1358,11 +1401,11 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public void onStop() {
mCalled = true;
}
-
+
public void onLowMemory() {
mCalled = true;
}
-
+
public void onTrimMemory(int level) {
mCalled = true;
}
@@ -1379,7 +1422,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public void onDestroyView() {
mCalled = true;
}
-
+
/**
* Called when the fragment is no longer in use. This is called
* after {@link #onStop()} and before {@link #onDetach()}.
@@ -1434,16 +1477,16 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public void onDetach() {
mCalled = true;
}
-
+
/**
* Initialize the contents of the Activity's standard options menu. You
* should place your menu items in to <var>menu</var>. For this method
* to be called, you must have first called {@link #setHasOptionsMenu}. See
* {@link Activity#onCreateOptionsMenu(Menu) Activity.onCreateOptionsMenu}
* for more information.
- *
+ *
* @param menu The options menu in which you place your items.
- *
+ *
* @see #setHasOptionsMenu
* @see #onPrepareOptionsMenu
* @see #onOptionsItemSelected
@@ -1458,10 +1501,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* dynamically modify the contents. See
* {@link Activity#onPrepareOptionsMenu(Menu) Activity.onPrepareOptionsMenu}
* for more information.
- *
+ *
* @param menu The options menu as last shown or first initialized by
* onCreateOptionsMenu().
- *
+ *
* @see #setHasOptionsMenu
* @see #onCreateOptionsMenu
*/
@@ -1477,7 +1520,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
*/
public void onDestroyOptionsMenu() {
}
-
+
/**
* This hook is called whenever an item in your options menu is selected.
* The default implementation simply returns false to have the normal
@@ -1485,15 +1528,15 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* its Handler as appropriate). You can use this method for any items
* for which you would like to do processing without those other
* facilities.
- *
+ *
* <p>Derived classes should call through to the base class for it to
* perform the default menu handling.
- *
+ *
* @param item The menu item that was selected.
- *
+ *
* @return boolean Return false to allow normal menu processing to
* proceed, true to consume it here.
- *
+ *
* @see #onCreateOptionsMenu
*/
public boolean onOptionsItemSelected(MenuItem item) {
@@ -1503,13 +1546,13 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
/**
* This hook is called whenever the options menu is being closed (either by the user canceling
* the menu with the back/menu button, or when an item is selected).
- *
+ *
* @param menu The options menu as last shown or first initialized by
* onCreateOptionsMenu().
*/
public void onOptionsMenuClosed(Menu menu) {
}
-
+
/**
* Called when a context menu for the {@code view} is about to be shown.
* Unlike {@link #onCreateOptionsMenu}, this will be called every
@@ -1537,25 +1580,25 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* {@link OnCreateContextMenuListener} on the view to this fragment, so
* {@link #onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} will be
* called when it is time to show the context menu.
- *
+ *
* @see #unregisterForContextMenu(View)
* @param view The view that should show a context menu.
*/
public void registerForContextMenu(View view) {
view.setOnCreateContextMenuListener(this);
}
-
+
/**
* Prevents a context menu to be shown for the given view. This method will
* remove the {@link OnCreateContextMenuListener} on the view.
- *
+ *
* @see #registerForContextMenu(View)
* @param view The view that should stop showing a context menu.
*/
public void unregisterForContextMenu(View view) {
view.setOnCreateContextMenuListener(null);
}
-
+
/**
* This hook is called whenever an item in a context menu is selected. The
* default implementation simply returns false to have the normal processing
@@ -1568,7 +1611,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* <p>
* Derived classes should call through to the base class for it to perform
* the default menu handling.
- *
+ *
* @param item The context menu item that was selected.
* @return boolean Return false to allow normal context menu processing to
* proceed, true to consume it here.
@@ -1576,7 +1619,284 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public boolean onContextItemSelected(MenuItem item) {
return false;
}
-
+
+ /**
+ * When custom transitions are used with Fragments, the enter transition listener
+ * is called when this Fragment is attached or detached when not popping the back stack.
+ *
+ * @param listener Used to manipulate the shared element transitions on this Fragment
+ * when added not as a pop from the back stack.
+ */
+ public void setEnterSharedElementTransitionListener(SharedElementListener listener) {
+ if (listener == null) {
+ listener = SharedElementListener.NULL_LISTENER;
+ }
+ mEnterTransitionListener = listener;
+ }
+
+ /**
+ * When custom transitions are used with Fragments, the exit transition listener
+ * is called when this Fragment is attached or detached when popping the back stack.
+ *
+ * @param listener Used to manipulate the shared element transitions on this Fragment
+ * when added as a pop from the back stack.
+ */
+ public void setExitSharedElementTransitionListener(SharedElementListener listener) {
+ if (listener == null) {
+ listener = SharedElementListener.NULL_LISTENER;
+ }
+ mExitTransitionListener = listener;
+ }
+
+ /**
+ * Sets the Transition that will be used to move Views into the initial scene. The entering
+ * Views will be those that are regular Views or ViewGroups that have
+ * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+ * {@link android.transition.Visibility} as entering is governed by changing visibility from
+ * {@link View#INVISIBLE} to {@link View#VISIBLE}. If <code>transition</code> is null,
+ * entering Views will remain unaffected.
+ *
+ * @param transition The Transition to use to move Views into the initial Scene.
+ * @attr ref android.R.styleable#Fragment_fragmentEnterTransition
+ */
+ public void setEnterTransition(Transition transition) {
+ mEnterTransition = transition;
+ }
+
+ /**
+ * Returns the Transition that will be used to move Views into the initial scene. The entering
+ * Views will be those that are regular Views or ViewGroups that have
+ * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+ * {@link android.transition.Visibility} as entering is governed by changing visibility from
+ * {@link View#INVISIBLE} to {@link View#VISIBLE}.
+ *
+ * @return the Transition to use to move Views into the initial Scene.
+ * @attr ref android.R.styleable#Fragment_fragmentEnterTransition
+ */
+ public Transition getEnterTransition() {
+ return mEnterTransition;
+ }
+
+ /**
+ * Sets the Transition that will be used to move Views out of the scene when the Fragment is
+ * preparing to be removed, hidden, or detached because of popping the back stack. The exiting
+ * Views will be those that are regular Views or ViewGroups that have
+ * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+ * {@link android.transition.Visibility} as entering is governed by changing visibility from
+ * {@link View#VISIBLE} to {@link View#INVISIBLE}. If <code>transition</code> is null,
+ * entering Views will remain unaffected. If nothing is set, the default will be to
+ * use the same value as set in {@link #setEnterTransition(android.transition.Transition)}.
+ *
+ * @param transition The Transition to use to move Views out of the Scene when the Fragment
+ * is preparing to close.
+ * @attr ref android.R.styleable#Fragment_fragmentExitTransition
+ */
+ public void setReturnTransition(Transition transition) {
+ mReturnTransition = transition;
+ }
+
+ /**
+ * Returns the Transition that will be used to move Views out of the scene when the Fragment is
+ * preparing to be removed, hidden, or detached because of popping the back stack. The exiting
+ * Views will be those that are regular Views or ViewGroups that have
+ * {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+ * {@link android.transition.Visibility} as entering is governed by changing visibility from
+ * {@link View#VISIBLE} to {@link View#INVISIBLE}. If <code>transition</code> is null,
+ * entering Views will remain unaffected.
+ *
+ * @return the Transition to use to move Views out of the Scene when the Fragment
+ * is preparing to close.
+ * @attr ref android.R.styleable#Fragment_fragmentExitTransition
+ */
+ public Transition getReturnTransition() {
+ return mReturnTransition == USE_DEFAULT_TRANSITION ? getEnterTransition()
+ : mReturnTransition;
+ }
+
+ /**
+ * Sets the Transition that will be used to move Views out of the scene when the
+ * fragment is removed, hidden, or detached when not popping the back stack.
+ * The exiting Views will be those that are regular Views or ViewGroups that
+ * have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+ * {@link android.transition.Visibility} as exiting is governed by changing visibility
+ * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will
+ * remain unaffected.
+ *
+ * @param transition The Transition to use to move Views out of the Scene when the Fragment
+ * is being closed not due to popping the back stack.
+ * @attr ref android.R.styleable#Fragment_fragmentExitTransition
+ */
+ public void setExitTransition(Transition transition) {
+ mExitTransition = transition;
+ }
+
+ /**
+ * Returns the Transition that will be used to move Views out of the scene when the
+ * fragment is removed, hidden, or detached when not popping the back stack.
+ * The exiting Views will be those that are regular Views or ViewGroups that
+ * have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
+ * {@link android.transition.Visibility} as exiting is governed by changing visibility
+ * from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will
+ * remain unaffected.
+ *
+ * @return the Transition to use to move Views out of the Scene when the Fragment
+ * is being closed not due to popping the back stack.
+ * @attr ref android.R.styleable#Fragment_fragmentExitTransition
+ */
+ public Transition getExitTransition() {
+ return mExitTransition;
+ }
+
+ /**
+ * Sets the Transition that will be used to move Views in to the scene when returning due
+ * to popping a back stack. The entering Views will be those that are regular Views
+ * or ViewGroups that have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions
+ * will extend {@link android.transition.Visibility} as exiting is governed by changing
+ * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null,
+ * the views will remain unaffected. If nothing is set, the default will be to use the same
+ * transition as {@link #setExitTransition(android.transition.Transition)}.
+ *
+ * @param transition The Transition to use to move Views into the scene when reentering from a
+ * previously-started Activity.
+ * @attr ref android.R.styleable#Fragment_fragmentReenterTransition
+ */
+ public void setReenterTransition(Transition transition) {
+ mReenterTransition = transition;
+ }
+
+ /**
+ * Returns the Transition that will be used to move Views in to the scene when returning due
+ * to popping a back stack. The entering Views will be those that are regular Views
+ * or ViewGroups that have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions
+ * will extend {@link android.transition.Visibility} as exiting is governed by changing
+ * visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null,
+ * the views will remain unaffected. If nothing is set, the default will be to use the same
+ * transition as {@link #setExitTransition(android.transition.Transition)}.
+ *
+ * @return the Transition to use to move Views into the scene when reentering from a
+ * previously-started Activity.
+ * @attr ref android.R.styleable#Fragment_fragmentReenterTransition
+ */
+ public Transition getReenterTransition() {
+ return mReenterTransition == USE_DEFAULT_TRANSITION ? getExitTransition()
+ : mReenterTransition;
+ }
+
+ /**
+ * Sets the Transition that will be used for shared elements transferred into the content
+ * Scene. Typical Transitions will affect size and location, such as
+ * {@link android.transition.ChangeBounds}. A null
+ * value will cause transferred shared elements to blink to the final position.
+ *
+ * @param transition The Transition to use for shared elements transferred into the content
+ * Scene.
+ * @attr ref android.R.styleable#Fragment_fragmentSharedElementEnterTransition
+ */
+ public void setSharedElementEnterTransition(Transition transition) {
+ mSharedElementEnterTransition = transition;
+ }
+
+ /**
+ * Returns the Transition that will be used for shared elements transferred into the content
+ * Scene. Typical Transitions will affect size and location, such as
+ * {@link android.transition.ChangeBounds}. A null
+ * value will cause transferred shared elements to blink to the final position.
+ *
+ * @return The Transition to use for shared elements transferred into the content
+ * Scene.
+ * @attr ref android.R.styleable#Fragment_fragmentSharedElementEnterTransition
+ */
+ public Transition getSharedElementEnterTransition() {
+ return mSharedElementEnterTransition;
+ }
+
+ /**
+ * Sets the Transition that will be used for shared elements transferred back during a
+ * pop of the back stack. This Transition acts in the leaving Fragment.
+ * Typical Transitions will affect size and location, such as
+ * {@link android.transition.ChangeBounds}. A null
+ * value will cause transferred shared elements to blink to the final position.
+ * If no value is set, the default will be to use the same value as
+ * {@link #setSharedElementEnterTransition(android.transition.Transition)}.
+ *
+ * @param transition The Transition to use for shared elements transferred out of the content
+ * Scene.
+ * @attr ref android.R.styleable#Fragment_fragmentSharedElementReturnTransition
+ */
+ public void setSharedElementReturnTransition(Transition transition) {
+ mSharedElementReturnTransition = transition;
+ }
+
+ /**
+ * Return the Transition that will be used for shared elements transferred back during a
+ * pop of the back stack. This Transition acts in the leaving Fragment.
+ * Typical Transitions will affect size and location, such as
+ * {@link android.transition.ChangeBounds}. A null
+ * value will cause transferred shared elements to blink to the final position.
+ * If no value is set, the default will be to use the same value as
+ * {@link #setSharedElementEnterTransition(android.transition.Transition)}.
+ *
+ * @return The Transition to use for shared elements transferred out of the content
+ * Scene.
+ * @attr ref android.R.styleable#Fragment_fragmentSharedElementReturnTransition
+ */
+ public Transition getSharedElementReturnTransition() {
+ return mSharedElementReturnTransition == USE_DEFAULT_TRANSITION ?
+ getSharedElementEnterTransition() : mSharedElementReturnTransition;
+ }
+
+ /**
+ * Sets whether the the exit transition and enter transition overlap or not.
+ * When true, the enter transition will start as soon as possible. When false, the
+ * enter transition will wait until the exit transition completes before starting.
+ *
+ * @param allow true to start the enter transition when possible or false to
+ * wait until the exiting transition completes.
+ * @attr ref android.R.styleable#Fragment_fragmentAllowEnterTransitionOverlap
+ */
+ public void setAllowEnterTransitionOverlap(boolean allow) {
+ mAllowEnterTransitionOverlap = allow;
+ }
+
+ /**
+ * Returns whether the the exit transition and enter transition overlap or not.
+ * When true, the enter transition will start as soon as possible. When false, the
+ * enter transition will wait until the exit transition completes before starting.
+ *
+ * @return true when the enter transition should start as soon as possible or false to
+ * when it should wait until the exiting transition completes.
+ * @attr ref android.R.styleable#Fragment_fragmentAllowEnterTransitionOverlap
+ */
+ public boolean getAllowEnterTransitionOverlap() {
+ return (mAllowEnterTransitionOverlap == null) ? true : mAllowEnterTransitionOverlap;
+ }
+
+ /**
+ * Sets whether the the return transition and reenter transition overlap or not.
+ * When true, the reenter transition will start as soon as possible. When false, the
+ * reenter transition will wait until the return transition completes before starting.
+ *
+ * @param allow true to start the reenter transition when possible or false to wait until the
+ * return transition completes.
+ * @attr ref android.R.styleable#Fragment_fragmentAllowReturnTransitionOverlap
+ */
+ public void setAllowReturnTransitionOverlap(boolean allow) {
+ mAllowReturnTransitionOverlap = allow;
+ }
+
+ /**
+ * Returns whether the the return transition and reenter transition overlap or not.
+ * When true, the reenter transition will start as soon as possible. When false, the
+ * reenter transition will wait until the return transition completes before starting.
+ *
+ * @return true to start the reenter transition when possible or false to wait until the
+ * return transition completes.
+ * @attr ref android.R.styleable#Fragment_fragmentAllowReturnTransitionOverlap
+ */
+ public boolean getAllowReturnTransitionOverlap() {
+ return (mAllowReturnTransitionOverlap == null) ? true : mAllowReturnTransitionOverlap;
+ }
+
/**
* Print the Fragments's state into the given stream.
*
@@ -1588,53 +1908,53 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
*/
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
writer.print(prefix); writer.print("mFragmentId=#");
- writer.print(Integer.toHexString(mFragmentId));
- writer.print(" mContainerId=#");
- writer.print(Integer.toHexString(mContainerId));
- writer.print(" mTag="); writer.println(mTag);
+ writer.print(Integer.toHexString(mFragmentId));
+ writer.print(" mContainerId=#");
+ writer.print(Integer.toHexString(mContainerId));
+ writer.print(" mTag="); writer.println(mTag);
writer.print(prefix); writer.print("mState="); writer.print(mState);
- writer.print(" mIndex="); writer.print(mIndex);
- writer.print(" mWho="); writer.print(mWho);
- writer.print(" mBackStackNesting="); writer.println(mBackStackNesting);
+ writer.print(" mIndex="); writer.print(mIndex);
+ writer.print(" mWho="); writer.print(mWho);
+ writer.print(" mBackStackNesting="); writer.println(mBackStackNesting);
writer.print(prefix); writer.print("mAdded="); writer.print(mAdded);
- writer.print(" mRemoving="); writer.print(mRemoving);
- writer.print(" mResumed="); writer.print(mResumed);
- writer.print(" mFromLayout="); writer.print(mFromLayout);
- writer.print(" mInLayout="); writer.println(mInLayout);
+ writer.print(" mRemoving="); writer.print(mRemoving);
+ writer.print(" mResumed="); writer.print(mResumed);
+ writer.print(" mFromLayout="); writer.print(mFromLayout);
+ writer.print(" mInLayout="); writer.println(mInLayout);
writer.print(prefix); writer.print("mHidden="); writer.print(mHidden);
- writer.print(" mDetached="); writer.print(mDetached);
- writer.print(" mMenuVisible="); writer.print(mMenuVisible);
- writer.print(" mHasMenu="); writer.println(mHasMenu);
+ writer.print(" mDetached="); writer.print(mDetached);
+ writer.print(" mMenuVisible="); writer.print(mMenuVisible);
+ writer.print(" mHasMenu="); writer.println(mHasMenu);
writer.print(prefix); writer.print("mRetainInstance="); writer.print(mRetainInstance);
- writer.print(" mRetaining="); writer.print(mRetaining);
- writer.print(" mUserVisibleHint="); writer.println(mUserVisibleHint);
+ writer.print(" mRetaining="); writer.print(mRetaining);
+ writer.print(" mUserVisibleHint="); writer.println(mUserVisibleHint);
if (mFragmentManager != null) {
writer.print(prefix); writer.print("mFragmentManager=");
- writer.println(mFragmentManager);
+ writer.println(mFragmentManager);
}
if (mActivity != null) {
writer.print(prefix); writer.print("mActivity=");
- writer.println(mActivity);
+ writer.println(mActivity);
}
if (mParentFragment != null) {
writer.print(prefix); writer.print("mParentFragment=");
- writer.println(mParentFragment);
+ writer.println(mParentFragment);
}
if (mArguments != null) {
writer.print(prefix); writer.print("mArguments="); writer.println(mArguments);
}
if (mSavedFragmentState != null) {
writer.print(prefix); writer.print("mSavedFragmentState=");
- writer.println(mSavedFragmentState);
+ writer.println(mSavedFragmentState);
}
if (mSavedViewState != null) {
writer.print(prefix); writer.print("mSavedViewState=");
- writer.println(mSavedViewState);
+ writer.println(mSavedViewState);
}
if (mTarget != null) {
writer.print(prefix); writer.print("mTarget="); writer.print(mTarget);
- writer.print(" mTargetRequestCode=");
- writer.println(mTargetRequestCode);
+ writer.print(" mTargetRequestCode=");
+ writer.println(mTargetRequestCode);
}
if (mNextAnim != 0) {
writer.print(prefix); writer.print("mNextAnim="); writer.println(mNextAnim);
@@ -1648,7 +1968,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
if (mAnimatingAway != null) {
writer.print(prefix); writer.print("mAnimatingAway="); writer.println(mAnimatingAway);
writer.print(prefix); writer.print("mStateAfterAnimating=");
- writer.println(mStateAfterAnimating);
+ writer.println(mStateAfterAnimating);
}
if (mLoaderManager != null) {
writer.print(prefix); writer.println("Loader Manager:");
@@ -1886,7 +2206,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onStop()");
}
-
+
if (mLoadersStarted) {
mLoadersStarted = false;
if (!mCheckedForLoaderManager) {
@@ -1929,4 +2249,23 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
+ " did not call through to super.onDestroy()");
}
}
+
+ private static Transition loadTransition(Context context, TypedArray typedArray,
+ Transition currentValue, Transition defaultValue, int id) {
+ if (currentValue != defaultValue) {
+ return currentValue;
+ }
+ int transitionId = typedArray.getResourceId(id, 0);
+ Transition transition = defaultValue;
+ if (transitionId != 0 && transitionId != com.android.internal.R.transition.no_transition) {
+ TransitionInflater inflater = TransitionInflater.from(context);
+ transition = inflater.inflateTransition(transitionId);
+ if (transition instanceof TransitionSet &&
+ ((TransitionSet)transition).getTransitionCount() == 0) {
+ transition = null;
+ }
+ }
+ return transition;
+ }
+
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 1df1d42..ef69fdd 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1497,7 +1497,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
return false;
}
final BackStackRecord bss = mBackStack.remove(last);
- bss.popFromBackStack(true, null);
+ SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
+ SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
+ bss.calculateBackFragments(firstOutFragments, lastInFragments);
+ bss.popFromBackStack(true, null, firstOutFragments, lastInFragments);
reportBackStackChanged();
} else {
int index = -1;
@@ -1541,10 +1544,16 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
states.add(mBackStack.remove(i));
}
final int LAST = states.size()-1;
+ SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
+ SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
+ for (int i=0; i<=LAST; i++) {
+ states.get(i).calculateBackFragments(firstOutFragments, lastInFragments);
+ }
BackStackRecord.TransitionState state = null;
for (int i=0; i<=LAST; i++) {
if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
- state = states.get(i).popFromBackStack(i == LAST, state);
+ state = states.get(i).popFromBackStack(i == LAST, state,
+ firstOutFragments, lastInFragments);
}
reportBackStackChanged();
}
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 1077bac..25cd3cc 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -172,19 +172,16 @@ public abstract class FragmentTransaction {
public abstract FragmentTransaction setTransition(int transit);
/**
- * Set a {@link android.transition.Transition} resource id to use with this transaction.
- * <var>transitionId</var> will be played for fragments when going forward and when popping
- * the back stack.
- * @param sceneRootId The ID of the element acting as the scene root for the transition.
- * This should be a ViewGroup containing all Fragments in the transaction.
- * @param transitionId The resource ID for the Transition used during the Fragment transaction.
+ * TODO: remove from API
+ * @hide
*/
- public abstract FragmentTransaction setCustomTransition(int sceneRootId, int transitionId);
+ public FragmentTransaction setCustomTransition(int sceneRootId, int transitionId) {
+ return this;
+ }
/**
- * Used with {@link #setCustomTransition(int, int)} to map a View from a removed or hidden
- * Fragment to a View from a shown or added Fragment.
- * <var>sharedElement</var> must have a unique transitionName in the View hierarchy.
+ * Used with to map a View from a removed or hidden Fragment to a View from a shown
+ * or added Fragment.
* @param sharedElement A View in a disappearing Fragment to match with a View in an
* appearing Fragment.
* @param name The transitionName for a View in an appearing Fragment to match to the shared
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 214f50c..dbd180f 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -23,6 +23,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.net.Uri;
+import android.os.Bundle;
import android.service.notification.Condition;
import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
@@ -58,13 +59,15 @@ interface INotificationManager
void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
- ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys);
+ ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim);
void requestHintsFromListener(in INotificationListener token, int hints);
int getHintsFromListener(in INotificationListener token);
void requestInterruptionFilterFromListener(in INotificationListener token, int interruptionFilter);
int getInterruptionFilterFromListener(in INotificationListener token);
+ void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
ComponentName getEffectsSuppressor();
+ boolean matchesCallFilter(in Bundle extras);
ZenModeConfig getZenModeConfig();
boolean setZenModeConfig(in ZenModeConfig config);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8a26ba5..6cc6fb2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -22,7 +22,6 @@ import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
@@ -1424,6 +1423,9 @@ public class Notification implements Parcelable
extras.remove(Notification.EXTRA_LARGE_ICON);
extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
extras.remove(Notification.EXTRA_PICTURE);
+ extras.remove(Notification.EXTRA_BIG_TEXT);
+ // Prevent light notifications from being rebuilt.
+ extras.remove(Builder.EXTRA_NEEDS_REBUILD);
}
}
@@ -2621,10 +2623,46 @@ public class Notification implements Parcelable
contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
}
+ private void unshrinkLine3Text(RemoteViews contentView) {
+ float regularTextSize = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_text_size);
+ contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, regularTextSize);
+ }
+
+ private void resetStandardTemplate(RemoteViews contentView) {
+ removeLargeIconBackground(contentView);
+ contentView.setViewPadding(R.id.icon, 0, 0, 0, 0);
+ contentView.setImageViewResource(R.id.icon, 0);
+ contentView.setInt(R.id.icon, "setBackgroundResource", 0);
+ contentView.setViewVisibility(R.id.right_icon, View.GONE);
+ contentView.setInt(R.id.right_icon, "setBackgroundResource", 0);
+ contentView.setImageViewResource(R.id.right_icon, 0);
+ contentView.setImageViewResource(R.id.icon, 0);
+ contentView.setTextViewText(R.id.title, null);
+ contentView.setTextViewText(R.id.text, null);
+ unshrinkLine3Text(contentView);
+ contentView.setTextViewText(R.id.text2, null);
+ contentView.setViewVisibility(R.id.text2, View.GONE);
+ contentView.setViewVisibility(R.id.info, View.GONE);
+ contentView.setViewVisibility(R.id.time, View.GONE);
+ contentView.setViewVisibility(R.id.line3, View.GONE);
+ contentView.setViewVisibility(R.id.overflow_divider, View.GONE);
+ contentView.setViewVisibility(R.id.progress, View.GONE);
+ }
+
private RemoteViews applyStandardTemplate(int resId) {
+ return applyStandardTemplate(resId, true /* hasProgress */);
+ }
+
+ /**
+ * @param hasProgress whether the progress bar should be shown and set
+ */
+ private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) {
RemoteViews contentView = new BuilderRemoteViews(mContext.getPackageName(),
mOriginatingUserId, resId);
+ resetStandardTemplate(contentView);
+
boolean showLine3 = false;
boolean showLine2 = false;
boolean contentTextInLine2 = false;
@@ -2681,7 +2719,7 @@ public class Notification implements Parcelable
}
} else {
contentView.setViewVisibility(R.id.text2, View.GONE);
- if (mProgressMax != 0 || mProgressIndeterminate) {
+ if (hasProgress && (mProgressMax != 0 || mProgressIndeterminate)) {
contentView.setProgressBar(
R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
contentView.setViewVisibility(R.id.progress, View.VISIBLE);
@@ -2696,7 +2734,7 @@ public class Notification implements Parcelable
shrinkLine3Text(contentView);
}
- if (mWhen != 0 && mShowWhen) {
+ if (showsTimeOrChronometer()) {
if (mUseChronometer) {
contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
contentView.setLong(R.id.chronometer, "setBase",
@@ -2730,6 +2768,14 @@ public class Notification implements Parcelable
}
/**
+ * @return true if the built notification will show the time or the chronometer; false
+ * otherwise
+ */
+ private boolean showsTimeOrChronometer() {
+ return mWhen != 0 && mShowWhen;
+ }
+
+ /**
* Logic to find out whether the notification is going to have three lines in the contracted
* layout. This is used to adjust the top padding.
*
@@ -2738,13 +2784,14 @@ public class Notification implements Parcelable
*/
private boolean hasThreeLines() {
boolean contentTextInLine2 = mSubText != null && mContentText != null;
-
+ boolean hasProgress = mStyle == null || mStyle.hasProgress();
// If we have content text in line 2, badge goes into line 2, or line 3 otherwise
boolean badgeInLine3 = getProfileBadgeDrawable() != null && !contentTextInLine2;
boolean hasLine3 = mContentText != null || mContentInfo != null || mNumber > 0
|| badgeInLine3;
boolean hasLine2 = (mSubText != null && mContentText != null) ||
- (mSubText == null && (mProgressMax != 0 || mProgressIndeterminate));
+ (hasProgress && mSubText == null
+ && (mProgressMax != 0 || mProgressIndeterminate));
return hasLine2 && hasLine3;
}
@@ -2767,15 +2814,22 @@ public class Notification implements Parcelable
return Math.round((1 - largeFactor) * padding + largeFactor * largePadding);
}
+ private void resetStandardTemplateWithActions(RemoteViews big) {
+ big.setViewVisibility(R.id.actions, View.GONE);
+ big.setViewVisibility(R.id.action_divider, View.GONE);
+ big.removeAllViews(R.id.actions);
+ }
+
private RemoteViews applyStandardTemplateWithActions(int layoutId) {
RemoteViews big = applyStandardTemplate(layoutId);
+ resetStandardTemplateWithActions(big);
+
int N = mActions.size();
if (N > 0) {
big.setViewVisibility(R.id.actions, View.VISIBLE);
big.setViewVisibility(R.id.action_divider, View.VISIBLE);
if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
- big.removeAllViews(R.id.actions);
for (int i=0; i<N; i++) {
final RemoteViews button = generateActionButton(mActions.get(i));
big.addView(R.id.actions, button);
@@ -3486,6 +3540,15 @@ public class Notification implements Parcelable
checkBuilder();
return mBuilder.build();
}
+
+ /**
+ * @hide
+ * @return true if the style positions the progress bar on the second line; false if the
+ * style hides the progress bar
+ */
+ protected boolean hasProgress() {
+ return true;
+ }
}
/**
@@ -3883,7 +3946,7 @@ public class Notification implements Parcelable
* @see Notification#bigContentView
*/
public static class MediaStyle extends Style {
- static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 2;
+ static final int MAX_MEDIA_BUTTONS_IN_COMPACT = 3;
static final int MAX_MEDIA_BUTTONS = 5;
private int[] mActionsToShowInCompact = null;
@@ -3897,8 +3960,10 @@ public class Notification implements Parcelable
}
/**
- * Request up to 2 actions (by index in the order of addition) to be shown in the compact
+ * Request up to 3 actions (by index in the order of addition) to be shown in the compact
* notification view.
+ *
+ * @param actions the indices of the actions to show in the compact notification view
*/
public MediaStyle setShowActionsInCompactView(int...actions) {
mActionsToShowInCompact = actions;
@@ -3975,6 +4040,9 @@ public class Notification implements Parcelable
RemoteViews button = new RemoteViews(mBuilder.mContext.getPackageName(),
R.layout.notification_material_media_action);
button.setImageViewResource(R.id.action0, action.icon);
+ button.setDrawableParameters(R.id.action0, false, -1,
+ 0xFFFFFFFF,
+ PorterDuff.Mode.SRC_ATOP, -1);
if (!tombstone) {
button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
}
@@ -3984,14 +4052,14 @@ public class Notification implements Parcelable
private RemoteViews makeMediaContentView() {
RemoteViews view = mBuilder.applyStandardTemplate(
- R.layout.notification_template_material_media);
+ R.layout.notification_template_material_media, false /* hasProgress */);
final int numActions = mBuilder.mActions.size();
final int N = mActionsToShowInCompact == null
? 0
: Math.min(mActionsToShowInCompact.length, MAX_MEDIA_BUTTONS_IN_COMPACT);
if (N > 0) {
- view.removeAllViews(R.id.actions);
+ view.removeAllViews(com.android.internal.R.id.media_actions);
for (int i = 0; i < N; i++) {
if (i >= numActions) {
throw new IllegalArgumentException(String.format(
@@ -4001,26 +4069,73 @@ public class Notification implements Parcelable
final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]);
final RemoteViews button = generateMediaActionButton(action);
- view.addView(R.id.actions, button);
+ view.addView(com.android.internal.R.id.media_actions, button);
}
}
+ styleText(view);
+ hideRightIcon(view);
return view;
}
private RemoteViews makeMediaBigContentView() {
- RemoteViews big = mBuilder.applyStandardTemplate(
- R.layout.notification_template_material_big_media);
+ final int actionCount = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
+ RemoteViews big = mBuilder.applyStandardTemplate(getBigLayoutResource(actionCount),
+ false /* hasProgress */);
- final int N = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
- if (N > 0) {
- big.removeAllViews(R.id.actions);
- for (int i=0; i<N; i++) {
+ if (actionCount > 0) {
+ big.removeAllViews(com.android.internal.R.id.media_actions);
+ for (int i = 0; i < actionCount; i++) {
final RemoteViews button = generateMediaActionButton(mBuilder.mActions.get(i));
- big.addView(R.id.actions, button);
+ big.addView(com.android.internal.R.id.media_actions, button);
}
}
+ styleText(big);
+ hideRightIcon(big);
+ applyTopPadding(big);
+ big.setViewVisibility(android.R.id.progress, View.GONE);
return big;
}
+
+ private int getBigLayoutResource(int actionCount) {
+ if (actionCount <= 3) {
+ return R.layout.notification_template_material_big_media_narrow;
+ } else {
+ return R.layout.notification_template_material_big_media;
+ }
+ }
+
+ private void hideRightIcon(RemoteViews contentView) {
+ contentView.setViewVisibility(R.id.right_icon, View.GONE);
+ }
+
+ /**
+ * Applies the special text colors for media notifications to all text views.
+ */
+ private void styleText(RemoteViews contentView) {
+ int primaryColor = mBuilder.mContext.getResources().getColor(
+ R.color.notification_media_primary_color);
+ int secondaryColor = mBuilder.mContext.getResources().getColor(
+ R.color.notification_media_secondary_color);
+ contentView.setTextColor(R.id.title, primaryColor);
+ if (mBuilder.showsTimeOrChronometer()) {
+ if (mBuilder.mUseChronometer) {
+ contentView.setTextColor(R.id.chronometer, secondaryColor);
+ } else {
+ contentView.setTextColor(R.id.time, secondaryColor);
+ }
+ }
+ contentView.setTextColor(R.id.text2, secondaryColor);
+ contentView.setTextColor(R.id.text, secondaryColor);
+ contentView.setTextColor(R.id.info, secondaryColor);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ protected boolean hasProgress() {
+ return false;
+ }
}
// When adding a new Style subclass here, don't forget to update
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index fc047de..7dc1ad6 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -20,6 +20,7 @@ import android.annotation.SdkConstant;
import android.app.Notification.Builder;
import android.content.ComponentName;
import android.content.Context;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -251,5 +252,17 @@ public class NotificationManager
}
}
+ /**
+ * @hide
+ */
+ public boolean matchesCallFilter(Bundle extras) {
+ INotificationManager service = getService();
+ try {
+ return service.matchesCallFilter(extras);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
private Context mContext;
}
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index dcdfd78..723cb9b 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.SystemApi;
import android.content.Context;
import android.os.Bundle;
import android.os.IBinder;
@@ -33,6 +34,7 @@ import com.android.internal.os.SomeArgs;
import java.util.ArrayList;
/**
+ * @hide
* Interface for an {@link Activity} to interact with the user through voice. Use
* {@link android.app.Activity#getVoiceInteractor() Activity.getVoiceInteractor}
* to retrieve the interface, if the activity is currently involved in a voice interaction.
@@ -54,6 +56,7 @@ import java.util.ArrayList;
* request, rather than holding on to the activity instance yourself, either explicitly
* or implicitly through a non-static inner class.
*/
+@SystemApi
public class VoiceInteractor {
static final String TAG = "VoiceInteractor";
static final boolean DEBUG = true;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 69b1139..9ed8960 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -115,6 +115,18 @@ public class DevicePolicyManager {
= "android.app.action.ACTION_PROVISION_MANAGED_PROFILE";
/**
+ * A {@link Parcelable} extra of type {@link PersistableBundle} that allows a mobile device
+ * management application that starts managed profile provisioning to pass data to itself on the
+ * managed profile when provisioning completes. The mobile device management application sends
+ * this extra in an intent with the action {@link #ACTION_PROVISION_MANAGED_PROFILE} and
+ * receives it in {@link DeviceAdminReceiver#onProfileProvisioningComplete} via an intent with
+ * the action {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}. The bundle is
+ * not changed during the managed profile provisioning.
+ */
+ public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE =
+ "android.app.extra.ADMIN_EXTRA_BUNDLE";
+
+ /**
* A String extra holding the package name of the mobile device management application that
* will be set as the profile owner or device owner.
*
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 2431ad0..fb80de2 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -106,7 +106,9 @@ public final class UsageEvents implements Parcelable {
}
/**
- * The time at which this event occurred.
+ * The time at which this event occurred, measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getTimeStamp() {
return mTimeStamp;
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index e47a802..abfc435 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -81,28 +81,36 @@ public final class UsageStats implements Parcelable {
}
/**
- * Get the beginning of the time range this {@link android.app.usage.UsageStats} represents.
+ * Get the beginning of the time range this {@link android.app.usage.UsageStats} represents,
+ * measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getFirstTimeStamp() {
return mBeginTimeStamp;
}
/**
- * Get the end of the time range this {@link android.app.usage.UsageStats} represents.
+ * Get the end of the time range this {@link android.app.usage.UsageStats} represents,
+ * measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getLastTimeStamp() {
return mEndTimeStamp;
}
/**
- * Get the last time this package was used.
+ * Get the last time this package was used, measured in milliseconds since the epoch.
+ * <p/>
+ * See {@link System#currentTimeMillis()}.
*/
public long getLastTimeUsed() {
return mLastTimeUsed;
}
/**
- * Get the total time this package spent in the foreground.
+ * Get the total time this package spent in the foreground, measured in milliseconds.
*/
public long getTotalTimeInForeground() {
return mTotalTimeInForeground;
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index f9b8928..5830fcf 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -23,6 +23,7 @@ import android.util.ArrayMap;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
/**
* Provides access to device usage history and statistics. Usage data is aggregated into
@@ -149,7 +150,6 @@ public final class UsageStatsManager {
* @param endTime The exclusive end of the range of events to include in the results.
* @return A {@link UsageEvents}.
*/
- @SuppressWarnings("unchecked")
public UsageEvents queryEvents(long beginTime, long endTime) {
try {
UsageEvents iter = mService.queryEvents(beginTime, endTime,
@@ -170,15 +170,13 @@ public final class UsageStatsManager {
*
* @param beginTime The inclusive beginning of the range of stats to include in the results.
* @param endTime The exclusive end of the range of stats to include in the results.
- * @return An {@link android.util.ArrayMap} keyed by package name or null if no stats are
+ * @return A {@link java.util.Map} keyed by package name, or null if no stats are
* available.
*/
- public ArrayMap<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
+ public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
List<UsageStats> stats = queryUsageStats(INTERVAL_BEST, beginTime, endTime);
if (stats.isEmpty()) {
- @SuppressWarnings("unchecked")
- ArrayMap<String, UsageStats> emptyStats = ArrayMap.EMPTY;
- return emptyStats;
+ return Collections.emptyMap();
}
ArrayMap<String, UsageStats> aggregatedStats = new ArrayMap<>();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b7d7c25..f979a0c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1486,8 +1486,6 @@ public abstract class Context {
* @see #sendBroadcast(Intent)
* @see #sendBroadcast(Intent, String)
* @see #sendOrderedBroadcast(Intent, String)
- * @see #sendStickyBroadcast(Intent)
- * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
* @see android.content.BroadcastReceiver
* @see #registerReceiver
* @see android.app.Activity#RESULT_OK
@@ -1584,7 +1582,7 @@ public abstract class Context {
@Nullable Bundle initialExtras);
/**
- * Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
+ * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
* Intent you are sending stays around after the broadcast is complete,
* so that others can quickly retrieve that data through the return
* value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}. In
@@ -1595,6 +1593,12 @@ public abstract class Context {
* permission in order to use this API. If you do not hold that
* permission, {@link SecurityException} will be thrown.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast, and the Intent will be held to
* be re-broadcast to future receivers.
@@ -1602,10 +1606,11 @@ public abstract class Context {
* @see #sendBroadcast(Intent)
* @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
*/
+ @Deprecated
public abstract void sendStickyBroadcast(Intent intent);
/**
- * Version of {@link #sendStickyBroadcast} that allows you to
+ * <p>Version of {@link #sendStickyBroadcast} that allows you to
* receive data back from the broadcast. This is accomplished by
* supplying your own BroadcastReceiver when calling, which will be
* treated as a final receiver at the end of the broadcast -- its
@@ -1622,6 +1627,12 @@ public abstract class Context {
*
* <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast.
* @param resultReceiver Your own BroadcastReceiver to treat as the final
@@ -1644,31 +1655,45 @@ public abstract class Context {
* @see #registerReceiver
* @see android.app.Activity#RESULT_OK
*/
+ @Deprecated
public abstract void sendStickyOrderedBroadcast(Intent intent,
BroadcastReceiver resultReceiver,
@Nullable Handler scheduler, int initialCode, @Nullable String initialData,
@Nullable Bundle initialExtras);
/**
- * Remove the data previously sent with {@link #sendStickyBroadcast},
+ * <p>Remove the data previously sent with {@link #sendStickyBroadcast},
* so that it is as if the sticky broadcast had never happened.
*
* <p>You must hold the {@link android.Manifest.permission#BROADCAST_STICKY}
* permission in order to use this API. If you do not hold that
* permission, {@link SecurityException} will be thrown.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent that was previously broadcast.
*
* @see #sendStickyBroadcast
*/
+ @Deprecated
public abstract void removeStickyBroadcast(Intent intent);
/**
- * Version of {@link #sendStickyBroadcast(Intent)} that allows you to specify the
+ * <p>Version of {@link #sendStickyBroadcast(Intent)} that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
* that are not pre-installed on the system image. Using it requires holding
* the INTERACT_ACROSS_USERS permission.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast, and the Intent will be held to
* be re-broadcast to future receivers.
@@ -1676,10 +1701,11 @@ public abstract class Context {
*
* @see #sendBroadcast(Intent)
*/
+ @Deprecated
public abstract void sendStickyBroadcastAsUser(Intent intent, UserHandle user);
/**
- * Version of
+ * <p>Version of
* {@link #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)}
* that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
@@ -1688,6 +1714,12 @@ public abstract class Context {
*
* <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent to broadcast; all receivers matching this
* Intent will receive the broadcast.
* @param user UserHandle to send the intent to.
@@ -1705,13 +1737,14 @@ public abstract class Context {
*
* @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
*/
+ @Deprecated
public abstract void sendStickyOrderedBroadcastAsUser(Intent intent,
UserHandle user, BroadcastReceiver resultReceiver,
@Nullable Handler scheduler, int initialCode, @Nullable String initialData,
@Nullable Bundle initialExtras);
/**
- * Version of {@link #removeStickyBroadcast(Intent)} that allows you to specify the
+ * <p>Version of {@link #removeStickyBroadcast(Intent)} that allows you to specify the
* user the broadcast will be sent to. This is not available to applications
* that are not pre-installed on the system image. Using it requires holding
* the INTERACT_ACROSS_USERS permission.
@@ -1720,11 +1753,18 @@ public abstract class Context {
* permission in order to use this API. If you do not hold that
* permission, {@link SecurityException} will be thrown.
*
+ * @deprecated Sticky broadcasts should not be used. They provide no security (anyone
+ * can access them), no protection (anyone can modify them), and many other problems.
+ * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em>
+ * has changed, with another mechanism for apps to retrieve the current value whenever
+ * desired.
+ *
* @param intent The Intent that was previously broadcast.
* @param user UserHandle to remove the sticky broadcast from.
*
* @see #sendStickyBroadcastAsUser
*/
+ @Deprecated
public abstract void removeStickyBroadcastAsUser(Intent intent, UserHandle user);
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 61e105b..b825c94 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2216,104 +2216,14 @@ public class Intent implements Parcelable, Cloneable {
/**
* Broadcast Action: Wired Headset plugged in or unplugged.
*
- * You <em>cannot</em> receive this through components declared
- * in manifests, only by explicitly registering for it with
- * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
- * Context.registerReceiver()}.
- *
- * <p>The intent will have the following extra values:
- * <ul>
- * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
- * <li><em>name</em> - Headset type, human readable string </li>
- * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
- * </ul>
- * </ul>
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HEADSET_PLUG =
- "android.intent.action.HEADSET_PLUG";
-
- /**
- * Broadcast Action: An analog audio speaker/headset plugged in or unplugged.
- *
- * <p>The intent will have the following extra values:
- * <ul>
- * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
- * <li><em>name</em> - Headset type, human readable string </li>
- * </ul>
- * </ul>
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_ANALOG_AUDIO_DOCK_PLUG =
- "android.intent.action.ANALOG_AUDIO_DOCK_PLUG";
-
- /**
- * Broadcast Action: A digital audio speaker/headset plugged in or unplugged.
- *
- * <p>The intent will have the following extra values:
- * <ul>
- * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
- * <li><em>name</em> - Headset type, human readable string </li>
- * </ul>
- * </ul>
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_DIGITAL_AUDIO_DOCK_PLUG =
- "android.intent.action.DIGITAL_AUDIO_DOCK_PLUG";
-
- /**
- * Broadcast Action: A sticky broadcast indicating an HMDI cable was plugged or unplugged
- *
- * <p>The intent will have the following extra values:
- * <ul>
- * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
- * <li><em>name</em> - HDMI cable, human readable string </li>
- * <li><em>maxChannelCount</em> - the maximum number of output channels supported by the
- * connected HDMI device, only available when <i>state</i> is 1.</li>
- * <li><em>encodings</em> - an array of formats supported by the connected HDMI device,
- * only available when <i>state</i> is 1. Encoding values are defined in
- * {@link android.media.AudioFormat} (for instance see
- * {@link android.media.AudioFormat#ENCODING_PCM_16BIT}). Use
- * {@link #getIntArrayExtra(String)} to retrieve the encoding values.</li>
- * </ul>
+ * Same as {@link android.media.AudioManager#ACTION_HEADSET_PLUG}, to be consulted for value
+ * and documentation.
+ * <p>If the minimum SDK version of your application is
+ * {@link android.os.Build.VERSION_CODES#L}, it is recommended to refer
+ * to the <code>AudioManager</code> constant in your receiver registration code instead.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HDMI_AUDIO_PLUG =
- "android.intent.action.HDMI_AUDIO_PLUG";
-
- /**
- * Broadcast Action: A USB audio accessory was plugged in or unplugged.
- *
- * <p>The intent will have the following extra values:
- * <ul>
- * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
- * <li><em>card</em> - ALSA card number (integer) </li>
- * <li><em>device</em> - ALSA device number (integer) </li>
- * </ul>
- * </ul>
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_USB_AUDIO_ACCESSORY_PLUG =
- "android.intent.action.USB_AUDIO_ACCESSORY_PLUG";
-
- /**
- * Broadcast Action: A USB audio device was plugged in or unplugged.
- *
- * <p>The intent will have the following extra values:
- * <ul>
- * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
- * <li><em>card</em> - ALSA card number (integer) </li>
- * <li><em>device</em> - ALSA device number (integer) </li>
- * </ul>
- * </ul>
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_USB_AUDIO_DEVICE_PLUG =
- "android.intent.action.USB_AUDIO_DEVICE_PLUG";
+ public static final String ACTION_HEADSET_PLUG = android.media.AudioManager.ACTION_HEADSET_PLUG;
/**
* <p>Broadcast Action: The user has switched on advanced settings in the settings app:</p>
@@ -2833,12 +2743,14 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE";
/**
+ * @hide
* Categories for activities that can participate in voice interaction.
* An activity that supports this category must be prepared to run with
* no UI shown at all (though in some case it may have a UI shown), and
* rely on {@link android.app.VoiceInteractor} to interact with the user.
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ @SystemApi
public static final String CATEGORY_VOICE = "android.intent.category.VOICE";
/**
* Set if the activity should be considered as an alternative action to
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 44478d4..3e1f60a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -32,6 +32,7 @@ import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
+import android.content.pm.KeySet;
import android.content.pm.PackageInfo;
import android.content.pm.ManifestDigest;
import android.content.pm.PackageCleanItem;
@@ -198,6 +199,14 @@ interface IPackageManager {
in VerificationParams verificationParams,
in String packageAbiOverride);
+ void installPackageAsUser(in String originPath,
+ in IPackageInstallObserver2 observer,
+ int flags,
+ in String installerPackageName,
+ in VerificationParams verificationParams,
+ in String packageAbiOverride,
+ int userId);
+
void finishPackageInstall(int token);
void setInstallerPackageName(in String targetPackage, in String installerPackageName);
@@ -446,8 +455,8 @@ interface IPackageManager {
boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId);
boolean getBlockUninstallForUser(String packageName, int userId);
- IBinder getKeySetByAlias(String packageName, String alias);
- IBinder getSigningKeySet(String packageName);
- boolean isPackageSignedByKeySet(String packageName, IBinder ks);
- boolean isPackageSignedByKeySetExactly(String packageName, IBinder ks);
+ KeySet getKeySetByAlias(String packageName, String alias);
+ KeySet getSigningKeySet(String packageName);
+ boolean isPackageSignedByKeySet(String packageName, in KeySet ks);
+ boolean isPackageSignedByKeySetExactly(String packageName, in KeySet ks);
}
diff --git a/core/java/android/content/pm/KeySet.aidl b/core/java/android/content/pm/KeySet.aidl
new file mode 100644
index 0000000..493d288
--- /dev/null
+++ b/core/java/android/content/pm/KeySet.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.content.pm;
+
+parcelable KeySet; \ No newline at end of file
diff --git a/core/java/android/content/pm/KeySet.java b/core/java/android/content/pm/KeySet.java
index fcdaa18..643db7e 100644
--- a/core/java/android/content/pm/KeySet.java
+++ b/core/java/android/content/pm/KeySet.java
@@ -17,13 +17,16 @@
package android.content.pm;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
/**
* Represents a {@code KeySet} that has been declared in the AndroidManifest.xml
* file for the application. A {@code KeySet} can be used explicitly to
* represent a trust relationship with other applications on the device.
+ * @hide
*/
-public class KeySet {
+public class KeySet implements Parcelable {
private IBinder token;
@@ -40,6 +43,7 @@ public class KeySet {
return token;
}
+ /** @hide */
@Override
public boolean equals(Object o) {
if (o instanceof KeySet) {
@@ -48,4 +52,58 @@ public class KeySet {
}
return false;
}
+
+ /** @hide */
+ @Override
+ public int hashCode() {
+ return token.hashCode();
+ }
+
+ /**
+ * Implement Parcelable
+ * @hide
+ */
+ public static final Parcelable.Creator<KeySet> CREATOR
+ = new Parcelable.Creator<KeySet>() {
+
+ /**
+ * Create a KeySet from a Parcel
+ *
+ * @param in The parcel containing the KeySet
+ */
+ public KeySet createFromParcel(Parcel source) {
+ return readFromParcel(source);
+ }
+
+ /**
+ * Create an array of null KeySets
+ */
+ public KeySet[] newArray(int size) {
+ return new KeySet[size];
+ }
+ };
+
+ /**
+ * @hide
+ */
+ private static KeySet readFromParcel(Parcel in) {
+ IBinder token = in.readStrongBinder();
+ return new KeySet(token);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeStrongBinder(token);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
} \ No newline at end of file
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fa2bb4d..1b15ff5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3698,10 +3698,13 @@ public abstract class PackageManager {
*
* @param alias The alias for a given {@link KeySet} as defined in the
* application's AndroidManifest.xml.
+ * @hide
*/
public abstract KeySet getKeySetByAlias(String packageName, String alias);
- /** Return the signing {@link KeySet} for this application. */
+ /** Return the signing {@link KeySet} for this application.
+ * @hide
+ */
public abstract KeySet getSigningKeySet(String packageName);
/**
@@ -3709,6 +3712,7 @@ public abstract class PackageManager {
* of the keys specified by the {@link KeySet} ks. This will return true if
* the package has been signed by additional keys (a superset) as well.
* Compare to {@link #isSignedByExactly(String packageName, KeySet ks)}.
+ * @hide
*/
public abstract boolean isSignedBy(String packageName, KeySet ks);
@@ -3716,6 +3720,7 @@ public abstract class PackageManager {
* Return whether the package denoted by packageName has been signed by all
* of, and only, the keys specified by the {@link KeySet} ks. Compare to
* {@link #isSignedBy(String packageName, KeySet ks)}.
+ * @hide
*/
public abstract boolean isSignedByExactly(String packageName, KeySet ks);
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 3c9b7b3..a57b361 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1575,6 +1575,13 @@ public abstract class CameraMetadata<TKey> {
*/
public static final int CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO = 17;
+ /**
+ * <p>Turn on custom high dynamic range (HDR) mode.</p>
+ * @see CaptureRequest#CONTROL_SCENE_MODE
+ * @hide
+ */
+ public static final int CONTROL_SCENE_MODE_HDR = 18;
+
//
// Enumeration values for CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
//
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index ee0ca9c..a8d1018 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -882,6 +882,7 @@ public class LegacyMetadataMapper {
Parameters.SCENE_MODE_PARTY,
Parameters.SCENE_MODE_CANDLELIGHT,
Parameters.SCENE_MODE_BARCODE,
+ Parameters.SCENE_MODE_HDR,
};
private final static int[] sSceneModes = {
@@ -901,6 +902,7 @@ public class LegacyMetadataMapper {
CameraCharacteristics.CONTROL_SCENE_MODE_PARTY,
CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT,
CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE,
+ CameraCharacteristics.CONTROL_SCENE_MODE_HDR,
};
static int convertSceneModeFromLegacy(String mode) {
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 51b7229..b077e06 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -472,7 +472,7 @@ public final class DisplayManager {
/**
* Creates a virtual display.
*
- * @see #createVirtualDisplay(String, int, int, int, Surface, int, VirtualDisplay.Callbacks)
+ * @see #createVirtualDisplay(String, int, int, int, Surface, int, VirtualDisplay.Callback)
*/
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags) {
@@ -513,7 +513,7 @@ public final class DisplayManager {
* {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION},
* {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
* or {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
- * @param callbacks Callbacks to call when the state of the {@link VirtualDisplay} changes
+ * @param callback Callback to call when the state of the {@link VirtualDisplay} changes
* @param handler The handler on which the listener should be invoked, or null
* if the listener should be invoked on the calling thread's looper.
* @return The newly created virtual display, or null if the application could
@@ -524,17 +524,17 @@ public final class DisplayManager {
*/
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags,
- @Nullable VirtualDisplay.Callbacks callbacks, @Nullable Handler handler) {
+ @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
return createVirtualDisplay(null,
- name, width, height, densityDpi, surface, flags, callbacks, handler);
+ name, width, height, densityDpi, surface, flags, callback, handler);
}
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
@NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface,
- int flags, @Nullable VirtualDisplay.Callbacks callbacks, @Nullable Handler handler) {
+ int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
return mGlobal.createVirtualDisplay(mContext, projection,
- name, width, height, densityDpi, surface, flags, callbacks, handler);
+ name, width, height, densityDpi, surface, flags, callback, handler);
}
/**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 8b44f3b..0051ef5 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -372,7 +372,7 @@ public final class DisplayManagerGlobal {
public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
String name, int width, int height, int densityDpi, Surface surface, int flags,
- VirtualDisplay.Callbacks callbacks, Handler handler) {
+ VirtualDisplay.Callback callback, Handler handler) {
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("name must be non-null and non-empty");
}
@@ -381,7 +381,7 @@ public final class DisplayManagerGlobal {
+ "greater than 0");
}
- VirtualDisplayCallbacks callbackWrapper = new VirtualDisplayCallbacks(callbacks, handler);
+ VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
int displayId;
try {
@@ -408,7 +408,7 @@ public final class DisplayManagerGlobal {
return new VirtualDisplay(this, display, callbackWrapper, surface);
}
- public void setVirtualDisplaySurface(IVirtualDisplayCallbacks token, Surface surface) {
+ public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
try {
mDm.setVirtualDisplaySurface(token, surface);
} catch (RemoteException ex) {
@@ -416,7 +416,7 @@ public final class DisplayManagerGlobal {
}
}
- public void resizeVirtualDisplay(IVirtualDisplayCallbacks token,
+ public void resizeVirtualDisplay(IVirtualDisplayCallback token,
int width, int height, int densityDpi) {
try {
mDm.resizeVirtualDisplay(token, width, height, densityDpi);
@@ -425,7 +425,7 @@ public final class DisplayManagerGlobal {
}
}
- public void releaseVirtualDisplay(IVirtualDisplayCallbacks token) {
+ public void releaseVirtualDisplay(IVirtualDisplayCallback token) {
try {
mDm.releaseVirtualDisplay(token);
} catch (RemoteException ex) {
@@ -476,61 +476,61 @@ public final class DisplayManagerGlobal {
}
}
- private final static class VirtualDisplayCallbacks extends IVirtualDisplayCallbacks.Stub {
- private VirtualDisplayCallbacksDelegate mDelegate;
+ private final static class VirtualDisplayCallback extends IVirtualDisplayCallback.Stub {
+ private VirtualDisplayCallbackDelegate mDelegate;
- public VirtualDisplayCallbacks(VirtualDisplay.Callbacks callbacks, Handler handler) {
- if (callbacks != null) {
- mDelegate = new VirtualDisplayCallbacksDelegate(callbacks, handler);
+ public VirtualDisplayCallback(VirtualDisplay.Callback callback, Handler handler) {
+ if (callback != null) {
+ mDelegate = new VirtualDisplayCallbackDelegate(callback, handler);
}
}
@Override // Binder call
- public void onDisplayPaused() {
+ public void onPaused() {
if (mDelegate != null) {
- mDelegate.sendEmptyMessage(VirtualDisplayCallbacksDelegate.MSG_DISPLAY_PAUSED);
+ mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_PAUSED);
}
}
@Override // Binder call
- public void onDisplayResumed() {
+ public void onResumed() {
if (mDelegate != null) {
- mDelegate.sendEmptyMessage(VirtualDisplayCallbacksDelegate.MSG_DISPLAY_RESUMED);
+ mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_RESUMED);
}
}
@Override // Binder call
- public void onDisplayStopped() {
+ public void onStopped() {
if (mDelegate != null) {
- mDelegate.sendEmptyMessage(VirtualDisplayCallbacksDelegate.MSG_DISPLAY_STOPPED);
+ mDelegate.sendEmptyMessage(VirtualDisplayCallbackDelegate.MSG_DISPLAY_STOPPED);
}
}
}
- private final static class VirtualDisplayCallbacksDelegate extends Handler {
+ private final static class VirtualDisplayCallbackDelegate extends Handler {
public static final int MSG_DISPLAY_PAUSED = 0;
public static final int MSG_DISPLAY_RESUMED = 1;
public static final int MSG_DISPLAY_STOPPED = 2;
- private final VirtualDisplay.Callbacks mCallbacks;
+ private final VirtualDisplay.Callback mCallback;
- public VirtualDisplayCallbacksDelegate(VirtualDisplay.Callbacks callbacks,
+ public VirtualDisplayCallbackDelegate(VirtualDisplay.Callback callback,
Handler handler) {
super(handler != null ? handler.getLooper() : Looper.myLooper(), null, true /*async*/);
- mCallbacks = callbacks;
+ mCallback = callback;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DISPLAY_PAUSED:
- mCallbacks.onDisplayPaused();
+ mCallback.onPaused();
break;
case MSG_DISPLAY_RESUMED:
- mCallbacks.onDisplayResumed();
+ mCallback.onResumed();
break;
case MSG_DISPLAY_STOPPED:
- mCallbacks.onDisplayStopped();
+ mCallback.onStopped();
break;
}
}
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index cfaa5a0..4486dd4 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -17,7 +17,7 @@
package android.hardware.display;
import android.hardware.display.IDisplayManagerCallback;
-import android.hardware.display.IVirtualDisplayCallbacks;
+import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.WifiDisplay;
import android.hardware.display.WifiDisplayStatus;
import android.media.projection.IMediaProjection;
@@ -61,17 +61,17 @@ interface IDisplayManager {
// Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
// MediaProjection token for certain combinations of flags.
- int createVirtualDisplay(in IVirtualDisplayCallbacks callbacks,
+ int createVirtualDisplay(in IVirtualDisplayCallback callback,
in IMediaProjection projectionToken, String packageName, String name,
int width, int height, int densityDpi, in Surface surface, int flags);
// No permissions required, but must be same Uid as the creator.
- void resizeVirtualDisplay(in IVirtualDisplayCallbacks token,
+ void resizeVirtualDisplay(in IVirtualDisplayCallback token,
int width, int height, int densityDpi);
// No permissions required but must be same Uid as the creator.
- void setVirtualDisplaySurface(in IVirtualDisplayCallbacks token, in Surface surface);
+ void setVirtualDisplaySurface(in IVirtualDisplayCallback token, in Surface surface);
// No permissions required but must be same Uid as the creator.
- void releaseVirtualDisplay(in IVirtualDisplayCallbacks token);
+ void releaseVirtualDisplay(in IVirtualDisplayCallback token);
}
diff --git a/core/java/android/hardware/display/IVirtualDisplayCallbacks.aidl b/core/java/android/hardware/display/IVirtualDisplayCallback.aidl
index a1cdc01..c3490d1 100644
--- a/core/java/android/hardware/display/IVirtualDisplayCallbacks.aidl
+++ b/core/java/android/hardware/display/IVirtualDisplayCallback.aidl
@@ -16,20 +16,20 @@
package android.hardware.display;
/** @hide */
-oneway interface IVirtualDisplayCallbacks {
+oneway interface IVirtualDisplayCallback {
/**
* Called when the virtual display video projection has been
* paused by the system or when the surface has been detached
* by the application by calling setSurface(null).
* The surface will not receive any more buffers while paused.
*/
- void onDisplayPaused();
+ void onPaused();
/**
* Called when the virtual display video projection has been
* resumed after having been paused.
*/
- void onDisplayResumed();
+ void onResumed();
/**
* Called when the virtual display video projection has been
@@ -37,5 +37,5 @@ oneway interface IVirtualDisplayCallbacks {
* and it will never be resumed. It is still the responsibility
* of the application to release() the virtual display.
*/
- void onDisplayStopped();
+ void onStopped();
}
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index 1dd6978..4ddf10f 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -35,11 +35,11 @@ import android.view.Surface;
public final class VirtualDisplay {
private final DisplayManagerGlobal mGlobal;
private final Display mDisplay;
- private IVirtualDisplayCallbacks mToken;
+ private IVirtualDisplayCallback mToken;
private Surface mSurface;
VirtualDisplay(DisplayManagerGlobal global, Display display,
- IVirtualDisplayCallbacks token, Surface surface) {
+ IVirtualDisplayCallback token, Surface surface) {
mGlobal = global;
mDisplay = display;
mToken = token;
@@ -114,20 +114,20 @@ public final class VirtualDisplay {
/**
* Interface for receiving information about a {@link VirtualDisplay}'s state changes.
*/
- public static abstract class Callbacks {
+ public static abstract class Callback {
/**
* Called when the virtual display video projection has been
* paused by the system or when the surface has been detached
* by the application by calling setSurface(null).
* The surface will not receive any more buffers while paused.
*/
- public void onDisplayPaused() { }
+ public void onPaused() { }
/**
* Called when the virtual display video projection has been
* resumed after having been paused.
*/
- public void onDisplayResumed() { }
+ public void onResumed() { }
/**
* Called when the virtual display video projection has been
@@ -135,6 +135,6 @@ public final class VirtualDisplay {
* and it will never be resumed. It is still the responsibility
* of the application to release() the virtual display.
*/
- public void onDisplayStopped() { }
+ public void onStopped() { }
}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4bfef41..3c219fd 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -685,6 +685,23 @@ public class ConnectivityManager {
}
/**
+ * Returns the {@link Network} object currently serving a given type, or
+ * null if the given type is not connected.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ *
+ * @hide
+ */
+ public Network getNetworkForType(int networkType) {
+ try {
+ return mService.getNetworkForType(networkType);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* Returns an array of all {@link Network} currently tracked by the
* framework.
*
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b2fc3be..974c4cd 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -48,6 +48,7 @@ interface IConnectivityManager
NetworkInfo getNetworkInfo(int networkType);
NetworkInfo getNetworkInfoForNetwork(in Network network);
NetworkInfo[] getAllNetworkInfo();
+ Network getNetworkForType(int networkType);
Network[] getAllNetworks();
NetworkInfo getProvisioningOrActiveNetworkInfo();
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index d2a4728..e686be7 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -35,6 +35,7 @@ import java.net.URLStreamHandler;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.SocketFactory;
+import com.android.okhttp.ConnectionPool;
import com.android.okhttp.HostResolver;
import com.android.okhttp.OkHttpClient;
@@ -60,6 +61,17 @@ public class Network implements Parcelable {
private volatile OkHttpClient mOkHttpClient = null;
private Object mLock = new Object();
+ // Default connection pool values. These are evaluated at startup, just
+ // like the OkHttp code. Also like the OkHttp code, we will throw parse
+ // exceptions at class loading time if the properties are set but are not
+ // valid integers.
+ private static final boolean httpKeepAlive =
+ Boolean.parseBoolean(System.getProperty("http.keepAlive", "true"));
+ private static final int httpMaxConnections =
+ httpKeepAlive ? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0;
+ private static final long httpKeepAliveDurationMs =
+ Long.parseLong(System.getProperty("http.keepAliveDuration", "300000")); // 5 minutes.
+
/**
* @hide
*/
@@ -183,6 +195,20 @@ public class Network implements Parcelable {
return mNetworkBoundSocketFactory;
}
+ // TODO: This creates an OkHttpClient with its own connection pool for
+ // every Network object, instead of one for every NetId. This is
+ // suboptimal, because an app could potentially have more than one
+ // Network object for the same NetId, causing increased memory footprint
+ // and performance penalties due to lack of connection reuse (connection
+ // setup time, congestion window growth time, etc.).
+ //
+ // Instead, investigate only having one OkHttpClient for every NetId,
+ // perhaps by using a static HashMap of NetIds to OkHttpClient objects. The
+ // tricky part is deciding when to remove an OkHttpClient; a WeakHashMap
+ // shouldn't be used because whether a Network is referenced doesn't
+ // correlate with whether a new Network will be instantiated in the near
+ // future with the same NetID. A good solution would involve purging empty
+ // (or when all connections are timed out) ConnectionPools.
private void maybeInitHttpClient() {
if (mOkHttpClient == null) {
synchronized (mLock) {
@@ -193,9 +219,12 @@ public class Network implements Parcelable {
return Network.this.getAllByName(host);
}
};
+ ConnectionPool pool = new ConnectionPool(httpMaxConnections,
+ httpKeepAliveDurationMs);
mOkHttpClient = new OkHttpClient()
.setSocketFactory(getSocketFactory())
- .setHostResolver(hostResolver);
+ .setHostResolver(hostResolver)
+ .setConnectionPool(pool);
}
}
}
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index d279412..7664c95 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -128,14 +128,6 @@ public class NetworkInfo implements Parcelable {
private boolean mIsAvailable;
/**
- * @param type network type
- * @deprecated
- * @hide because this constructor was only meant for internal use (and
- * has now been superseded by the package-private constructor below).
- */
- public NetworkInfo(int type) {}
-
- /**
* @hide
*/
public NetworkInfo(int type, int subtype, String typeName, String subtypeName) {
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 6d4a302..b3e28ea 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -19,6 +19,7 @@ package android.os;
import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
+import android.net.Network;
import android.net.NetworkStats;
import android.net.RouteInfo;
import android.net.UidRange;
@@ -164,10 +165,10 @@ interface INetworkManagementService
/**
* Sets the list of DNS forwarders (in order of priority)
*/
- void setDnsForwarders(in String[] dns);
+ void setDnsForwarders(in Network network, in String[] dns);
/**
- * Returns the list of DNS fowarders (in order of priority)
+ * Returns the list of DNS forwarders (in order of priority)
*/
String[] getDnsForwarders();
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 713fcd8..3286627 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -52,4 +52,5 @@ interface IUserManager {
void removeRestrictions();
void setDefaultGuestRestrictions(in Bundle restrictions);
Bundle getDefaultGuestRestrictions();
+ boolean markGuestForDeletion(int userHandle);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index e215669..f793667 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -676,6 +676,22 @@ public class UserManager {
}
/**
+ * @hide
+ * Marks the guest user for deletion to allow a new guest to be created before deleting
+ * the current user who is a guest.
+ * @param userHandle
+ * @return
+ */
+ public boolean markGuestForDeletion(int userHandle) {
+ try {
+ return mService.markGuestForDeletion(userHandle);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not mark guest for deletion", re);
+ return false;
+ }
+ }
+
+ /**
* Sets the user as enabled, if such an user exists.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* Note that the default is true, it's only that managed profiles might not be enabled.
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index d1fadd6..cf407f4 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -1518,10 +1518,14 @@ public interface IMountService extends IInterface {
static final int ENCRYPTION_STATE_NONE = 1;
/** The volume has been encrypted succesfully. */
static final int ENCRYPTION_STATE_OK = 0;
- /** The volume is in a bad state. */
+ /** The volume is in a bad state.*/
static final int ENCRYPTION_STATE_ERROR_UNKNOWN = -1;
- /** The volume is in a bad state - partially encrypted. Data is likely irrecoverable. */
+ /** Encryption is incomplete */
static final int ENCRYPTION_STATE_ERROR_INCOMPLETE = -2;
+ /** Encryption is incomplete and irrecoverable */
+ static final int ENCRYPTION_STATE_ERROR_INCONSISTENT = -3;
+ /** Underlying data is corrupt */
+ static final int ENCRYPTION_STATE_ERROR_CORRUPT = -4;
/**
* Determines the encryption state of the volume.
diff --git a/core/java/android/preference/CheckBoxPreference.java b/core/java/android/preference/CheckBoxPreference.java
index 1ce98b8..fee3f0f 100644
--- a/core/java/android/preference/CheckBoxPreference.java
+++ b/core/java/android/preference/CheckBoxPreference.java
@@ -66,7 +66,6 @@ public class CheckBoxPreference extends TwoStatePreference {
View checkboxView = view.findViewById(com.android.internal.R.id.checkbox);
if (checkboxView != null && checkboxView instanceof Checkable) {
((Checkable) checkboxView).setChecked(mChecked);
- sendAccessibilityEvent(checkboxView);
}
syncSummaryView(view);
diff --git a/core/java/android/preference/SwitchPreference.java b/core/java/android/preference/SwitchPreference.java
index 46be928..53b5aad 100644
--- a/core/java/android/preference/SwitchPreference.java
+++ b/core/java/android/preference/SwitchPreference.java
@@ -130,8 +130,6 @@ public class SwitchPreference extends TwoStatePreference {
((Checkable) checkableView).setChecked(mChecked);
- sendAccessibilityEvent(checkableView);
-
if (checkableView instanceof Switch) {
final Switch switchView = (Switch) checkableView;
switchView.setTextOn(mSwitchOn);
diff --git a/core/java/android/preference/TwoStatePreference.java b/core/java/android/preference/TwoStatePreference.java
index 6f8be1f..3823b27 100644
--- a/core/java/android/preference/TwoStatePreference.java
+++ b/core/java/android/preference/TwoStatePreference.java
@@ -24,8 +24,6 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
import android.widget.TextView;
/**
@@ -39,7 +37,6 @@ public abstract class TwoStatePreference extends Preference {
private CharSequence mSummaryOff;
boolean mChecked;
private boolean mCheckedSet;
- private boolean mSendClickAccessibilityEvent;
private boolean mDisableDependentsState;
public TwoStatePreference(
@@ -63,15 +60,10 @@ public abstract class TwoStatePreference extends Preference {
protected void onClick() {
super.onClick();
- boolean newValue = !isChecked();
-
- mSendClickAccessibilityEvent = true;
-
- if (!callChangeListener(newValue)) {
- return;
+ final boolean newValue = !isChecked();
+ if (callChangeListener(newValue)) {
+ setChecked(newValue);
}
-
- setChecked(newValue);
}
/**
@@ -196,21 +188,6 @@ public abstract class TwoStatePreference extends Preference {
: (Boolean) defaultValue);
}
- void sendAccessibilityEvent(View view) {
- // Since the view is still not attached we create, populate,
- // and send the event directly since we do not know when it
- // will be attached and posting commands is not as clean.
- AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getContext());
- if (mSendClickAccessibilityEvent && accessibilityManager.isEnabled()) {
- AccessibilityEvent event = AccessibilityEvent.obtain();
- event.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED);
- view.onInitializeAccessibilityEvent(event);
- view.dispatchPopulateAccessibilityEvent(event);
- accessibilityManager.sendAccessibilityEvent(event);
- }
- mSendClickAccessibilityEvent = false;
- }
-
/**
* Sync a summary view contained within view's subhierarchy with the correct summary text.
* @param view View where a summary should be located
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ae11f47..f4c2dc8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -18,6 +18,7 @@ package android.provider;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.app.SearchManager;
import android.app.WallpaperManager;
import android.content.ComponentName;
@@ -131,6 +132,7 @@ public final class Settings {
"android.settings.AIRPLANE_MODE_SETTINGS";
/**
+ * @hide
* Activity Action: Modify Airplane mode settings using the users voice.
* <p>
* In some cases, a matching Activity may not exist, so ensure you safeguard against this.
@@ -152,6 +154,7 @@ public final class Settings {
* Output: Nothing.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ @SystemApi
public static final String ACTION_VOICE_CONTROL_AIRPLANE_MODE =
"android.settings.VOICE_CONTROL_AIRPLANE_MODE";
@@ -904,6 +907,15 @@ public final class Settings {
public static final String ACTION_APP_NOTIFICATION_SETTINGS
= "android.settings.APP_NOTIFICATION_SETTINGS";
+ /**
+ * Activity Action: Show notification redaction settings.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_APP_NOTIFICATION_REDACTION
+ = "android.settings.ACTION_APP_NOTIFICATION_REDACTION";
+
/** @hide */ public static final String EXTRA_APP_UID = "app_uid";
/** @hide */ public static final String EXTRA_APP_PACKAGE = "app_package";
@@ -966,11 +978,13 @@ public final class Settings {
public static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
/**
+ * @hide
* Activity Extra: Enable or disable Airplane Mode.
* <p>
* This can be passed as an extra field to the {@link #ACTION_VOICE_CONTROL_AIRPLANE_MODE}
* intent as a boolean.
*/
+ @SystemApi
public static final String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
private static final String JID_RESOURCE_PREFIX = "android";
@@ -2552,7 +2566,6 @@ public final class Settings {
* Call Preference String.
* "SIP_ALWAYS" : Always use SIP with network access
* "SIP_ADDRESS_ONLY" : Only if destination is a SIP address
- * "SIP_ASK_ME_EACH_TIME" : Always ask me each time
* @hide
*/
public static final String SIP_CALL_OPTIONS = "sip_call_options";
@@ -2570,9 +2583,13 @@ public final class Settings {
public static final String SIP_ADDRESS_ONLY = "SIP_ADDRESS_ONLY";
/**
- * One of the sip call options: Always ask me each time.
+ * @deprecated Use SIP_ALWAYS or SIP_ADDRESS_ONLY instead. Formerly used to indicate that
+ * the user should be prompted each time a call is made whether it should be placed using
+ * SIP. The {@link com.android.providers.settings.DatabaseHelper} replaces this with
+ * SIP_ADDRESS_ONLY.
* @hide
*/
+ @Deprecated
public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME";
/**
@@ -3714,6 +3731,14 @@ public final class Settings {
"lock_screen_allow_private_notifications";
/**
+ * Set by the system to track if the user needs to see the call to action for
+ * the lockscreen notification policy.
+ * @hide
+ */
+ public static final String SHOW_NOTE_ABOUT_NOTIFICATION_HIDING =
+ "show_note_about_notification_hiding";
+
+ /**
* The Logging ID (a unique 64-bit value) as a hex string.
* Used as a pseudonymous identifier for logging.
* @deprecated This identifier is poorly initialized and has
diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
index f8bf45b..7e9aba0 100644
--- a/core/java/android/security/IKeystoreService.java
+++ b/core/java/android/security/IKeystoreService.java
@@ -478,6 +478,59 @@ public interface IKeystoreService extends IInterface {
}
return _result;
}
+
+ public int reset_uid(int uid) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(uid);
+ mRemote.transact(Stub.TRANSACTION_reset_uid, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
+ public int sync_uid(int srcUid, int dstUid) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(srcUid);
+ _data.writeInt(dstUid);
+ mRemote.transact(Stub.TRANSACTION_sync_uid, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
+ public int password_uid(String password, int uid) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeString(password);
+ _data.writeInt(uid);
+ mRemote.transact(Stub.TRANSACTION_password_uid, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
}
private static final String DESCRIPTOR = "android.security.keystore";
@@ -505,6 +558,9 @@ public interface IKeystoreService extends IInterface {
static final int TRANSACTION_duplicate = IBinder.FIRST_CALL_TRANSACTION + 20;
static final int TRANSACTION_is_hardware_backed = IBinder.FIRST_CALL_TRANSACTION + 21;
static final int TRANSACTION_clear_uid = IBinder.FIRST_CALL_TRANSACTION + 22;
+ static final int TRANSACTION_reset_uid = IBinder.FIRST_CALL_TRANSACTION + 23;
+ static final int TRANSACTION_sync_uid = IBinder.FIRST_CALL_TRANSACTION + 24;
+ static final int TRANSACTION_password_uid = IBinder.FIRST_CALL_TRANSACTION + 25;
/**
* Cast an IBinder object into an IKeystoreService interface, generating
@@ -597,4 +653,10 @@ public interface IKeystoreService extends IInterface {
public int is_hardware_backed(String string) throws RemoteException;
public int clear_uid(long uid) throws RemoteException;
+
+ public int reset_uid(int uid) throws RemoteException;
+
+ public int sync_uid(int sourceUid, int targetUid) throws RemoteException;
+
+ public int password_uid(String password, int uid) throws RemoteException;
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index a544b2d..fc12101 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -81,6 +81,34 @@ public abstract class NotificationListenerService extends Service {
* This does not change the interruption filter, only the effects. **/
public static final int HINT_HOST_DISABLE_EFFECTS = 1;
+ /**
+ * The full trim of the StatusBarNotification including all its features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int TRIM_FULL = 0;
+
+ /**
+ * A light trim of the StatusBarNotification excluding the following features:
+ *
+ * <ol>
+ * <li>{@link Notification#tickerView tickerView}</li>
+ * <li>{@link Notification#contentView contentView}</li>
+ * <li>{@link Notification#largeIcon largeIcon}</li>
+ * <li>{@link Notification#bigContentView bigContentView}</li>
+ * <li>{@link Notification#headsUpContentView headsUpContentView}</li>
+ * <li>{@link Notification#EXTRA_LARGE_ICON extras[EXTRA_LARGE_ICON]}</li>
+ * <li>{@link Notification#EXTRA_LARGE_ICON_BIG extras[EXTRA_LARGE_ICON_BIG]}</li>
+ * <li>{@link Notification#EXTRA_PICTURE extras[EXTRA_PICTURE]}</li>
+ * <li>{@link Notification#EXTRA_BIG_TEXT extras[EXTRA_BIG_TEXT]}</li>
+ * </ol>
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int TRIM_LIGHT = 1;
+
private INotificationListenerWrapper mWrapper = null;
private RankingMap mRankingMap;
@@ -314,13 +342,53 @@ public abstract class NotificationListenerService extends Service {
}
/**
+ * Sets the notification trim that will be received via {@link #onNotificationPosted}.
+ *
+ * <p>
+ * Setting a trim other than {@link #TRIM_FULL} enables listeners that don't need access to the
+ * full notification features right away to reduce their memory footprint. Full notifications
+ * can be requested on-demand via {@link #getActiveNotifications(int)}.
+ *
+ * <p>
+ * Set to {@link #TRIM_FULL} initially.
+ *
+ * @hide
+ *
+ * @param trim trim of the notifications to be passed via {@link #onNotificationPosted}.
+ * See <code>TRIM_*</code> constants.
+ */
+ @SystemApi
+ public final void setOnNotificationPostedTrim(int trim) {
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().setOnNotificationPostedTrimFromListener(mWrapper, trim);
+ } catch (RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ /**
* Request the list of outstanding notifications (that is, those that are visible to the
* current user). Useful when you don't know what's already been posted.
*
* @return An array of active notifications, sorted in natural order.
*/
public StatusBarNotification[] getActiveNotifications() {
- return getActiveNotifications(null);
+ return getActiveNotifications(null, TRIM_FULL);
+ }
+
+ /**
+ * Request the list of outstanding notifications (that is, those that are visible to the
+ * current user). Useful when you don't know what's already been posted.
+ *
+ * @hide
+ *
+ * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
+ * @return An array of active notifications, sorted in natural order.
+ */
+ @SystemApi
+ public StatusBarNotification[] getActiveNotifications(int trim) {
+ return getActiveNotifications(null, trim);
}
/**
@@ -328,14 +396,33 @@ public abstract class NotificationListenerService extends Service {
* notifications but didn't want to retain the bits, and now need to go back and extract
* more data out of those notifications.
*
+ * @param keys the keys of the notifications to request
* @return An array of notifications corresponding to the requested keys, in the
* same order as the key list.
*/
public StatusBarNotification[] getActiveNotifications(String[] keys) {
- if (!isBound()) return null;
+ return getActiveNotifications(keys, TRIM_FULL);
+ }
+
+ /**
+ * Request one or more notifications by key. Useful if you have been keeping track of
+ * notifications but didn't want to retain the bits, and now need to go back and extract
+ * more data out of those notifications.
+ *
+ * @hide
+ *
+ * @param keys the keys of the notifications to request
+ * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
+ * @return An array of notifications corresponding to the requested keys, in the
+ * same order as the key list.
+ */
+ @SystemApi
+ public StatusBarNotification[] getActiveNotifications(String[] keys, int trim) {
+ if (!isBound())
+ return null;
try {
- ParceledListSlice<StatusBarNotification> parceledList =
- getNotificationInterface().getActiveNotificationsFromListener(mWrapper, keys);
+ ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface()
+ .getActiveNotificationsFromListener(mWrapper, keys, trim);
List<StatusBarNotification> list = parceledList.getList();
int N = list.size();
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 65e6988..0cde4f2 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -40,16 +40,15 @@ import java.util.Locale;
/**
* Top-level service of the current global voice interactor, which is providing
- * support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc.
+ * support for hotwording etc.
* The current VoiceInteractionService that has been selected by the user is kept
* always running by the system, to allow it to do things like listen for hotwords
- * in the background to instigate voice interactions.
+ * in the background.
*
* <p>Because this service is always running, it should be kept as lightweight as
* possible. Heavy-weight operations (including showing UI) should be implemented
- * in the associated {@link android.service.voice.VoiceInteractionSessionService} when
- * an actual voice interaction is taking place, and that service should run in a
- * separate process from this one.
+ * in the associated {@link android.service.voice.VoiceInteractionSessionService}
+ * that only runs while the operation is active.
*/
public class VoiceInteractionService extends Service {
/**
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 19d14bf..749f813 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -16,6 +16,7 @@
package android.service.voice;
+import android.annotation.SystemApi;
import android.app.Dialog;
import android.app.Instrumentation;
import android.content.Context;
@@ -53,15 +54,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
/**
- * An active voice interaction session, providing a facility for the implementation
- * to interact with the user in the voice interaction layer. This interface is no shown
- * by default, but you can request that it be shown with {@link #showWindow()}, which
- * will result in a later call to {@link #onCreateContentView()} in which the UI can be
- * built
- *
- * <p>A voice interaction session can be self-contained, ultimately calling {@link #finish}
- * when done. It can also initiate voice interactions with applications by calling
- * {@link #startVoiceActivity}</p>.
+ * An active interaction session, started by a {@link VoiceInteractionService}.
*/
public abstract class VoiceInteractionSession implements KeyEvent.Callback {
static final String TAG = "VoiceInteractionSession";
@@ -175,6 +168,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
};
+ /**
+ * @hide
+ */
+ @SystemApi
public static class Request {
final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() {
@Override
@@ -258,6 +255,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
}
+ /**
+ * @hide
+ */
+ @SystemApi
public static class Caller {
final String packageName;
final int uid;
@@ -353,8 +354,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
final MyCallbacks mCallbacks = new MyCallbacks();
/**
+ * @hide
* Information about where interesting parts of the input method UI appear.
*/
+ @SystemApi
public static final class Insets {
/**
* This is the part of the UI that is the main content. It is
@@ -474,6 +477,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
}
+ /**
+ * @hide
+ */
+ @SystemApi
public void showWindow() {
if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
+ " mWindowVisible=" + mWindowVisible);
@@ -502,6 +509,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
}
+ /**
+ * @hide
+ */
+ @SystemApi
public void hideWindow() {
if (mWindowVisible) {
mWindow.hide();
@@ -510,11 +521,13 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * @hide
* You can call this to customize the theme used by your IME's window.
* This must be set before {@link #onCreate}, so you
* will typically call it in your constructor with the resource ID
* of your custom theme.
*/
+ @SystemApi
public void setTheme(int theme) {
if (mWindow != null) {
throw new IllegalStateException("Must be called before onCreate()");
@@ -523,6 +536,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * @hide
* Ask that a new activity be started for voice interaction. This will create a
* new dedicated task in the activity manager for this voice interaction session;
* this means that {@link Intent#FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_NEW_TASK}
@@ -543,6 +557,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
* always have {@link Intent#CATEGORY_VOICE Intent.CATEGORY_VOICE} added to it, since
* this is part of a voice interaction.
*/
+ @SystemApi
public void startVoiceActivity(Intent intent) {
if (mToken == null) {
throw new IllegalStateException("Can't call before onCreate()");
@@ -558,15 +573,19 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * @hide
* Convenience for inflating views.
*/
+ @SystemApi
public LayoutInflater getLayoutInflater() {
return mInflater;
}
/**
+ * @hide
* Retrieve the window being used to show the session's UI.
*/
+ @SystemApi
public Dialog getWindow() {
return mWindow;
}
@@ -612,8 +631,10 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * @hide
* Hook in which to create the session's UI.
*/
+ @SystemApi
public View onCreateContentView() {
return null;
}
@@ -626,22 +647,42 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
+ /**
+ * @hide
+ */
+ @SystemApi
public boolean onKeyDown(int keyCode, KeyEvent event) {
return false;
}
+ /**
+ * @hide
+ */
+ @SystemApi
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
return false;
}
+ /**
+ * @hide
+ */
+ @SystemApi
public boolean onKeyUp(int keyCode, KeyEvent event) {
return false;
}
+ /**
+ * @hide
+ */
+ @SystemApi
public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
return false;
}
+ /**
+ * @hide
+ */
+ @SystemApi
public void onBackPressed() {
finish();
}
@@ -656,12 +697,14 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * @hide
* Compute the interesting insets into your UI. The default implementation
* uses the entire window frame as the insets. The default touchable
* insets are {@link Insets#TOUCHABLE_INSETS_FRAME}.
*
* @param outInsets Fill in with the current UI insets.
*/
+ @SystemApi
public void onComputeInsets(Insets outInsets) {
int[] loc = mTmpLocation;
View decor = getWindow().getWindow().getDecorView();
@@ -675,6 +718,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * @hide
+ * @SystemApi
* Called when a task initiated by {@link #startVoiceActivity(android.content.Intent)}
* has actually started.
*
@@ -686,6 +731,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * @hide
+ * @SystemApi
* Called when the last activity of a task initiated by
* {@link #startVoiceActivity(android.content.Intent)} has finished. The default
* implementation calls {@link #finish()} on the assumption that this represents
@@ -701,6 +748,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * @hide
+ * @SystemApi
* Request to query for what extended commands the session supports.
*
* @param caller Who is making the request.
@@ -715,6 +764,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * @hide
+ * @SystemApi
* Request to confirm with the user before proceeding with an unrecoverable operation,
* corresponding to a {@link android.app.VoiceInteractor.ConfirmationRequest
* VoiceInteractor.ConfirmationRequest}.
@@ -730,6 +781,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
Bundle extras);
/**
+ * @hide
+ * @SystemApi
* Request to complete the voice interaction session because the voice activity successfully
* completed its interaction using voice. Corresponds to
* {@link android.app.VoiceInteractor.CompleteVoiceRequest
@@ -751,6 +804,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * @hide
+ * @SystemApi
* Request to abort the voice interaction session because the voice activity can not
* complete its interaction using voice. Corresponds to
* {@link android.app.VoiceInteractor.AbortVoiceRequest
@@ -769,6 +824,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
}
/**
+ * @hide
+ * @SystemApi
* Process an arbitrary extended command from the caller,
* corresponding to a {@link android.app.VoiceInteractor.CommandRequest
* VoiceInteractor.CommandRequest}.
@@ -783,6 +840,8 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback {
public abstract void onCommand(Caller caller, Request request, String command, Bundle extras);
/**
+ * @hide
+ * @SystemApi
* Called when the {@link android.app.VoiceInteractor} has asked to cancel a {@link Request}
* that was previously delivered to {@link #onConfirm} or {@link #onCommand}.
*
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
index ebb1a5c..eb17429 100644
--- a/core/java/android/transition/ChangeBounds.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -31,6 +31,7 @@ import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.util.IntProperty;
import android.util.Property;
import android.view.View;
import android.view.ViewGroup;
@@ -185,25 +186,36 @@ public class ChangeBounds extends Transition {
}
if (numChanges > 0) {
if (!mResizeClip) {
- if (startLeft != endLeft) view.setLeft(startLeft);
- if (startTop != endTop) view.setTop(startTop);
- if (startRight != endRight) view.setRight(startRight);
- if (startBottom != endBottom) view.setBottom(startBottom);
- ObjectAnimator topLeftAnimator = null;
- if (startLeft != endLeft || startTop != endTop) {
- Path topLeftPath = getPathMotion().getPath(startLeft, startTop,
- endLeft, endTop);
- topLeftAnimator = ObjectAnimator.ofInt(view, "left", "top", topLeftPath);
- }
- ObjectAnimator bottomRightAnimator = null;
- if (startRight != endRight || startBottom != endBottom) {
- Path bottomRightPath = getPathMotion().getPath(startRight, startBottom,
- endRight, endBottom);
- bottomRightAnimator = ObjectAnimator.ofInt(view, "right", "bottom",
- bottomRightPath);
+ Animator anim;
+ if (startWidth == endWidth && startHeight == endHeight) {
+ view.offsetLeftAndRight(startLeft - view.getLeft());
+ view.offsetTopAndBottom(startTop - view.getTop());
+ Path positionPath = getPathMotion().getPath(0, 0, endLeft - startLeft,
+ endTop - startTop);
+ anim = ObjectAnimator.ofInt(view, new HorizontalOffsetProperty(),
+ new VerticalOffsetProperty(), positionPath);
+ } else {
+ if (startLeft != endLeft) view.setLeft(startLeft);
+ if (startTop != endTop) view.setTop(startTop);
+ if (startRight != endRight) view.setRight(startRight);
+ if (startBottom != endBottom) view.setBottom(startBottom);
+ ObjectAnimator topLeftAnimator = null;
+ if (startLeft != endLeft || startTop != endTop) {
+ Path topLeftPath = getPathMotion().getPath(startLeft, startTop,
+ endLeft, endTop);
+ topLeftAnimator = ObjectAnimator
+ .ofInt(view, "left", "top", topLeftPath);
+ }
+ ObjectAnimator bottomRightAnimator = null;
+ if (startRight != endRight || startBottom != endBottom) {
+ Path bottomRightPath = getPathMotion().getPath(startRight, startBottom,
+ endRight, endBottom);
+ bottomRightAnimator = ObjectAnimator.ofInt(view, "right", "bottom",
+ bottomRightPath);
+ }
+ anim = TransitionUtils.mergeAnimators(topLeftAnimator,
+ bottomRightAnimator);
}
- Animator anim = TransitionUtils.mergeAnimators(topLeftAnimator,
- bottomRightAnimator);
if (view.getParent() instanceof ViewGroup) {
final ViewGroup parent = (ViewGroup) view.getParent();
parent.suppressLayout(true);
@@ -341,4 +353,48 @@ public class ChangeBounds extends Transition {
}
return null;
}
+
+ private abstract static class OffsetProperty extends IntProperty<View> {
+ int mPreviousValue;
+
+ public OffsetProperty(String name) {
+ super(name);
+ }
+
+ @Override
+ public void setValue(View view, int value) {
+ int offset = value - mPreviousValue;
+ offsetBy(view, offset);
+ mPreviousValue = value;
+ }
+
+ @Override
+ public Integer get(View object) {
+ return null;
+ }
+
+ protected abstract void offsetBy(View view, int by);
+ }
+
+ private static class HorizontalOffsetProperty extends OffsetProperty {
+ public HorizontalOffsetProperty() {
+ super("offsetLeftAndRight");
+ }
+
+ @Override
+ protected void offsetBy(View view, int by) {
+ view.offsetLeftAndRight(by);
+ }
+ }
+
+ private static class VerticalOffsetProperty extends OffsetProperty {
+ public VerticalOffsetProperty() {
+ super("offsetTopAndBottom");
+ }
+
+ @Override
+ protected void offsetBy(View view, int by) {
+ view.offsetTopAndBottom(by);
+ }
+ }
}
diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java
index b0c9e9a..a84ecd1 100644
--- a/core/java/android/transition/TransitionUtils.java
+++ b/core/java/android/transition/TransitionUtils.java
@@ -40,6 +40,33 @@ public class TransitionUtils {
}
}
+ public static Transition mergeTransitions(Transition... transitions) {
+ int count = 0;
+ int nonNullIndex = -1;
+ for (int i = 0; i < transitions.length; i++) {
+ if (transitions[i] != null) {
+ count++;
+ nonNullIndex = i;
+ }
+ }
+
+ if (count == 0) {
+ return null;
+ }
+
+ if (count == 1) {
+ return transitions[nonNullIndex];
+ }
+
+ TransitionSet transitionSet = new TransitionSet();
+ for (int i = 0; i < transitions.length; i++) {
+ if (transitions[i] != null) {
+ transitionSet.addTransition(transitions[i]);
+ }
+ }
+ return transitionSet;
+ }
+
public static class MatrixEvaluator implements TypeEvaluator<Matrix> {
float[] mTempStartValues = new float[9];
diff --git a/core/java/android/util/Spline.java b/core/java/android/util/Spline.java
index ed027eb..41a2e5d 100644
--- a/core/java/android/util/Spline.java
+++ b/core/java/android/util/Spline.java
@@ -20,15 +20,34 @@ package android.util;
* Performs spline interpolation given a set of control points.
* @hide
*/
-public final class Spline {
- private final float[] mX;
- private final float[] mY;
- private final float[] mM;
-
- private Spline(float[] x, float[] y, float[] m) {
- mX = x;
- mY = y;
- mM = m;
+public abstract class Spline {
+
+ /**
+ * Interpolates the value of Y = f(X) for given X.
+ * Clamps X to the domain of the spline.
+ *
+ * @param x The X value.
+ * @return The interpolated Y = f(X) value.
+ */
+ public abstract float interpolate(float x);
+
+ /**
+ * Creates an appropriate spline based on the properties of the control points.
+ *
+ * If the control points are monotonic then the resulting spline will preserve that and
+ * otherwise optimize for error bounds.
+ */
+ public static Spline createSpline(float[] x, float[] y) {
+ if (!isStrictlyIncreasing(x)) {
+ throw new IllegalArgumentException("The control points must all have strictly "
+ + "increasing X values.");
+ }
+
+ if (isMonotonic(y)) {
+ return createMonotoneCubicSpline(x, y);
+ } else {
+ return createLinearSpline(x, y);
+ }
}
/**
@@ -50,107 +69,229 @@ public final class Spline {
* @throws IllegalArgumentException if the control points are not monotonic.
*/
public static Spline createMonotoneCubicSpline(float[] x, float[] y) {
- if (x == null || y == null || x.length != y.length || x.length < 2) {
- throw new IllegalArgumentException("There must be at least two control "
- + "points and the arrays must be of equal length.");
- }
+ return new MonotoneCubicSpline(x, y);
+ }
- final int n = x.length;
- float[] d = new float[n - 1]; // could optimize this out
- float[] m = new float[n];
+ /**
+ * Creates a linear spline from a given set of control points.
+ *
+ * Like a monotone cubic spline, the interpolated curve will be monotonic if the control points
+ * are monotonic.
+ *
+ * @param x The X component of the control points, strictly increasing.
+ * @param y The Y component of the control points.
+ * @return
+ *
+ * @throws IllegalArgumentException if the X or Y arrays are null, have
+ * different lengths or have fewer than 2 values.
+ * @throws IllegalArgumentException if the X components of the control points are not strictly
+ * increasing.
+ */
+ public static Spline createLinearSpline(float[] x, float[] y) {
+ return new LinearSpline(x, y);
+ }
- // Compute slopes of secant lines between successive points.
- for (int i = 0; i < n - 1; i++) {
- float h = x[i + 1] - x[i];
- if (h <= 0f) {
- throw new IllegalArgumentException("The control points must all "
- + "have strictly increasing X values.");
+ private static boolean isStrictlyIncreasing(float[] x) {
+ if (x == null || x.length < 2) {
+ throw new IllegalArgumentException("There must be at least two control points.");
+ }
+ float prev = x[0];
+ for (int i = 1; i < x.length; i++) {
+ float curr = x[i];
+ if (curr <= prev) {
+ return false;
}
- d[i] = (y[i + 1] - y[i]) / h;
+ prev = curr;
}
+ return true;
+ }
- // Initialize the tangents as the average of the secants.
- m[0] = d[0];
- for (int i = 1; i < n - 1; i++) {
- m[i] = (d[i - 1] + d[i]) * 0.5f;
+ private static boolean isMonotonic(float[] x) {
+ if (x == null || x.length < 2) {
+ throw new IllegalArgumentException("There must be at least two control points.");
}
- m[n - 1] = d[n - 2];
-
- // Update the tangents to preserve monotonicity.
- for (int i = 0; i < n - 1; i++) {
- if (d[i] == 0f) { // successive Y values are equal
- m[i] = 0f;
- m[i + 1] = 0f;
- } else {
- float a = m[i] / d[i];
- float b = m[i + 1] / d[i];
- if (a < 0f || b < 0f) {
- throw new IllegalArgumentException("The control points must have "
- + "monotonic Y values.");
- }
- float h = FloatMath.hypot(a, b);
- if (h > 9f) {
- float t = 3f / h;
- m[i] = t * a * d[i];
- m[i + 1] = t * b * d[i];
- }
+ float prev = x[0];
+ for (int i = 1; i < x.length; i++) {
+ float curr = x[i];
+ if (curr < prev) {
+ return false;
}
+ prev = curr;
}
- return new Spline(x, y, m);
+ return true;
}
- /**
- * Interpolates the value of Y = f(X) for given X.
- * Clamps X to the domain of the spline.
- *
- * @param x The X value.
- * @return The interpolated Y = f(X) value.
- */
- public float interpolate(float x) {
- // Handle the boundary cases.
- final int n = mX.length;
- if (Float.isNaN(x)) {
- return x;
+ public static class MonotoneCubicSpline extends Spline {
+ private float[] mX;
+ private float[] mY;
+ private float[] mM;
+
+ public MonotoneCubicSpline(float[] x, float[] y) {
+ if (x == null || y == null || x.length != y.length || x.length < 2) {
+ throw new IllegalArgumentException("There must be at least two control "
+ + "points and the arrays must be of equal length.");
+ }
+
+ final int n = x.length;
+ float[] d = new float[n - 1]; // could optimize this out
+ float[] m = new float[n];
+
+ // Compute slopes of secant lines between successive points.
+ for (int i = 0; i < n - 1; i++) {
+ float h = x[i + 1] - x[i];
+ if (h <= 0f) {
+ throw new IllegalArgumentException("The control points must all "
+ + "have strictly increasing X values.");
+ }
+ d[i] = (y[i + 1] - y[i]) / h;
+ }
+
+ // Initialize the tangents as the average of the secants.
+ m[0] = d[0];
+ for (int i = 1; i < n - 1; i++) {
+ m[i] = (d[i - 1] + d[i]) * 0.5f;
+ }
+ m[n - 1] = d[n - 2];
+
+ // Update the tangents to preserve monotonicity.
+ for (int i = 0; i < n - 1; i++) {
+ if (d[i] == 0f) { // successive Y values are equal
+ m[i] = 0f;
+ m[i + 1] = 0f;
+ } else {
+ float a = m[i] / d[i];
+ float b = m[i + 1] / d[i];
+ if (a < 0f || b < 0f) {
+ throw new IllegalArgumentException("The control points must have "
+ + "monotonic Y values.");
+ }
+ float h = FloatMath.hypot(a, b);
+ if (h > 9f) {
+ float t = 3f / h;
+ m[i] = t * a * d[i];
+ m[i + 1] = t * b * d[i];
+ }
+ }
+ }
+
+ mX = x;
+ mY = y;
+ mM = m;
}
- if (x <= mX[0]) {
- return mY[0];
+
+ @Override
+ public float interpolate(float x) {
+ // Handle the boundary cases.
+ final int n = mX.length;
+ if (Float.isNaN(x)) {
+ return x;
+ }
+ if (x <= mX[0]) {
+ return mY[0];
+ }
+ if (x >= mX[n - 1]) {
+ return mY[n - 1];
+ }
+
+ // Find the index 'i' of the last point with smaller X.
+ // We know this will be within the spline due to the boundary tests.
+ int i = 0;
+ while (x >= mX[i + 1]) {
+ i += 1;
+ if (x == mX[i]) {
+ return mY[i];
+ }
+ }
+
+ // Perform cubic Hermite spline interpolation.
+ float h = mX[i + 1] - mX[i];
+ float t = (x - mX[i]) / h;
+ return (mY[i] * (1 + 2 * t) + h * mM[i] * t) * (1 - t) * (1 - t)
+ + (mY[i + 1] * (3 - 2 * t) + h * mM[i + 1] * (t - 1)) * t * t;
}
- if (x >= mX[n - 1]) {
- return mY[n - 1];
+
+ // For debugging.
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder();
+ final int n = mX.length;
+ str.append("MonotoneCubicSpline{[");
+ for (int i = 0; i < n; i++) {
+ if (i != 0) {
+ str.append(", ");
+ }
+ str.append("(").append(mX[i]);
+ str.append(", ").append(mY[i]);
+ str.append(": ").append(mM[i]).append(")");
+ }
+ str.append("]}");
+ return str.toString();
}
+ }
- // Find the index 'i' of the last point with smaller X.
- // We know this will be within the spline due to the boundary tests.
- int i = 0;
- while (x >= mX[i + 1]) {
- i += 1;
- if (x == mX[i]) {
- return mY[i];
+ public static class LinearSpline extends Spline {
+ private final float[] mX;
+ private final float[] mY;
+ private final float[] mM;
+
+ public LinearSpline(float[] x, float[] y) {
+ if (x == null || y == null || x.length != y.length || x.length < 2) {
+ throw new IllegalArgumentException("There must be at least two control "
+ + "points and the arrays must be of equal length.");
+ }
+ final int N = x.length;
+ mM = new float[N-1];
+ for (int i = 0; i < N-1; i++) {
+ mM[i] = (y[i+1] - y[i]) / (x[i+1] - x[i]);
}
+ mX = x;
+ mY = y;
}
- // Perform cubic Hermite spline interpolation.
- float h = mX[i + 1] - mX[i];
- float t = (x - mX[i]) / h;
- return (mY[i] * (1 + 2 * t) + h * mM[i] * t) * (1 - t) * (1 - t)
- + (mY[i + 1] * (3 - 2 * t) + h * mM[i + 1] * (t - 1)) * t * t;
- }
+ @Override
+ public float interpolate(float x) {
+ // Handle the boundary cases.
+ final int n = mX.length;
+ if (Float.isNaN(x)) {
+ return x;
+ }
+ if (x <= mX[0]) {
+ return mY[0];
+ }
+ if (x >= mX[n - 1]) {
+ return mY[n - 1];
+ }
- // For debugging.
- @Override
- public String toString() {
- StringBuilder str = new StringBuilder();
- final int n = mX.length;
- str.append("[");
- for (int i = 0; i < n; i++) {
- if (i != 0) {
- str.append(", ");
- }
- str.append("(").append(mX[i]);
- str.append(", ").append(mY[i]);
- str.append(": ").append(mM[i]).append(")");
+ // Find the index 'i' of the last point with smaller X.
+ // We know this will be within the spline due to the boundary tests.
+ int i = 0;
+ while (x >= mX[i + 1]) {
+ i += 1;
+ if (x == mX[i]) {
+ return mY[i];
+ }
+ }
+ return mY[i] + mM[i] * (x - mX[i]);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder();
+ final int n = mX.length;
+ str.append("LinearSpline{[");
+ for (int i = 0; i < n; i++) {
+ if (i != 0) {
+ str.append(", ");
+ }
+ str.append("(").append(mX[i]);
+ str.append(", ").append(mY[i]);
+ if (i < n-1) {
+ str.append(": ").append(mM[i]);
+ }
+ str.append(")");
+ }
+ str.append("]}");
+ return str.toString();
}
- str.append("]");
- return str.toString();
}
}
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 477c994..a10dda3 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -18,6 +18,7 @@ package android.view;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -96,7 +97,7 @@ final class AccessibilityInteractionController {
}
public void findAccessibilityNodeInfoByAccessibilityIdClientThread(
- long accessibilityNodeId, int interactionId,
+ long accessibilityNodeId, Region interactiveRegion, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
long interrogatingTid, MagnificationSpec spec) {
Message message = mHandler.obtainMessage();
@@ -109,6 +110,7 @@ final class AccessibilityInteractionController {
args.argi3 = interactionId;
args.arg1 = callback;
args.arg2 = spec;
+ args.arg3 = interactiveRegion;
message.obj = args;
// If the interrogation is performed by the same thread as the main UI
@@ -133,6 +135,7 @@ final class AccessibilityInteractionController {
final IAccessibilityInteractionConnectionCallback callback =
(IAccessibilityInteractionConnectionCallback) args.arg1;
final MagnificationSpec spec = (MagnificationSpec) args.arg2;
+ final Region interactiveRegion = (Region) args.arg3;
args.recycle();
@@ -159,6 +162,7 @@ final class AccessibilityInteractionController {
if (spec != null) {
spec.recycle();
}
+ adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
infos.clear();
} catch (RemoteException re) {
@@ -168,8 +172,9 @@ final class AccessibilityInteractionController {
}
public void findAccessibilityNodeInfosByViewIdClientThread(long accessibilityNodeId,
- String viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
- int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
+ String viewId, Region interactiveRegion, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
+ long interrogatingTid, MagnificationSpec spec) {
Message message = mHandler.obtainMessage();
message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFOS_BY_VIEW_ID;
message.arg1 = flags;
@@ -180,6 +185,7 @@ final class AccessibilityInteractionController {
args.arg1 = callback;
args.arg2 = spec;
args.arg3 = viewId;
+ args.arg4 = interactiveRegion;
message.obj = args;
@@ -205,6 +211,7 @@ final class AccessibilityInteractionController {
(IAccessibilityInteractionConnectionCallback) args.arg1;
final MagnificationSpec spec = (MagnificationSpec) args.arg2;
final String viewId = (String) args.arg3;
+ final Region interactiveRegion = (Region) args.arg4;
args.recycle();
@@ -241,6 +248,7 @@ final class AccessibilityInteractionController {
if (spec != null) {
spec.recycle();
}
+ adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
} catch (RemoteException re) {
/* ignore - the other side will time out */
@@ -249,8 +257,9 @@ final class AccessibilityInteractionController {
}
public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeId,
- String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
- int flags, int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
+ String text, Region interactiveRegion, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
+ long interrogatingTid, MagnificationSpec spec) {
Message message = mHandler.obtainMessage();
message.what = PrivateHandler.MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT;
message.arg1 = flags;
@@ -262,6 +271,7 @@ final class AccessibilityInteractionController {
args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
args.argi3 = interactionId;
+ args.arg4 = interactiveRegion;
message.obj = args;
// If the interrogation is performed by the same thread as the main UI
@@ -287,6 +297,7 @@ final class AccessibilityInteractionController {
final int accessibilityViewId = args.argi1;
final int virtualDescendantId = args.argi2;
final int interactionId = args.argi3;
+ final Region interactiveRegion = (Region) args.arg4;
args.recycle();
List<AccessibilityNodeInfo> infos = null;
@@ -347,6 +358,7 @@ final class AccessibilityInteractionController {
if (spec != null) {
spec.recycle();
}
+ adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
} catch (RemoteException re) {
/* ignore - the other side will time out */
@@ -354,7 +366,8 @@ final class AccessibilityInteractionController {
}
}
- public void findFocusClientThread(long accessibilityNodeId, int focusType, int interactionId,
+ public void findFocusClientThread(long accessibilityNodeId, int focusType,
+ Region interactiveRegion, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid,
long interrogatingTid, MagnificationSpec spec) {
Message message = mHandler.obtainMessage();
@@ -368,6 +381,7 @@ final class AccessibilityInteractionController {
args.argi3 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
args.arg1 = callback;
args.arg2 = spec;
+ args.arg3 = interactiveRegion;
message.obj = args;
@@ -394,6 +408,7 @@ final class AccessibilityInteractionController {
final IAccessibilityInteractionConnectionCallback callback =
(IAccessibilityInteractionConnectionCallback) args.arg1;
final MagnificationSpec spec = (MagnificationSpec) args.arg2;
+ final Region interactiveRegion = (Region) args.arg3;
args.recycle();
AccessibilityNodeInfo focused = null;
@@ -457,6 +472,7 @@ final class AccessibilityInteractionController {
if (spec != null) {
spec.recycle();
}
+ adjustIsVisibleToUserIfNeeded(focused, interactiveRegion);
callback.setFindAccessibilityNodeInfoResult(focused, interactionId);
} catch (RemoteException re) {
/* ignore - the other side will time out */
@@ -464,7 +480,8 @@ final class AccessibilityInteractionController {
}
}
- public void focusSearchClientThread(long accessibilityNodeId, int direction, int interactionId,
+ public void focusSearchClientThread(long accessibilityNodeId, int direction,
+ Region interactiveRegion, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags, int interogatingPid,
long interrogatingTid, MagnificationSpec spec) {
Message message = mHandler.obtainMessage();
@@ -477,6 +494,7 @@ final class AccessibilityInteractionController {
args.argi3 = interactionId;
args.arg1 = callback;
args.arg2 = spec;
+ args.arg3 = interactiveRegion;
message.obj = args;
@@ -502,6 +520,7 @@ final class AccessibilityInteractionController {
final IAccessibilityInteractionConnectionCallback callback =
(IAccessibilityInteractionConnectionCallback) args.arg1;
final MagnificationSpec spec = (MagnificationSpec) args.arg2;
+ final Region interactiveRegion = (Region) args.arg3;
args.recycle();
@@ -530,6 +549,7 @@ final class AccessibilityInteractionController {
if (spec != null) {
spec.recycle();
}
+ adjustIsVisibleToUserIfNeeded(next, interactiveRegion);
callback.setFindAccessibilityNodeInfoResult(next, interactionId);
} catch (RemoteException re) {
/* ignore - the other side will time out */
@@ -644,6 +664,30 @@ final class AccessibilityInteractionController {
}
}
+ private void adjustIsVisibleToUserIfNeeded(List<AccessibilityNodeInfo> infos,
+ Region interactiveRegion) {
+ if (interactiveRegion == null || infos == null) {
+ return;
+ }
+ final int infoCount = infos.size();
+ for (int i = 0; i < infoCount; i++) {
+ AccessibilityNodeInfo info = infos.get(i);
+ adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+ }
+ }
+
+ private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info,
+ Region interactiveRegion) {
+ if (interactiveRegion == null || info == null) {
+ return;
+ }
+ Rect boundsInScreen = mTempRect;
+ info.getBoundsInScreen(boundsInScreen);
+ if (interactiveRegion.quickReject(boundsInScreen)) {
+ info.setVisibleToUser(false);
+ }
+ }
+
private void applyAppScaleAndMagnificationSpecIfNeeded(AccessibilityNodeInfo info,
MagnificationSpec spec) {
if (info == null) {
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 063a08d..7dcad68 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -149,9 +149,9 @@ public final class PointerIcon implements Parcelable {
* Creates a custom pointer from the given bitmap and hotspot information.
*
* @param bitmap The bitmap for the icon.
- * @param hotspotX The X offset of the pointer icon hotspot in the bitmap.
+ * @param hotSpotX The X offset of the pointer icon hotspot in the bitmap.
* Must be within the [0, bitmap.getWidth()) range.
- * @param hotspotY The Y offset of the pointer icon hotspot in the bitmap.
+ * @param hotSpotY The Y offset of the pointer icon hotspot in the bitmap.
* Must be within the [0, bitmap.getHeight()) range.
* @return A pointer icon for this bitmap.
*
@@ -374,18 +374,18 @@ public final class PointerIcon implements Parcelable {
}
private void loadResource(Context context, Resources resources, int resourceId) {
- XmlResourceParser parser = resources.getXml(resourceId);
+ final XmlResourceParser parser = resources.getXml(resourceId);
final int bitmapRes;
final float hotSpotX;
final float hotSpotY;
try {
XmlUtils.beginDocument(parser, "pointer-icon");
- TypedArray a = resources.obtainAttributes(
+ final TypedArray a = resources.obtainAttributes(
parser, com.android.internal.R.styleable.PointerIcon);
bitmapRes = a.getResourceId(com.android.internal.R.styleable.PointerIcon_bitmap, 0);
- hotSpotX = a.getFloat(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0);
- hotSpotY = a.getFloat(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0);
+ hotSpotX = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0);
+ hotSpotY = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0);
a.recycle();
} catch (Exception ex) {
throw new IllegalArgumentException("Exception parsing pointer icon resource.", ex);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 49d925f..dd1cbc9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6629,14 +6629,15 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
- int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
+ Region interactiveRegion, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, int flags,
int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
ViewRootImpl viewRootImpl = mViewRootImpl.get();
if (viewRootImpl != null && viewRootImpl.mView != null) {
viewRootImpl.getAccessibilityInteractionController()
.findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
- interactionId, callback, flags, interrogatingPid, interrogatingTid,
- spec);
+ interactiveRegion, interactionId, callback, flags, interrogatingPid,
+ interrogatingTid, spec);
} else {
// We cannot make the call and notify the caller so it does not wait.
try {
@@ -6669,15 +6670,15 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
- String viewId, int interactionId,
+ String viewId, Region interactiveRegion, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags,
int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
ViewRootImpl viewRootImpl = mViewRootImpl.get();
if (viewRootImpl != null && viewRootImpl.mView != null) {
viewRootImpl.getAccessibilityInteractionController()
.findAccessibilityNodeInfosByViewIdClientThread(accessibilityNodeId,
- viewId, interactionId, callback, flags, interrogatingPid,
- interrogatingTid, spec);
+ viewId, interactiveRegion, interactionId, callback, flags,
+ interrogatingPid, interrogatingTid, spec);
} else {
// We cannot make the call and notify the caller so it does not wait.
try {
@@ -6690,14 +6691,15 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
- int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
+ Region interactiveRegion, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, int flags,
int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
ViewRootImpl viewRootImpl = mViewRootImpl.get();
if (viewRootImpl != null && viewRootImpl.mView != null) {
viewRootImpl.getAccessibilityInteractionController()
.findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
- interactionId, callback, flags, interrogatingPid, interrogatingTid,
- spec);
+ interactiveRegion, interactionId, callback, flags, interrogatingPid,
+ interrogatingTid, spec);
} else {
// We cannot make the call and notify the caller so it does not wait.
try {
@@ -6709,14 +6711,15 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
- public void findFocus(long accessibilityNodeId, int focusType, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, int flags,
+ public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
ViewRootImpl viewRootImpl = mViewRootImpl.get();
if (viewRootImpl != null && viewRootImpl.mView != null) {
viewRootImpl.getAccessibilityInteractionController()
- .findFocusClientThread(accessibilityNodeId, focusType, interactionId, callback,
- flags, interrogatingPid, interrogatingTid, spec);
+ .findFocusClientThread(accessibilityNodeId, focusType, interactiveRegion,
+ interactionId, callback, flags, interrogatingPid, interrogatingTid,
+ spec);
} else {
// We cannot make the call and notify the caller so it does not wait.
try {
@@ -6728,14 +6731,15 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
- public void focusSearch(long accessibilityNodeId, int direction, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, int flags,
+ public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
ViewRootImpl viewRootImpl = mViewRootImpl.get();
if (viewRootImpl != null && viewRootImpl.mView != null) {
viewRootImpl.getAccessibilityInteractionController()
- .focusSearchClientThread(accessibilityNodeId, direction, interactionId,
- callback, flags, interrogatingPid, interrogatingTid, spec);
+ .focusSearchClientThread(accessibilityNodeId, direction, interactiveRegion,
+ interactionId, callback, flags, interrogatingPid, interrogatingTid,
+ spec);
} else {
// We cannot make the call and notify the caller so it does not wait.
try {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 9b6f200..ebc683a 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1430,7 +1430,9 @@ public abstract class Window {
* {@link android.transition.Visibility} as entering is governed by changing visibility from
* {@link View#INVISIBLE} to {@link View#VISIBLE}. If <code>transition</code> is null,
* entering Views will remain unaffected.
+ *
* @param transition The Transition to use to move Views into the initial Scene.
+ * @attr ref android.R.styleable#Window_windowEnterTransition
*/
public void setEnterTransition(Transition transition) {}
@@ -1444,8 +1446,10 @@ public abstract class Window {
* {@link View#VISIBLE} to {@link View#INVISIBLE}. If <code>transition</code> is null,
* entering Views will remain unaffected. If nothing is set, the default will be to
* use the same value as set in {@link #setEnterTransition(android.transition.Transition)}.
+ *
* @param transition The Transition to use to move Views out of the Scene when the Window
* is preparing to close.
+ * @attr ref android.R.styleable#Window_windowReturnTransition
*/
public void setReturnTransition(Transition transition) {}
@@ -1456,8 +1460,10 @@ public abstract class Window {
* {@link android.transition.Visibility} as exiting is governed by changing visibility
* from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will
* remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ *
* @param transition The Transition to use to move Views out of the scene when calling a
* new Activity.
+ * @attr ref android.R.styleable#Window_windowExitTransition
*/
public void setExitTransition(Transition transition) {}
@@ -1470,8 +1476,10 @@ public abstract class Window {
* the views will remain unaffected. If nothing is set, the default will be to use the same
* transition as {@link #setExitTransition(android.transition.Transition)}.
* Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ *
* @param transition The Transition to use to move Views into the scene when reentering from a
* previously-started Activity.
+ * @attr ref android.R.styleable#Window_windowReenterTransition
*/
public void setReenterTransition(Transition transition) {}
@@ -1484,6 +1492,7 @@ public abstract class Window {
* entering Views will remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
*
* @return the Transition to use to move Views into the initial Scene.
+ * @attr ref android.R.styleable#Window_windowEnterTransition
*/
public Transition getEnterTransition() { return null; }
@@ -1495,8 +1504,10 @@ public abstract class Window {
* {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
* {@link android.transition.Visibility} as entering is governed by changing visibility from
* {@link View#VISIBLE} to {@link View#INVISIBLE}.
+ *
* @return The Transition to use to move Views out of the Scene when the Window
* is preparing to close.
+ * @attr ref android.R.styleable#Window_windowReturnTransition
*/
public Transition getReturnTransition() { return null; }
@@ -1507,8 +1518,10 @@ public abstract class Window {
* {@link android.transition.Visibility} as exiting is governed by changing visibility
* from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will
* remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ *
* @return the Transition to use to move Views out of the scene when calling a
* new Activity.
+ * @attr ref android.R.styleable#Window_windowExitTransition
*/
public Transition getExitTransition() { return null; }
@@ -1519,8 +1532,10 @@ public abstract class Window {
* will extend {@link android.transition.Visibility} as exiting is governed by changing
* visibility from {@link View#VISIBLE} to {@link View#INVISIBLE}.
* Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ *
* @return The Transition to use to move Views into the scene when reentering from a
* previously-started Activity.
+ * @attr ref android.R.styleable#Window_windowReenterTransition
*/
public Transition getReenterTransition() { return null; }
@@ -1530,8 +1545,10 @@ public abstract class Window {
* {@link android.transition.ChangeBounds}. A null
* value will cause transferred shared elements to blink to the final position.
* Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ *
* @param transition The Transition to use for shared elements transferred into the content
* Scene.
+ * @attr ref android.R.styleable#Window_windowSharedElementEnterTransition
*/
public void setSharedElementEnterTransition(Transition transition) {}
@@ -1543,22 +1560,28 @@ public abstract class Window {
* If no value is set, the default will be to use the same value as
* {@link #setSharedElementEnterTransition(android.transition.Transition)}.
* Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ *
* @param transition The Transition to use for shared elements transferred out of the content
* Scene.
+ * @attr ref android.R.styleable#Window_windowSharedElementReturnTransition
*/
public void setSharedElementReturnTransition(Transition transition) {}
/**
* Returns the Transition that will be used for shared elements transferred into the content
* Scene. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ *
* @return Transition to use for sharend elements transferred into the content Scene.
+ * @attr ref android.R.styleable#Window_windowSharedElementEnterTransition
*/
public Transition getSharedElementEnterTransition() { return null; }
/**
* Returns the Transition that will be used for shared elements transferred back to a
* calling Activity. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ *
* @return Transition to use for sharend elements transferred into the content Scene.
+ * @attr ref android.R.styleable#Window_windowSharedElementReturnTransition
*/
public Transition getSharedElementReturnTransition() { return null; }
@@ -1568,8 +1591,10 @@ public abstract class Window {
* must animate during the exit transition, this Transition should be used. Upon completion,
* the shared elements may be transferred to the started Activity.
* Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ *
* @param transition The Transition to use for shared elements in the launching Window
* prior to transferring to the launched Activity's Window.
+ * @attr ref android.R.styleable#Window_windowSharedElementExitTransition
*/
public void setSharedElementExitTransition(Transition transition) {}
@@ -1579,8 +1604,10 @@ public abstract class Window {
* is set, this will default to
* {@link #setSharedElementExitTransition(android.transition.Transition)}.
* Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
+ *
* @param transition The Transition to use for shared elements in the launching Window
* after the shared element has returned to the Window.
+ * @attr ref android.R.styleable#Window_windowSharedElementReenterTransition
*/
public void setSharedElementReenterTransition(Transition transition) {}
@@ -1591,6 +1618,7 @@ public abstract class Window {
*
* @return the Transition to use for shared elements in the launching Window prior
* to transferring to the launched Activity's Window.
+ * @attr ref android.R.styleable#Window_windowSharedElementExitTransition
*/
public Transition getSharedElementExitTransition() { return null; }
@@ -1601,6 +1629,7 @@ public abstract class Window {
*
* @return the Transition that will be used for shared elements reentering from a started
* Activity after it has returned the shared element to it start location.
+ * @attr ref android.R.styleable#Window_windowSharedElementReenterTransition
*/
public Transition getSharedElementReenterTransition() { return null; }
@@ -1610,8 +1639,10 @@ public abstract class Window {
* transition of the calling Activity. When true, the transition will start as soon as possible.
* When false, the transition will wait until the remote exiting transition completes before
* starting.
+ *
* @param allow true to start the enter transition when possible or false to
* wait until the exiting transition completes.
+ * @attr ref android.R.styleable#Window_windowAllowEnterTransitionOverlap
*/
public void setAllowEnterTransitionOverlap(boolean allow) {}
@@ -1621,8 +1652,10 @@ public abstract class Window {
* transition of the calling Activity. When true, the transition will start as soon as possible.
* When false, the transition will wait until the remote exiting transition completes before
* starting.
+ *
* @return true when the enter transition should start as soon as possible or false to
* when it should wait until the exiting transition completes.
+ * @attr ref android.R.styleable#Window_windowAllowEnterTransitionOverlap
*/
public boolean getAllowEnterTransitionOverlap() { return true; }
@@ -1632,10 +1665,20 @@ public abstract class Window {
* transition of the called Activity when reentering after if finishes. When true,
* the transition will start as soon as possible. When false, the transition will wait
* until the called Activity's exiting transition completes before starting.
+ *
* @param allow true to start the transition when possible or false to wait until the
* called Activity's exiting transition completes.
+ * @attr ref android.R.styleable#Window_windowAllowReturnTransitionOverlap
*/
- public void setAllowExitTransitionOverlap(boolean allow) {}
+ public void setAllowReturnTransitionOverlap(boolean allow) {}
+
+ /**
+ * TODO: remove this.
+ * @hide
+ */
+ public void setAllowExitTransitionOverlap(boolean allow) {
+ setAllowReturnTransitionOverlap(allow);
+ }
/**
* Returns how the transition set in
@@ -1643,10 +1686,18 @@ public abstract class Window {
* transition of the called Activity when reentering after if finishes. When true,
* the transition will start as soon as possible. When false, the transition will wait
* until the called Activity's exiting transition completes before starting.
+ *
* @return true when the transition should start when possible or false when it should wait
* until the called Activity's exiting transition completes.
+ * @attr ref android.R.styleable#Window_windowAllowReturnTransitionOverlap
*/
- public boolean getAllowExitTransitionOverlap() { return true; }
+ public boolean getAllowReturnTransitionOverlap() { return true; }
+
+ /**
+ * TODO: remove this.
+ * @hide
+ */
+ public boolean getAllowExitTransitionOverlap() { return getAllowReturnTransitionOverlap(); }
/**
* Returns the duration, in milliseconds, of the window background fade
@@ -1654,8 +1705,10 @@ public abstract class Window {
* <p>When executing the enter transition, the background starts transparent
* and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is
* 300 milliseconds.</p>
+ *
* @return The duration of the window background fade to opaque during enter transition.
* @see #getEnterTransition()
+ * @attr ref android.R.styleable#Window_windowTransitionBackgroundFadeDuration
*/
public long getTransitionBackgroundFadeDuration() { return 0; }
@@ -1665,9 +1718,11 @@ public abstract class Window {
* <p>When executing the enter transition, the background starts transparent
* and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is
* 300 milliseconds.</p>
+ *
* @param fadeDurationMillis The duration of the window background fade to or from opaque
* during enter transition.
* @see #setEnterTransition(android.transition.Transition)
+ * @attr ref android.R.styleable#Window_windowTransitionBackgroundFadeDuration
*/
public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) { }
@@ -1679,6 +1734,7 @@ public abstract class Window {
* @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.
+ * @attr ref android.R.styleable#Window_windowSharedElementsUseOverlay
*/
public boolean getSharedElementsUseOverlay() { return true; }
@@ -1689,6 +1745,7 @@ public abstract class Window {
* @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.
+ * @attr ref android.R.styleable#Window_windowSharedElementsUseOverlay
*/
public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) { }
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index 8d15472..faf7789 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -16,6 +16,7 @@
package android.view.accessibility;
+import android.graphics.Region;
import android.os.Bundle;
import android.view.MagnificationSpec;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -29,23 +30,23 @@ import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
*/
oneway interface IAccessibilityInteractionConnection {
- void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
- long interrogatingTid, in MagnificationSpec spec);
+ void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId, in Region bounds,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
+ int interrogatingPid, long interrogatingTid, in MagnificationSpec spec);
void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId,
+ in Region bounds, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ int flags, int interrogatingPid, long interrogatingTid, in MagnificationSpec spec);
+
+ void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, in Region bounds,
int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
int interrogatingPid, long interrogatingTid, in MagnificationSpec spec);
- void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
- long interrogatingTid, in MagnificationSpec spec);
-
- void findFocus(long accessibilityNodeId, int focusType, int interactionId,
+ void findFocus(long accessibilityNodeId, int focusType, in Region bounds, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
long interrogatingTid, in MagnificationSpec spec);
- void focusSearch(long accessibilityNodeId, int direction, int interactionId,
+ void focusSearch(long accessibilityNodeId, int direction, in Region bounds, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid,
long interrogatingTid, in MagnificationSpec spec);
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 4d2f57a..20adfe4 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -431,7 +431,15 @@ public class BaseInputConnection implements InputConnection {
/**
* The default implementation does nothing.
*/
- public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
+ public boolean requestCursorUpdates(int cursorUpdateMode) {
+ return false;
+ }
+
+ /**
+ * The default implementation does nothing.
+ * @removed
+ */
+ public final boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
return false;
}
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index 730b7f6..fe0f5b9 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -45,9 +45,9 @@ public final class CursorAnchorInfo implements Parcelable {
private final CharSequence mComposingText;
/**
- * {@code True} if the insertion marker is partially or entirely clipped by other UI elements.
+ * Flags of the insertion marker. See {@link #FLAG_HAS_VISIBLE_REGION} for example.
*/
- private final boolean mInsertionMarkerClipped;
+ private final int mInsertionMarkerFlags;
/**
* Horizontal position of the insertion marker, in the local coordinates that will be
* transformed with the transformation matrix when rendered on the screen. This should be
@@ -90,27 +90,47 @@ public final class CursorAnchorInfo implements Parcelable {
*/
private final Matrix mMatrix;
+ /**
+ * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterRectFlags(int)}: the
+ * insertion marker or character bounds have at least one visible region.
+ */
+ public static final int FLAG_HAS_VISIBLE_REGION = 0x01;
+
+ /**
+ * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterRectFlags(int)}: the
+ * insertion marker or character bounds have at least one invisible (clipped) region.
+ */
+ public static final int FLAG_HAS_INVISIBLE_REGION = 0x02;
+
+ /**
+ * @removed
+ */
public static final int CHARACTER_RECT_TYPE_MASK = 0x0f;
/**
* Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor did not specify any type of this
* character. Editor authors should not use this flag.
+ * @removed
*/
public static final int CHARACTER_RECT_TYPE_UNSPECIFIED = 0;
/**
* Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely visible.
+ * @removed
*/
public static final int CHARACTER_RECT_TYPE_FULLY_VISIBLE = 1;
/**
* Type for {@link #CHARACTER_RECT_TYPE_MASK}: some area of the character is invisible.
+ * @removed
*/
public static final int CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE = 2;
/**
* Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely invisible.
+ * @removed
*/
public static final int CHARACTER_RECT_TYPE_INVISIBLE = 3;
/**
* Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor gave up to calculate the rectangle
* for this character. Input method authors should ignore the returned rectangle.
+ * @removed
*/
public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4;
@@ -119,7 +139,7 @@ public final class CursorAnchorInfo implements Parcelable {
mSelectionEnd = source.readInt();
mComposingTextStart = source.readInt();
mComposingText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
- mInsertionMarkerClipped = (source.readInt() != 0);
+ mInsertionMarkerFlags = source.readInt();
mInsertionMarkerHorizontal = source.readFloat();
mInsertionMarkerTop = source.readFloat();
mInsertionMarkerBaseline = source.readFloat();
@@ -141,7 +161,7 @@ public final class CursorAnchorInfo implements Parcelable {
dest.writeInt(mSelectionEnd);
dest.writeInt(mComposingTextStart);
TextUtils.writeToParcel(mComposingText, dest, flags);
- dest.writeInt(mInsertionMarkerClipped ? 1 : 0);
+ dest.writeInt(mInsertionMarkerFlags);
dest.writeFloat(mInsertionMarkerHorizontal);
dest.writeFloat(mInsertionMarkerTop);
dest.writeFloat(mInsertionMarkerBaseline);
@@ -159,7 +179,7 @@ public final class CursorAnchorInfo implements Parcelable {
+ mInsertionMarkerBaseline + mInsertionMarkerBottom;
int hash = floatHash > 0 ? (int) floatHash : (int)(-floatHash);
hash *= 31;
- hash += (mInsertionMarkerClipped ? 2 : 1);
+ hash += mInsertionMarkerFlags;
hash *= 31;
hash += mSelectionStart + mSelectionEnd + mComposingTextStart;
hash *= 31;
@@ -204,16 +224,13 @@ public final class CursorAnchorInfo implements Parcelable {
|| !Objects.equals(mComposingText, that.mComposingText)) {
return false;
}
- if (mInsertionMarkerClipped != that.mInsertionMarkerClipped
+ if (mInsertionMarkerFlags != that.mInsertionMarkerFlags
|| !areSameFloatImpl(mInsertionMarkerHorizontal, that.mInsertionMarkerHorizontal)
|| !areSameFloatImpl(mInsertionMarkerTop, that.mInsertionMarkerTop)
|| !areSameFloatImpl(mInsertionMarkerBaseline, that.mInsertionMarkerBaseline)
|| !areSameFloatImpl(mInsertionMarkerBottom, that.mInsertionMarkerBottom)) {
return false;
}
- if (!Objects.equals(mComposingTextStart, that.mComposingTextStart)) {
- return false;
- }
if (!Objects.equals(mCharacterRects, that.mCharacterRects)) {
return false;
}
@@ -228,7 +245,7 @@ public final class CursorAnchorInfo implements Parcelable {
return "SelectionInfo{mSelection=" + mSelectionStart + "," + mSelectionEnd
+ " mComposingTextStart=" + mComposingTextStart
+ " mComposingText=" + Objects.toString(mComposingText)
- + " mInsertionMarkerClipped=" + mInsertionMarkerClipped
+ + " mInsertionMarkerFlags=" + mInsertionMarkerFlags
+ " mInsertionMarkerHorizontal=" + mInsertionMarkerHorizontal
+ " mInsertionMarkerTop=" + mInsertionMarkerTop
+ " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline
@@ -275,6 +292,20 @@ public final class CursorAnchorInfo implements Parcelable {
private CharSequence mComposingText = null;
/**
+ * @removed
+ */
+ public Builder setInsertionMarkerLocation(final float horizontalPosition,
+ final float lineTop, final float lineBaseline, final float lineBottom,
+ final boolean clipped){
+ mInsertionMarkerHorizontal = horizontalPosition;
+ mInsertionMarkerTop = lineTop;
+ mInsertionMarkerBaseline = lineBaseline;
+ mInsertionMarkerBottom = lineBottom;
+ mInsertionMarkerFlags = clipped ? FLAG_HAS_INVISIBLE_REGION : 0;
+ return this;
+ }
+
+ /**
* Sets the location of the text insertion point (zero width cursor) as a rectangle in
* local coordinates. Calling this can be skipped when there is no text insertion point;
* however if there is an insertion point, editors must call this method.
@@ -291,24 +322,24 @@ public final class CursorAnchorInfo implements Parcelable {
* @param lineBottom vertical position of the insertion marker, in the local coordinates
* that will be transformed with the transformation matrix when rendered on the screen. This
* should be calculated or compatible with {@link Layout#getLineBottom(int)}.
- * @param clipped {@code true} is the insertion marker is partially or entierly clipped by
- * other UI elements.
+ * @param flags flags of the insertion marker. See {@link #FLAG_HAS_VISIBLE_REGION} for
+ * example.
*/
public Builder setInsertionMarkerLocation(final float horizontalPosition,
final float lineTop, final float lineBaseline, final float lineBottom,
- final boolean clipped){
+ final int flags){
mInsertionMarkerHorizontal = horizontalPosition;
mInsertionMarkerTop = lineTop;
mInsertionMarkerBaseline = lineBaseline;
mInsertionMarkerBottom = lineBottom;
- mInsertionMarkerClipped = clipped;
+ mInsertionMarkerFlags = flags;
return this;
}
private float mInsertionMarkerHorizontal = Float.NaN;
private float mInsertionMarkerTop = Float.NaN;
private float mInsertionMarkerBaseline = Float.NaN;
private float mInsertionMarkerBottom = Float.NaN;
- private boolean mInsertionMarkerClipped = false;
+ private int mInsertionMarkerFlags = 0;
/**
* Adds the bounding box of the character specified with the index.
@@ -323,8 +354,8 @@ public final class CursorAnchorInfo implements Parcelable {
* coordinates, that is, right edge for LTR text and left edge for RTL text.
* @param trailingEdgeY y coordinate of the trailing edge of the character in local
* coordinates.
- * @param flags type and flags for this character. See
- * {@link #CHARACTER_RECT_TYPE_FULLY_VISIBLE} for example.
+ * @param flags flags for this character rect. See {@link #FLAG_HAS_VISIBLE_REGION} for
+ * example.
* @throws IllegalArgumentException If the index is a negative value, or not greater than
* all of the previously called indices.
*/
@@ -334,11 +365,6 @@ public final class CursorAnchorInfo implements Parcelable {
if (index < 0) {
throw new IllegalArgumentException("index must not be a negative integer.");
}
- final int type = flags & CHARACTER_RECT_TYPE_MASK;
- if (type == CHARACTER_RECT_TYPE_UNSPECIFIED) {
- throw new IllegalArgumentException("Type except for "
- + "CHARACTER_RECT_TYPE_UNSPECIFIED must be specified.");
- }
if (mCharacterRectBuilder == null) {
mCharacterRectBuilder = new SparseRectFArrayBuilder();
}
@@ -391,7 +417,7 @@ public final class CursorAnchorInfo implements Parcelable {
mSelectionEnd = -1;
mComposingTextStart = -1;
mComposingText = null;
- mInsertionMarkerClipped = false;
+ mInsertionMarkerFlags = 0;
mInsertionMarkerHorizontal = Float.NaN;
mInsertionMarkerTop = Float.NaN;
mInsertionMarkerBaseline = Float.NaN;
@@ -409,7 +435,7 @@ public final class CursorAnchorInfo implements Parcelable {
mSelectionEnd = builder.mSelectionEnd;
mComposingTextStart = builder.mComposingTextStart;
mComposingText = builder.mComposingText;
- mInsertionMarkerClipped = builder.mInsertionMarkerClipped;
+ mInsertionMarkerFlags = builder.mInsertionMarkerFlags;
mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal;
mInsertionMarkerTop = builder.mInsertionMarkerTop;
mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline;
@@ -452,11 +478,20 @@ public final class CursorAnchorInfo implements Parcelable {
}
/**
+ * Returns the flag of the insertion marker.
+ * @return the flag of the insertion marker. {@code 0} if no flag is specified.
+ */
+ public int getInsertionMarkerFlags() {
+ return mInsertionMarkerFlags;
+ }
+
+ /**
* Returns the visibility of the insertion marker.
* @return {@code true} if the insertion marker is partially or entirely clipped.
+ * @removed
*/
public boolean isInsertionMarkerClipped() {
- return mInsertionMarkerClipped;
+ return (mInsertionMarkerFlags & FLAG_HAS_VISIBLE_REGION) != 0;
}
/**
@@ -525,17 +560,17 @@ public final class CursorAnchorInfo implements Parcelable {
}
/**
- * Returns the flags associated with the character specified with the index.
+ * Returns the flags associated with the character rect specified with the index.
* @param index index of the character in a Java chars.
- * @return {@link #CHARACTER_RECT_TYPE_UNSPECIFIED} if no flag is specified.
+ * @return {@code 0} if no flag is specified.
*/
// TODO: Prepare a document about the expected behavior for surrogate pairs, combining
// characters, and non-graphical chars.
public int getCharacterRectFlags(final int index) {
if (mCharacterRects == null) {
- return CHARACTER_RECT_TYPE_UNSPECIFIED;
+ return 0;
}
- return mCharacterRects.getFlags(index, CHARACTER_RECT_TYPE_UNSPECIFIED);
+ return mCharacterRects.getFlags(index, 0);
}
/**
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index ca094c1..093fb2f 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -728,31 +728,47 @@ public interface InputConnection {
* 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}.
+ * used together with {@link #CURSOR_UPDATE_MONITOR}.
*/
- public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE = 1 << 0;
+ public static final int CURSOR_UPDATE_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.
+ * {@link InputConnection#requestCursorUpdates(int)} again with this flag off.
* <p>
- * This flag can be used together with {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE}.
+ * This flag can be used together with {@link #CURSOR_UPDATE_IMMEDIATE}.
* </p>
*/
- public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR = 1 << 1;
+ public static final int CURSOR_UPDATE_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 cursorUpdateMode {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE} and/or
- * {@link #REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR}
+ * @param cursorUpdateMode {@link #CURSOR_UPDATE_IMMEDIATE} and/or
+ * {@link #CURSOR_UPDATE_MONITOR}. Pass {@code 0} to disable the effect of
+ * {@link #CURSOR_UPDATE_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 boolean requestCursorUpdates(int cursorUpdateMode);
+
+ /**
+ * @removed
+ */
+ public static final int REQUEST_UPDATE_CURSOR_UPDATE_IMMEDIATE = 1 << 0;
+
+ /**
+ * @removed
+ */
+ public static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR = 1 << 1;
+
+ /**
+ * @removed
+ */
public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode);
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index d95df25..87853de 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -126,7 +126,14 @@ public class InputConnectionWrapper implements InputConnection {
return mTarget.performPrivateCommand(action, data);
}
- public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
- return mTarget.requestUpdateCursorAnchorInfo(cursorUpdateMode);
+ public boolean requestCursorUpdates(int cursorUpdateMode) {
+ return mTarget.requestCursorUpdates(cursorUpdateMode);
}
- }
+
+ /**
+ * @removed
+ */
+ public final boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
+ return mTarget.requestCursorUpdates(cursorUpdateMode);
+ }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0a472c7..b56378f 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1526,7 +1526,7 @@ public final class InputMethodManager {
* Return true if the current input method wants to watch the location
* of the input editor's cursor in its window.
*
- * @deprecated Use {@link InputConnection#requestUpdateCursorAnchorInfo(int)} instead.
+ * @deprecated Use {@link InputConnection#requestCursorUpdates(int)} instead.
*/
@Deprecated
public boolean isWatchingCursor(View view) {
@@ -1542,9 +1542,9 @@ public final class InputMethodManager {
public boolean isCursorAnchorInfoEnabled() {
synchronized (mH) {
final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode &
- InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0;
+ InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0;
final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode &
- InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR) != 0;
+ InputConnection.CURSOR_UPDATE_MONITOR) != 0;
return isImmediate || isMonitoring;
}
}
@@ -1608,7 +1608,7 @@ public final class InputMethodManager {
// If immediate bit is set, we will call updateCursorAnchorInfo() even when the data has
// not been changed from the previous call.
final boolean isImmediate = (mRequestUpdateCursorAnchorInfoMonitorMode &
- InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0;
+ InputConnection.CURSOR_UPDATE_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.
@@ -1624,7 +1624,7 @@ public final class InputMethodManager {
mCursorAnchorInfo = cursorAnchorInfo;
// Clear immediate bit (if any).
mRequestUpdateCursorAnchorInfoMonitorMode &=
- ~InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE;
+ ~InputConnection.CURSOR_UPDATE_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 eb93745..eef8554 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -5717,8 +5717,16 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
@Override
+ public boolean requestCursorUpdates(int cursorUpdateMode) {
+ return getTarget().requestCursorUpdates(cursorUpdateMode);
+ }
+
+ /**
+ * @removed
+ */
+ @Override
public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
- return getTarget().requestUpdateCursorAnchorInfo(cursorUpdateMode);
+ return getTarget().requestCursorUpdates(cursorUpdateMode);
}
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 1da22ca..b9f891c 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -297,10 +297,10 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
public boolean performItemClick(View view, int position, long id) {
if (mOnItemClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
+ mOnItemClickListener.onItemClick(this, view, position, id);
if (view != null) {
view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
}
- mOnItemClickListener.onItemClick(this, view, position, id);
return true;
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 46b225d..22138d0 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3089,13 +3089,12 @@ public class Editor {
final boolean isLeadingEdgeTopVisible = isPositionVisible(leadingEdgeX, top);
final boolean isTrailingEdgeBottomVisible =
isPositionVisible(trailingEdgeX, bottom);
- final int characterRectFlags;
- if (isLeadingEdgeTopVisible && isTrailingEdgeBottomVisible) {
- characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_FULLY_VISIBLE;
- } else if (isLeadingEdgeTopVisible || isTrailingEdgeBottomVisible) {
- characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE;
- } else {
- characterRectFlags = CursorAnchorInfo.CHARACTER_RECT_TYPE_INVISIBLE;
+ int characterRectFlags = 0;
+ if (isLeadingEdgeTopVisible || isTrailingEdgeBottomVisible) {
+ characterRectFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
+ }
+ if (!isLeadingEdgeTopVisible || !isTrailingEdgeBottomVisible) {
+ characterRectFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
}
// Here offset is the index in Java chars.
// TODO: We must have a well-defined specification. For example, how
@@ -3117,11 +3116,19 @@ public class Editor {
+ viewportToContentVerticalOffset;
final float insertionMarkerBottom = layout.getLineBottom(line)
+ viewportToContentVerticalOffset;
- // Take TextView's padding and scroll into account.
- final boolean isClipped = !isPositionVisible(insertionMarkerX, insertionMarkerTop)
- || !isPositionVisible(insertionMarkerX, insertionMarkerBottom);
+ final boolean isTopVisible =
+ isPositionVisible(insertionMarkerX, insertionMarkerTop);
+ final boolean isBottomVisible =
+ isPositionVisible(insertionMarkerX, insertionMarkerBottom);
+ int insertionMarkerFlags = 0;
+ if (isTopVisible || isBottomVisible) {
+ insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
+ }
+ if (!isTopVisible || !isBottomVisible) {
+ insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
+ }
builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop,
- insertionMarkerBaseline, insertionMarkerBottom, isClipped);
+ insertionMarkerBaseline, insertionMarkerBottom, insertionMarkerFlags);
}
imm.updateCursorAnchorInfo(mTextView, builder.build());
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 05ff151..69d5f40 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -864,7 +864,7 @@ public class RemoteViews implements Parcelable, Filter {
if (alpha != -1) {
targetDrawable.setAlpha(alpha);
}
- if (colorFilter != -1 && filterMode != null) {
+ if (filterMode != null) {
targetDrawable.setColorFilter(colorFilter, filterMode);
}
if (level != -1) {
@@ -2189,8 +2189,8 @@ public class RemoteViews implements Parcelable, Filter {
* @param alpha Specify an alpha value for the drawable, or -1 to leave
* unchanged.
* @param colorFilter Specify a color for a
- * {@link android.graphics.ColorFilter} for this drawable, or -1
- * to leave unchanged.
+ * {@link android.graphics.ColorFilter} for this drawable. This will be ignored if
+ * {@code mode} is {@code null}.
* @param mode Specify a PorterDuff mode for this drawable, or null to leave
* unchanged.
* @param level Specify the level for the drawable, or -1 to leave
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9b3a1e0..3e1b674 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1861,6 +1861,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return getCompoundPaddingTop();
}
+ if (mLayout == null) {
+ assumeLayout();
+ }
+
if (mLayout.getLineCount() <= mMaximum) {
return getCompoundPaddingTop();
}
@@ -1894,6 +1898,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return getCompoundPaddingBottom();
}
+ if (mLayout == null) {
+ assumeLayout();
+ }
+
if (mLayout.getLineCount() <= mMaximum) {
return getCompoundPaddingBottom();
}
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index ece8aa4..3ba03b8 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -248,11 +248,12 @@ public class Toolbar extends ViewGroup {
final Drawable navIcon = a.getDrawable(R.styleable.Toolbar_navigationIcon);
if (navIcon != null) {
setNavigationIcon(navIcon);
- final CharSequence navDesc = a.getText(
- R.styleable.Toolbar_navigationContentDescription);
- if (!TextUtils.isEmpty(navDesc)) {
- setNavigationContentDescription(navDesc);
- }
+ }
+
+ final CharSequence navDesc = a.getText(
+ R.styleable.Toolbar_navigationContentDescription);
+ if (!TextUtils.isEmpty(navDesc)) {
+ setNavigationContentDescription(navDesc);
}
a.recycle();
}
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index cb0c3d0..572cca2 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -253,6 +253,10 @@ public class VideoView extends SurfaceView
*
* @param uri the URI of the video.
* @param headers the headers for the URI request.
+ * Note that the cross domain redirection is allowed by default, but that can be
+ * changed with key/value pairs through the headers parameter with
+ * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
+ * to disallow or allow cross domain redirection.
*/
public void setVideoURI(Uri uri, Map<String, String> headers) {
mUri = uri;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 61b4567..b6e7353 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -23,7 +23,6 @@ import android.app.usage.UsageStatsManager;
import android.os.AsyncTask;
import android.provider.Settings;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.Slog;
import android.widget.AbsListView;
import android.widget.GridView;
@@ -73,6 +72,7 @@ import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -100,7 +100,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
private boolean mResolvingHome = false;
private UsageStatsManager mUsm;
- private ArrayMap<String, UsageStats> mStats;
+ private Map<String, UsageStats> mStats;
private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
private boolean mRegistered;
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index abe8a9f..6f1c7ec 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -22,6 +22,7 @@ import android.app.ActionBar;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
import android.view.ActionMode;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -32,6 +33,7 @@ import android.view.Window;
import android.view.WindowCallbackWrapper;
import android.widget.SpinnerAdapter;
import android.widget.Toolbar;
+import com.android.internal.R;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.widget.DecorToolbar;
import com.android.internal.widget.ToolbarWidgetWrapper;
@@ -44,6 +46,8 @@ public class ToolbarActionBar extends ActionBar {
private boolean mToolbarMenuPrepared;
private Window.Callback mWindowCallback;
+ private CharSequence mHomeDescription;
+
private boolean mLastMenuVisibility;
private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
new ArrayList<OnMenuVisibilityListener>();
@@ -70,6 +74,8 @@ public class ToolbarActionBar extends ActionBar {
mDecorToolbar.setWindowCallback(mWindowCallback);
toolbar.setOnMenuItemClickListener(mMenuClicker);
mDecorToolbar.setWindowTitle(title);
+ mHomeDescription = mToolbar.getNavigationContentDescription();
+ updateNavDescription();
}
public Window.Callback getWrappedWindowCallback() {
@@ -161,6 +167,7 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void setHomeActionContentDescription(CharSequence description) {
mToolbar.setNavigationContentDescription(description);
+ mHomeDescription = description;
}
@Override
@@ -171,6 +178,7 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void setHomeActionContentDescription(int resId) {
mToolbar.setNavigationContentDescription(resId);
+ mHomeDescription = mToolbar.getNavigationContentDescription();
}
@Override
@@ -247,8 +255,22 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void setDisplayOptions(@DisplayOptions int options, @DisplayOptions int mask) {
- mDecorToolbar.setDisplayOptions((options & mask) |
- mDecorToolbar.getDisplayOptions() & ~mask);
+ final int currentOptions = mDecorToolbar.getDisplayOptions();
+ final int changed = (options ^ currentOptions) & mask;
+ mDecorToolbar.setDisplayOptions(options & mask | currentOptions & ~mask);
+ if ((changed & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+ updateNavDescription();
+ }
+ }
+
+ private void updateNavDescription() {
+ if ((mDecorToolbar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+ if (TextUtils.isEmpty(mHomeDescription)) {
+ mToolbar.setNavigationContentDescription(R.string.action_bar_up_description);
+ } else {
+ mToolbar.setNavigationContentDescription(mHomeDescription);
+ }
+ }
}
@Override
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index b1f5d90..e19b2b6 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -437,7 +437,7 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
return;
}
args.callback.setRequestUpdateCursorAnchorInfoResult(
- ic.requestUpdateCursorAnchorInfo(msg.arg1), args.seq);
+ ic.requestCursorUpdates(msg.arg1), args.seq);
} catch (RemoteException e) {
Log.w(TAG, "Got RemoteException calling requestCursorAnchorInfo", e);
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index a8526c8..0c65ad1 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -428,7 +428,7 @@ public class InputConnectionWrapper implements InputConnection {
}
}
- public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
+ public boolean requestCursorUpdates(int cursorUpdateMode) {
boolean result = false;
try {
InputContextCallback callback = InputContextCallback.getInstance();
@@ -445,4 +445,11 @@ public class InputConnectionWrapper implements InputConnection {
}
return result;
}
+
+ /**
+ * @removed
+ */
+ public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
+ return requestCursorUpdates(cursorUpdateMode);
+ }
}
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index ba236f3..f211ff2 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -188,13 +188,13 @@ public class EditableInputConnection extends BaseInputConnection {
}
@Override
- public boolean requestUpdateCursorAnchorInfo(int cursorUpdateMode) {
+ public boolean requestCursorUpdates(int cursorUpdateMode) {
if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode);
// It is possible that any other bit is used as a valid flag in a future release.
// We should reject the entire request in such a case.
- final int KNOWN_FLAGS_MASK = InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE |
- InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_MONITOR;
+ final int KNOWN_FLAGS_MASK = InputConnection.CURSOR_UPDATE_IMMEDIATE |
+ InputConnection.CURSOR_UPDATE_MONITOR;
final int unknownFlags = cursorUpdateMode & ~KNOWN_FLAGS_MASK;
if (unknownFlags != 0) {
if (DEBUG) {
@@ -212,7 +212,7 @@ public class EditableInputConnection extends BaseInputConnection {
return false;
}
mIMM.setUpdateCursorAnchorInfoMode(cursorUpdateMode);
- if ((cursorUpdateMode & InputConnection.REQUEST_UPDATE_CURSOR_ANCHOR_INFO_IMMEDIATE) != 0) {
+ if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_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
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 71cf391..2114ff6 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -862,14 +862,23 @@ public class LockPatternUtils {
* @return stored password quality
*/
public int getKeyguardStoredPasswordQuality() {
- int quality =
- (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+ return getKeyguardStoredPasswordQuality(getCurrentOrCallingUserId());
+ }
+
+ /**
+ * Retrieves the quality mode for {@param userHandle}.
+ * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
+ *
+ * @return stored password quality
+ */
+ public int getKeyguardStoredPasswordQuality(int userHandle) {
+ int quality = (int) getLong(PASSWORD_TYPE_KEY,
+ DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
// If the user has chosen to use weak biometric sensor, then return the backup locking
// method and treat biometric as a special case.
if (quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
- quality =
- (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+ quality = (int) getLong(PASSWORD_TYPE_ALTERNATE_KEY,
+ DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
}
return quality;
}