summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/svc/src/com/android/commands/svc/PowerCommand.java2
-rw-r--r--core/java/android/animation/Animator.java15
-rw-r--r--core/java/android/animation/AnimatorSet.java929
-rw-r--r--core/java/android/animation/ValueAnimator.java12
-rw-r--r--core/java/android/annotation/IntRange.java3
-rw-r--r--core/java/android/content/Intent.java13
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java22
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java14
-rw-r--r--core/java/android/os/IPowerManager.aidl2
-rw-r--r--core/java/android/os/PowerManager.java13
-rw-r--r--core/java/android/os/Trace.java2
-rw-r--r--core/java/android/provider/Settings.java6
-rw-r--r--core/java/android/view/RenderNodeAnimator.java8
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java11
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java11
-rw-r--r--core/java/com/android/internal/app/ShutdownActivity.java7
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java28
-rw-r--r--core/jni/android_hardware_camera2_CameraMetadata.cpp167
-rw-r--r--core/res/res/values-fa/strings.xml4
-rw-r--r--core/res/res/values-fr/strings.xml2
-rw-r--r--core/res/res/values-iw/strings.xml4
-rw-r--r--core/res/res/values-ky-rKG/strings.xml2
-rw-r--r--core/res/res/values-nb/strings.xml2
-rw-r--r--core/res/res/values/colors_material.xml3
-rw-r--r--core/res/res/values/themes_material.xml12
-rw-r--r--libs/androidfw/AssetManager.cpp6
-rw-r--r--media/java/android/media/MediaCodec.java142
-rw-r--r--media/java/android/media/MediaCodecInfo.java26
-rw-r--r--media/java/android/media/MediaCodecList.java14
-rw-r--r--media/java/android/media/Ringtone.java3
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java3
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java29
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java38
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml6
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml2
-rw-r--r--packages/SystemUI/res/values-uz-rUZ/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java33
-rw-r--r--services/core/java/com/android/server/AppOpsService.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/am/RecentTasks.java10
-rw-r--r--services/core/java/com/android/server/location/GpsLocationProvider.java6
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java188
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java15
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java25
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java4
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java2
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java17
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java11
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.pngbin9786 -> 5188 bytes
-rw-r--r--tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.pngbin636 -> 566 bytes
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java14
54 files changed, 1246 insertions, 660 deletions
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index 2754f2d270bd..6ce29cb24bc6 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -93,7 +93,7 @@ public class PowerCommand extends Svc.Command {
} else if ("shutdown".equals(args[1])) {
try {
// no confirm, wait till device is off
- pm.shutdown(false, true);
+ pm.shutdown(false, null, true);
} catch (RemoteException e) {
System.err.println("Failed to shutdown.");
}
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index aa1be9a6a946..d331c2a066c4 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -27,6 +27,11 @@ import java.util.ArrayList;
public abstract class Animator implements Cloneable {
/**
+ * The value used to indicate infinite duration (e.g. when Animators repeat infinitely).
+ * @hide
+ */
+ public static final long DURATION_INFINITE = -1;
+ /**
* The set of listeners to be sent events through the life of an animation.
*/
ArrayList<AnimatorListener> mListeners = null;
@@ -184,6 +189,16 @@ public abstract class Animator implements Cloneable {
public abstract long getDuration();
/**
+ * Gets the total duration of the animation, accounting for animation sequences, start delay,
+ * and repeating. Return {@link #DURATION_INFINITE} if the duration is infinite.
+ * @hide
+ * TODO: Unhide
+ */
+ public long getTotalDuration() {
+ return getStartDelay() + getDuration();
+ }
+
+ /**
* The time interpolator used in calculating the elapsed fraction of the
* animation. The interpolator determines whether the animation runs with
* linear or non-linear motion, such as acceleration and deceleration. The
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 951fe49cbd9e..5480193a8c34 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -17,6 +17,7 @@
package android.animation;
import android.util.ArrayMap;
+import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
@@ -50,6 +51,7 @@ import java.util.List;
*/
public final class AnimatorSet extends Animator {
+ private static final String TAG = "AnimatorSet";
/**
* Internal variables
* NOTE: This object implements the clone() method, making a deep copy of any referenced
@@ -79,20 +81,10 @@ public final class AnimatorSet extends Animator {
private ArrayList<Node> mNodes = new ArrayList<Node>();
/**
- * The sorted list of nodes. This is the order in which the animations will
- * be played. The details about when exactly they will be played depend
- * on the dependency relationships of the nodes.
+ * Animator Listener that tracks the lifecycle of each Animator in the set. It will be added
+ * to each Animator before they start and removed after they end.
*/
- private ArrayList<Node> mSortedNodes = new ArrayList<Node>();
-
- /**
- * Flag indicating whether the nodes should be sorted prior to playing. This
- * flag allows us to cache the previous sorted nodes so that if the sequence
- * is replayed with no changes, it does not have to re-sort the nodes again.
- */
- private boolean mNeedsSort = true;
-
- private AnimatorSetListener mSetListener = null;
+ private AnimatorSetListener mSetListener = new AnimatorSetListener(this);
/**
* Flag indicating that the AnimatorSet has been manually
@@ -101,7 +93,13 @@ public final class AnimatorSet extends Animator {
* child animations of this AnimatorSet end. It also determines whether cancel/end
* notifications are sent out via the normal AnimatorSetListener mechanism.
*/
- boolean mTerminated = false;
+ private boolean mTerminated = false;
+
+ /**
+ * Tracks whether any change has been made to the AnimatorSet, which is then used to
+ * determine whether the dependency graph should be re-constructed.
+ */
+ private boolean mDependencyDirty = false;
/**
* Indicates whether an AnimatorSet has been start()'d, whether or
@@ -113,8 +111,13 @@ public final class AnimatorSet extends Animator {
private long mStartDelay = 0;
// Animator used for a nonzero startDelay
- private ValueAnimator mDelayAnim = null;
+ private ValueAnimator mDelayAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(0);
+ // Root of the dependency tree of all the animators in the set. In this tree, parent-child
+ // relationship captures the order of animation (i.e. parent and child will play sequentially),
+ // and sibling relationship indicates "with" relationship, as sibling animators start at the
+ // same time.
+ private Node mRootNode = new Node(mDelayAnim);
// How long the child animations should last in ms. The default value is negative, which
// simply means that there is no duration set on the AnimatorSet. When a real duration is
@@ -125,7 +128,17 @@ public final class AnimatorSet extends Animator {
// was set on this AnimatorSet, so it should not be passed down to the children.
private TimeInterpolator mInterpolator = null;
+ // Whether the AnimatorSet can be reversed.
private boolean mReversible = true;
+ // The total duration of finishing all the Animators in the set.
+ private long mTotalDuration = 0;
+
+ public AnimatorSet() {
+ super();
+ mNodeMap.put(mDelayAnim, mRootNode);
+ mNodes.add(mRootNode);
+ }
+
/**
* Sets up this AnimatorSet to play all of the supplied animations at the same time.
* This is equivalent to calling {@link #play(Animator)} with the first animator in the
@@ -139,7 +152,6 @@ public final class AnimatorSet extends Animator {
*/
public void playTogether(Animator... items) {
if (items != null) {
- mNeedsSort = true;
Builder builder = play(items[0]);
for (int i = 1; i < items.length; ++i) {
builder.with(items[i]);
@@ -154,7 +166,6 @@ public final class AnimatorSet extends Animator {
*/
public void playTogether(Collection<Animator> items) {
if (items != null && items.size() > 0) {
- mNeedsSort = true;
Builder builder = null;
for (Animator anim : items) {
if (builder == null) {
@@ -174,13 +185,12 @@ public final class AnimatorSet extends Animator {
*/
public void playSequentially(Animator... items) {
if (items != null) {
- mNeedsSort = true;
if (items.length == 1) {
play(items[0]);
} else {
mReversible = false;
for (int i = 0; i < items.length - 1; ++i) {
- play(items[i]).before(items[i+1]);
+ play(items[i]).before(items[i + 1]);
}
}
}
@@ -194,13 +204,12 @@ public final class AnimatorSet extends Animator {
*/
public void playSequentially(List<Animator> items) {
if (items != null && items.size() > 0) {
- mNeedsSort = true;
if (items.size() == 1) {
play(items.get(0));
} else {
mReversible = false;
for (int i = 0; i < items.size() - 1; ++i) {
- play(items.get(i)).before(items.get(i+1));
+ play(items.get(i)).before(items.get(i + 1));
}
}
}
@@ -216,8 +225,10 @@ public final class AnimatorSet extends Animator {
*/
public ArrayList<Animator> getChildAnimations() {
ArrayList<Animator> childList = new ArrayList<Animator>();
- for (Node node : mNodes) {
- childList.add(node.animation);
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ childList.add(node.mAnimation);
}
return childList;
}
@@ -231,8 +242,10 @@ public final class AnimatorSet extends Animator {
*/
@Override
public void setTarget(Object target) {
- for (Node node : mNodes) {
- Animator animation = node.animation;
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ Animator animation = node.mAnimation;
if (animation instanceof AnimatorSet) {
((AnimatorSet)animation).setTarget(target);
} else if (animation instanceof ObjectAnimator) {
@@ -249,7 +262,7 @@ public final class AnimatorSet extends Animator {
int conf = super.getChangingConfigurations();
final int nodeCount = mNodes.size();
for (int i = 0; i < nodeCount; i ++) {
- conf |= mNodes.get(i).animation.getChangingConfigurations();
+ conf |= mNodes.get(i).mAnimation.getChangingConfigurations();
}
return conf;
}
@@ -303,7 +316,6 @@ public final class AnimatorSet extends Animator {
*/
public Builder play(Animator anim) {
if (anim != null) {
- mNeedsSort = true;
return new Builder(anim);
}
return null;
@@ -323,22 +335,20 @@ public final class AnimatorSet extends Animator {
ArrayList<AnimatorListener> tmpListeners = null;
if (mListeners != null) {
tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
- for (AnimatorListener listener : tmpListeners) {
- listener.onAnimationCancel(this);
+ int size = tmpListeners.size();
+ for (int i = 0; i < size; i++) {
+ tmpListeners.get(i).onAnimationCancel(this);
}
}
- if (mDelayAnim != null && mDelayAnim.isRunning()) {
- // If we're currently in the startDelay period, just cancel that animator and
- // send out the end event to all listeners
- mDelayAnim.cancel();
- } else if (mSortedNodes.size() > 0) {
- for (Node node : mSortedNodes) {
- node.animation.cancel();
- }
+ ArrayList<Animator> playingSet = new ArrayList<>(mPlayingSet);
+ int setSize = playingSet.size();
+ for (int i = 0; i < setSize; i++) {
+ playingSet.get(i).cancel();
}
if (tmpListeners != null) {
- for (AnimatorListener listener : tmpListeners) {
- listener.onAnimationEnd(this);
+ int size = tmpListeners.size();
+ for (int i = 0; i < size; i++) {
+ tmpListeners.get(i).onAnimationEnd(this);
}
}
mStarted = false;
@@ -355,35 +365,45 @@ public final class AnimatorSet extends Animator {
public void end() {
mTerminated = true;
if (isStarted()) {
- if (mSortedNodes.size() != mNodes.size()) {
- // hasn't been started yet - sort the nodes now, then end them
- sortNodes();
- for (Node node : mSortedNodes) {
- if (mSetListener == null) {
- mSetListener = new AnimatorSetListener(this);
- }
- node.animation.addListener(mSetListener);
- }
- }
- if (mDelayAnim != null) {
- mDelayAnim.cancel();
- }
- if (mSortedNodes.size() > 0) {
- for (Node node : mSortedNodes) {
- node.animation.end();
- }
+ endRemainingAnimations();
+ }
+ if (mListeners != null) {
+ ArrayList<AnimatorListener> tmpListeners =
+ (ArrayList<AnimatorListener>) mListeners.clone();
+ for (int i = 0; i < tmpListeners.size(); i++) {
+ tmpListeners.get(i).onAnimationEnd(this);
}
- if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- for (AnimatorListener listener : tmpListeners) {
- listener.onAnimationEnd(this);
+ }
+ mStarted = false;
+ }
+
+ /**
+ * Iterate the animations that haven't finished or haven't started, and end them.
+ */
+ private void endRemainingAnimations() {
+ ArrayList<Animator> remainingList = new ArrayList<Animator>(mNodes.size());
+ remainingList.addAll(mPlayingSet);
+
+ int index = 0;
+ while (index < remainingList.size()) {
+ Animator anim = remainingList.get(index);
+ anim.end();
+ index++;
+ Node node = mNodeMap.get(anim);
+ if (node.mChildNodes != null) {
+ int childSize = node.mChildNodes.size();
+ for (int i = 0; i < childSize; i++) {
+ Node child = node.mChildNodes.get(i);
+ if (child.mLatestParent != node) {
+ continue;
+ }
+ remainingList.add(child.mAnimation);
}
}
- mStarted = false;
}
}
+
/**
* Returns true if any of the child animations of this AnimatorSet have been started and have
* not yet ended.
@@ -391,8 +411,9 @@ public final class AnimatorSet extends Animator {
*/
@Override
public boolean isRunning() {
- for (Node node : mNodes) {
- if (node.animation.isRunning()) {
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ if (mNodes.get(i).mAnimation.isRunning()) {
return true;
}
}
@@ -426,7 +447,24 @@ public final class AnimatorSet extends Animator {
if (mStartDelay > 0) {
mReversible = false;
}
+ long delta = startDelay - mStartDelay;
mStartDelay = startDelay;
+ if (!mDependencyDirty) {
+ // Dependency graph already constructed, update all the nodes' start/end time
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ if (node == mRootNode) {
+ node.mEndTime = mStartDelay;
+ } else {
+ node.mStartTime = node.mStartTime == DURATION_INFINITE ?
+ DURATION_INFINITE : node.mStartTime + delta;
+ node.mEndTime = node.mEndTime == DURATION_INFINITE ?
+ DURATION_INFINITE : node.mEndTime + delta;
+
+ }
+ }
+ }
}
/**
@@ -455,6 +493,7 @@ public final class AnimatorSet extends Animator {
if (duration < 0) {
throw new IllegalArgumentException("duration must be a value of zero or greater");
}
+ mDependencyDirty = true;
// Just record the value for now - it will be used later when the AnimatorSet starts
mDuration = duration;
return this;
@@ -462,15 +501,19 @@ public final class AnimatorSet extends Animator {
@Override
public void setupStartValues() {
- for (Node node : mNodes) {
- node.animation.setupStartValues();
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ node.mAnimation.setupStartValues();
}
}
@Override
public void setupEndValues() {
- for (Node node : mNodes) {
- node.animation.setupEndValues();
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ node.mAnimation.setupEndValues();
}
}
@@ -482,8 +525,10 @@ public final class AnimatorSet extends Animator {
if (mDelayAnim != null) {
mDelayAnim.pause();
} else {
- for (Node node : mNodes) {
- node.animation.pause();
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ node.mAnimation.pause();
}
}
}
@@ -497,8 +542,10 @@ public final class AnimatorSet extends Animator {
if (mDelayAnim != null) {
mDelayAnim.resume();
} else {
- for (Node node : mNodes) {
- node.animation.resume();
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ node.mAnimation.resume();
}
}
}
@@ -518,96 +565,25 @@ public final class AnimatorSet extends Animator {
mStarted = true;
mPaused = false;
- for (Node node : mNodes) {
- node.animation.setAllowRunningAsynchronously(false);
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ node.mEnded = false;
+ node.mAnimation.setAllowRunningAsynchronously(false);
}
- if (mDuration >= 0) {
- // If the duration was set on this AnimatorSet, pass it along to all child animations
- for (Node node : mNodes) {
- // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to
- // insert "play-after" delays
- node.animation.setDuration(mDuration);
- }
- }
if (mInterpolator != null) {
- for (Node node : mNodes) {
- node.animation.setInterpolator(mInterpolator);
- }
- }
- // First, sort the nodes (if necessary). This will ensure that sortedNodes
- // contains the animation nodes in the correct order.
- sortNodes();
-
- int numSortedNodes = mSortedNodes.size();
- for (int i = 0; i < numSortedNodes; ++i) {
- Node node = mSortedNodes.get(i);
- // First, clear out the old listeners
- ArrayList<AnimatorListener> oldListeners = node.animation.getListeners();
- if (oldListeners != null && oldListeners.size() > 0) {
- final ArrayList<AnimatorListener> clonedListeners = new
- ArrayList<AnimatorListener>(oldListeners);
-
- for (AnimatorListener listener : clonedListeners) {
- if (listener instanceof DependencyListener ||
- listener instanceof AnimatorSetListener) {
- node.animation.removeListener(listener);
- }
- }
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ node.mAnimation.setInterpolator(mInterpolator);
}
}
- // nodesToStart holds the list of nodes to be started immediately. We don't want to
- // start the animations in the loop directly because we first need to set up
- // dependencies on all of the nodes. For example, we don't want to start an animation
- // when some other animation also wants to start when the first animation begins.
- final ArrayList<Node> nodesToStart = new ArrayList<Node>();
- for (int i = 0; i < numSortedNodes; ++i) {
- Node node = mSortedNodes.get(i);
- if (mSetListener == null) {
- mSetListener = new AnimatorSetListener(this);
- }
- if (node.dependencies == null || node.dependencies.size() == 0) {
- nodesToStart.add(node);
- } else {
- int numDependencies = node.dependencies.size();
- for (int j = 0; j < numDependencies; ++j) {
- Dependency dependency = node.dependencies.get(j);
- dependency.node.animation.addListener(
- new DependencyListener(this, node, dependency.rule));
- }
- node.tmpDependencies = (ArrayList<Dependency>) node.dependencies.clone();
- }
- node.animation.addListener(mSetListener);
- }
+ updateAnimatorsDuration();
+ createDependencyGraph();
+
// Now that all dependencies are set up, start the animations that should be started.
- if (mStartDelay <= 0) {
- for (Node node : nodesToStart) {
- node.animation.start();
- mPlayingSet.add(node.animation);
- }
- } else {
- mDelayAnim = ValueAnimator.ofFloat(0f, 1f);
- mDelayAnim.setDuration(mStartDelay);
- mDelayAnim.addListener(new AnimatorListenerAdapter() {
- boolean canceled = false;
- public void onAnimationCancel(Animator anim) {
- canceled = true;
- }
- public void onAnimationEnd(Animator anim) {
- if (!canceled) {
- int numNodes = nodesToStart.size();
- for (int i = 0; i < numNodes; ++i) {
- Node node = nodesToStart.get(i);
- node.animation.start();
- mPlayingSet.add(node.animation);
- }
- }
- mDelayAnim = null;
- }
- });
- mDelayAnim.start();
- }
+ start(mRootNode);
if (mListeners != null) {
ArrayList<AnimatorListener> tmpListeners =
(ArrayList<AnimatorListener>) mListeners.clone();
@@ -631,6 +607,27 @@ public final class AnimatorSet extends Animator {
}
}
+ private void updateAnimatorsDuration() {
+ if (mDuration >= 0) {
+ // If the duration was set on this AnimatorSet, pass it along to all child animations
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to
+ // insert "play-after" delays
+ node.mAnimation.setDuration(mDuration);
+ }
+ }
+ mDelayAnim.setDuration(mStartDelay);
+ }
+
+ void start(final Node node) {
+ final Animator anim = node.mAnimation;
+ mPlayingSet.add(anim);
+ anim.addListener(mSetListener);
+ anim.start();
+ }
+
@Override
public AnimatorSet clone() {
final AnimatorSet anim = (AnimatorSet) super.clone();
@@ -643,15 +640,13 @@ public final class AnimatorSet extends Animator {
* and will populate any appropriate lists, when it is started.
*/
final int nodeCount = mNodes.size();
- anim.mNeedsSort = true;
anim.mTerminated = false;
anim.mStarted = false;
anim.mPlayingSet = new ArrayList<Animator>();
anim.mNodeMap = new ArrayMap<Animator, Node>();
anim.mNodes = new ArrayList<Node>(nodeCount);
- anim.mSortedNodes = new ArrayList<Node>(nodeCount);
anim.mReversible = mReversible;
- anim.mSetListener = null;
+ anim.mSetListener = new AnimatorSetListener(anim);
// Walk through the old nodes list, cloning each node and adding it to the new nodemap.
// One problem is that the old node dependencies point to nodes in the old AnimatorSet.
@@ -662,16 +657,10 @@ public final class AnimatorSet extends Animator {
Node nodeClone = node.clone();
node.mTmpClone = nodeClone;
anim.mNodes.add(nodeClone);
- anim.mNodeMap.put(nodeClone.animation, nodeClone);
- // Clear out the dependencies in the clone; we'll set these up manually later
- nodeClone.dependencies = null;
- nodeClone.tmpDependencies = null;
- nodeClone.nodeDependents = null;
- nodeClone.nodeDependencies = null;
-
- // clear out any listeners that were set up by the AnimatorSet; these will
- // be set up when the clone's nodes are sorted
- final ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
+ anim.mNodeMap.put(nodeClone.mAnimation, nodeClone);
+
+ // clear out any listeners that were set up by the AnimatorSet
+ final ArrayList<AnimatorListener> cloneListeners = nodeClone.mAnimation.getListeners();
if (cloneListeners != null) {
for (int i = cloneListeners.size() - 1; i >= 0; i--) {
final AnimatorListener listener = cloneListeners.get(i);
@@ -681,127 +670,37 @@ public final class AnimatorSet extends Animator {
}
}
}
+
+ anim.mRootNode = mRootNode.mTmpClone;
+ anim.mDelayAnim = (ValueAnimator) anim.mRootNode.mAnimation;
+
// Now that we've cloned all of the nodes, we're ready to walk through their
// dependencies, mapping the old dependencies to the new nodes
- for (int n = 0; n < nodeCount; n++) {
- final Node node = mNodes.get(n);
- final Node clone = node.mTmpClone;
- if (node.dependencies != null) {
- clone.dependencies = new ArrayList<Dependency>(node.dependencies.size());
- final int depSize = node.dependencies.size();
- for (int i = 0; i < depSize; i ++) {
- final Dependency dependency = node.dependencies.get(i);
- Dependency cloneDependency = new Dependency(dependency.node.mTmpClone,
- dependency.rule);
- clone.dependencies.add(cloneDependency);
- }
+ for (int i = 0; i < nodeCount; i++) {
+ Node node = mNodes.get(i);
+ // Update dependencies for node's clone
+ node.mTmpClone.mLatestParent = node.mLatestParent == null ?
+ null : node.mLatestParent.mTmpClone;
+ int size = node.mChildNodes == null ? 0 : node.mChildNodes.size();
+ for (int j = 0; j < size; j++) {
+ node.mTmpClone.mChildNodes.set(j, node.mChildNodes.get(j).mTmpClone);
}
- if (node.nodeDependents != null) {
- clone.nodeDependents = new ArrayList<Node>(node.nodeDependents.size());
- for (Node dep : node.nodeDependents) {
- clone.nodeDependents.add(dep.mTmpClone);
- }
+ size = node.mSiblings == null ? 0 : node.mSiblings.size();
+ for (int j = 0; j < size; j++) {
+ node.mTmpClone.mSiblings.set(j, node.mSiblings.get(j).mTmpClone);
}
- if (node.nodeDependencies != null) {
- clone.nodeDependencies = new ArrayList<Node>(node.nodeDependencies.size());
- for (Node dep : node.nodeDependencies) {
- clone.nodeDependencies.add(dep.mTmpClone);
- }
+ size = node.mParents == null ? 0 : node.mParents.size();
+ for (int j = 0; j < size; j++) {
+ node.mTmpClone.mParents.set(j, node.mParents.get(j).mTmpClone);
}
}
+
for (int n = 0; n < nodeCount; n++) {
mNodes.get(n).mTmpClone = null;
}
return anim;
}
- /**
- * This class is the mechanism by which animations are started based on events in other
- * animations. If an animation has multiple dependencies on other animations, then
- * all dependencies must be satisfied before the animation is started.
- */
- private static class DependencyListener implements AnimatorListener {
-
- private AnimatorSet mAnimatorSet;
-
- // The node upon which the dependency is based.
- private Node mNode;
-
- // The Dependency rule (WITH or AFTER) that the listener should wait for on
- // the node
- private int mRule;
-
- public DependencyListener(AnimatorSet animatorSet, Node node, int rule) {
- this.mAnimatorSet = animatorSet;
- this.mNode = node;
- this.mRule = rule;
- }
-
- /**
- * Ignore cancel events for now. We may want to handle this eventually,
- * to prevent follow-on animations from running when some dependency
- * animation is canceled.
- */
- public void onAnimationCancel(Animator animation) {
- }
-
- /**
- * An end event is received - see if this is an event we are listening for
- */
- public void onAnimationEnd(Animator animation) {
- if (mRule == Dependency.AFTER) {
- startIfReady(animation);
- }
- }
-
- /**
- * Ignore repeat events for now
- */
- public void onAnimationRepeat(Animator animation) {
- }
-
- /**
- * A start event is received - see if this is an event we are listening for
- */
- public void onAnimationStart(Animator animation) {
- if (mRule == Dependency.WITH) {
- startIfReady(animation);
- }
- }
-
- /**
- * Check whether the event received is one that the node was waiting for.
- * If so, mark it as complete and see whether it's time to start
- * the animation.
- * @param dependencyAnimation the animation that sent the event.
- */
- private void startIfReady(Animator dependencyAnimation) {
- if (mAnimatorSet.mTerminated) {
- // if the parent AnimatorSet was canceled, then don't start any dependent anims
- return;
- }
- Dependency dependencyToRemove = null;
- int numDependencies = mNode.tmpDependencies.size();
- for (int i = 0; i < numDependencies; ++i) {
- Dependency dependency = mNode.tmpDependencies.get(i);
- if (dependency.rule == mRule &&
- dependency.node.animation == dependencyAnimation) {
- // rule fired - remove the dependency and listener and check to
- // see whether it's time to start the animation
- dependencyToRemove = dependency;
- dependencyAnimation.removeListener(this);
- break;
- }
- }
- mNode.tmpDependencies.remove(dependencyToRemove);
- if (mNode.tmpDependencies.size() == 0) {
- // all dependencies satisfied: start the animation
- mNode.animation.start();
- mAnimatorSet.mPlayingSet.add(mNode.animation);
- }
- }
-
- }
private class AnimatorSetListener implements AnimatorListener {
@@ -812,14 +711,16 @@ public final class AnimatorSet extends Animator {
}
public void onAnimationCancel(Animator animation) {
+
if (!mTerminated) {
// Listeners are already notified of the AnimatorSet canceling in cancel().
// The logic below only kicks in when animations end normally
- if (mPlayingSet.size() == 0) {
- if (mListeners != null) {
- int numListeners = mListeners.size();
+ if (mAnimatorSet.mPlayingSet.size() == 0) {
+ ArrayList<AnimatorListener> listeners = mAnimatorSet.mListeners;
+ if (listeners != null) {
+ int numListeners = listeners.size();
for (int i = 0; i < numListeners; ++i) {
- mListeners.get(i).onAnimationCancel(mAnimatorSet);
+ listeners.get(i).onAnimationCancel(mAnimatorSet);
}
}
}
@@ -829,17 +730,26 @@ public final class AnimatorSet extends Animator {
@SuppressWarnings("unchecked")
public void onAnimationEnd(Animator animation) {
animation.removeListener(this);
- mPlayingSet.remove(animation);
+ mAnimatorSet.mPlayingSet.remove(animation);
Node animNode = mAnimatorSet.mNodeMap.get(animation);
- animNode.done = true;
+ animNode.mEnded = true;
+
if (!mTerminated) {
+ List<Node> children = animNode.mChildNodes;
+ // Start children animations, if any.
+ int childrenSize = children == null ? 0 : children.size();
+ for (int i = 0; i < childrenSize; i++) {
+ if (children.get(i).mLatestParent == animNode) {
+ mAnimatorSet.start(children.get(i));
+ }
+ }
// Listeners are already notified of the AnimatorSet ending in cancel() or
// end(); the logic below only kicks in when animations end normally
- ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
boolean allDone = true;
- int numSortedNodes = sortedNodes.size();
- for (int i = 0; i < numSortedNodes; ++i) {
- if (!sortedNodes.get(i).done) {
+ // Traverse the tree and find if there's any unfinished node
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ if (!mNodes.get(i).mEnded) {
allDone = false;
break;
}
@@ -872,79 +782,6 @@ public final class AnimatorSet extends Animator {
}
/**
- * This method sorts the current set of nodes, if needed. The sort is a simple
- * DependencyGraph sort, which goes like this:
- * - All nodes without dependencies become 'roots'
- * - while roots list is not null
- * - for each root r
- * - add r to sorted list
- * - remove r as a dependency from any other node
- * - any nodes with no dependencies are added to the roots list
- */
- private void sortNodes() {
- if (mNeedsSort) {
- mSortedNodes.clear();
- ArrayList<Node> roots = new ArrayList<Node>();
- int numNodes = mNodes.size();
- for (int i = 0; i < numNodes; ++i) {
- Node node = mNodes.get(i);
- if (node.dependencies == null || node.dependencies.size() == 0) {
- roots.add(node);
- }
- }
- ArrayList<Node> tmpRoots = new ArrayList<Node>();
- while (roots.size() > 0) {
- int numRoots = roots.size();
- for (int i = 0; i < numRoots; ++i) {
- Node root = roots.get(i);
- mSortedNodes.add(root);
- if (root.nodeDependents != null) {
- int numDependents = root.nodeDependents.size();
- for (int j = 0; j < numDependents; ++j) {
- Node node = root.nodeDependents.get(j);
- node.nodeDependencies.remove(root);
- if (node.nodeDependencies.size() == 0) {
- tmpRoots.add(node);
- }
- }
- }
- }
- roots.clear();
- roots.addAll(tmpRoots);
- tmpRoots.clear();
- }
- mNeedsSort = false;
- if (mSortedNodes.size() != mNodes.size()) {
- throw new IllegalStateException("Circular dependencies cannot exist"
- + " in AnimatorSet");
- }
- } else {
- // Doesn't need sorting, but still need to add in the nodeDependencies list
- // because these get removed as the event listeners fire and the dependencies
- // are satisfied
- int numNodes = mNodes.size();
- for (int i = 0; i < numNodes; ++i) {
- Node node = mNodes.get(i);
- if (node.dependencies != null && node.dependencies.size() > 0) {
- int numDependencies = node.dependencies.size();
- for (int j = 0; j < numDependencies; ++j) {
- Dependency dependency = node.dependencies.get(j);
- if (node.nodeDependencies == null) {
- node.nodeDependencies = new ArrayList<Node>();
- }
- if (!node.nodeDependencies.contains(dependency.node)) {
- node.nodeDependencies.add(dependency.node);
- }
- }
- }
- // nodes are 'done' by default; they become un-done when started, and done
- // again when ended
- node.done = false;
- }
- }
- }
-
- /**
* @hide
*/
@Override
@@ -953,8 +790,10 @@ public final class AnimatorSet extends Animator {
return false;
}
// Loop to make sure all the Nodes can reverse.
- for (Node node : mNodes) {
- if (!node.animation.canReverse() || node.animation.getStartDelay() > 0) {
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ if (!node.mAnimation.canReverse() || node.mAnimation.getStartDelay() > 0) {
return false;
}
}
@@ -967,8 +806,10 @@ public final class AnimatorSet extends Animator {
@Override
public void reverse() {
if (canReverse()) {
- for (Node node : mNodes) {
- node.animation.reverse();
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ node.mAnimation.reverse();
}
}
}
@@ -976,88 +817,244 @@ public final class AnimatorSet extends Animator {
@Override
public String toString() {
String returnVal = "AnimatorSet@" + Integer.toHexString(hashCode()) + "{";
- boolean prevNeedsSort = mNeedsSort;
- sortNodes();
- mNeedsSort = prevNeedsSort;
- for (Node node : mSortedNodes) {
- returnVal += "\n " + node.animation.toString();
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ returnVal += "\n " + node.mAnimation.toString();
}
return returnVal + "\n}";
}
+ private void printChildCount() {
+ // Print out the child count through a level traverse.
+ ArrayList<Node> list = new ArrayList<>(mNodes.size());
+ list.add(mRootNode);
+ Log.d(TAG, "Current tree: ");
+ int index = 0;
+ while (index < list.size()) {
+ int listSize = list.size();
+ StringBuilder builder = new StringBuilder();
+ for (; index < listSize; index++) {
+ Node node = list.get(index);
+ int num = 0;
+ if (node.mChildNodes != null) {
+ for (int i = 0; i < node.mChildNodes.size(); i++) {
+ Node child = node.mChildNodes.get(i);
+ if (child.mLatestParent == node) {
+ num++;
+ list.add(child);
+ }
+ }
+ }
+ builder.append(" ");
+ builder.append(num);
+ }
+ Log.d(TAG, builder.toString());
+ }
+ }
+
+ private void createDependencyGraph() {
+ if (!mDependencyDirty) {
+ return;
+ }
+
+ // TODO: In addition to checking the dirty flag, we should also cache the duration for
+ // each animator, so that when the animator's duration is changed, we can detect that and
+ // update the dependency graph.
+
+ mDependencyDirty = false;
+ // Traverse all the siblings and make sure they have all the parents
+ int size = mNodes.size();
+ for (int i = 0; i < size; i++) {
+ mNodes.get(i).mParentsAdded = false;
+ }
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ if (node.mParentsAdded) {
+ continue;
+ }
+
+ node.mParentsAdded = true;
+ if (node.mSiblings == null) {
+ continue;
+ }
+
+ // Find all the siblings
+ findSiblings(node, node.mSiblings);
+ node.mSiblings.remove(node);
+
+ // Get parents from all siblings
+ int siblingSize = node.mSiblings.size();
+ for (int j = 0; j < siblingSize; j++) {
+ node.addParents(node.mSiblings.get(j).mParents);
+ }
+
+ // Now make sure all siblings share the same set of parents
+ for (int j = 0; j < siblingSize; j++) {
+ Node sibling = node.mSiblings.get(j);
+ sibling.addParents(node.mParents);
+ sibling.mParentsAdded = true;
+ }
+ }
+
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ if (node != mRootNode && node.mParents == null) {
+ node.addParent(mRootNode);
+ }
+ }
+
+ // Do a DFS on the tree
+ ArrayList<Node> visited = new ArrayList<Node>(mNodes.size());
+ // Assign start/end time
+ mRootNode.mStartTime = 0;
+ mRootNode.mEndTime = mDelayAnim.getDuration();
+ updatePlayTime(mRootNode, visited);
+
+ long maxEndTime = 0;
+ for (int i = 0; i < size; i++) {
+ Node node = mNodes.get(i);
+ if (node.mEndTime == DURATION_INFINITE) {
+ maxEndTime = DURATION_INFINITE;
+ break;
+ } else {
+ maxEndTime = node.mEndTime > maxEndTime ? node.mEndTime : maxEndTime;
+ }
+ }
+ mTotalDuration = maxEndTime;
+ }
+
/**
- * Dependency holds information about the node that some other node is
- * dependent upon and the nature of that dependency.
- *
+ * Based on parent's start/end time, calculate children's start/end time. If cycle exists in
+ * the graph, all the nodes on the cycle will be marked to start at {@link #DURATION_INFINITE},
+ * meaning they will ever play.
*/
- private static class Dependency {
- static final int WITH = 0; // dependent node must start with this dependency node
- static final int AFTER = 1; // dependent node must start when this dependency node finishes
+ private void updatePlayTime(Node parent, ArrayList<Node> visited) {
+ if (parent.mChildNodes == null) {
+ return;
+ }
+
+ visited.add(parent);
+ int childrenSize = parent.mChildNodes.size();
+ for (int i = 0; i < childrenSize; i++) {
+ Node child = parent.mChildNodes.get(i);
+ int index = visited.indexOf(child);
+ if (index >= 0) {
+ // Child has been visited, cycle found. Mark all the nodes in the cycle.
+ for (int j = index; j < visited.size(); i++) {
+ visited.get(j).mLatestParent = null;
+ visited.get(j).mStartTime = DURATION_INFINITE;
+ visited.get(j).mEndTime = DURATION_INFINITE;
+ }
+ child.mStartTime = DURATION_INFINITE;
+ child.mEndTime = DURATION_INFINITE;
+ child.mLatestParent = null;
+ Log.w(TAG, "Cycle found in AnimatorSet: " + this);
+ continue;
+ }
- // The node that the other node with this Dependency is dependent upon
- public Node node;
+ if (child.mStartTime != DURATION_INFINITE) {
+ if (parent.mEndTime == DURATION_INFINITE) {
+ child.mLatestParent = parent;
+ child.mStartTime = DURATION_INFINITE;
+ child.mEndTime = DURATION_INFINITE;
+ } else {
+ if (parent.mEndTime >= child.mStartTime) {
+ child.mLatestParent = parent;
+ child.mStartTime = parent.mEndTime;
+ }
- // The nature of the dependency (WITH or AFTER)
- public int rule;
+ long duration = child.mAnimation.getTotalDuration();
+ child.mEndTime = duration == DURATION_INFINITE ?
+ DURATION_INFINITE : child.mStartTime + duration;
+ }
+ }
+ updatePlayTime(child, visited);
+ }
+ visited.remove(parent);
+ }
- public Dependency(Node node, int rule) {
- this.node = node;
- this.rule = rule;
+ // Recursively find all the siblings
+ private void findSiblings(Node node, ArrayList<Node> siblings) {
+ if (!siblings.contains(node)) {
+ siblings.add(node);
+ if (node.mSiblings == null) {
+ return;
+ }
+ for (int i = 0; i < node.mSiblings.size(); i++) {
+ findSiblings(node.mSiblings.get(i), siblings);
+ }
}
}
/**
+ * @hide
+ */
+ @Override
+ public long getTotalDuration() {
+ updateAnimatorsDuration();
+ createDependencyGraph();
+ return mTotalDuration;
+ }
+
+ private Node getNodeForAnimation(Animator anim) {
+ Node node = mNodeMap.get(anim);
+ if (node == null) {
+ node = new Node(anim);
+ mNodeMap.put(anim, node);
+ mNodes.add(node);
+ }
+ return node;
+ }
+
+ /**
* A Node is an embodiment of both the Animator that it wraps as well as
* any dependencies that are associated with that Animation. This includes
* both dependencies upon other nodes (in the dependencies list) as
* well as dependencies of other nodes upon this (in the nodeDependents list).
*/
private static class Node implements Cloneable {
- public Animator animation;
+ Animator mAnimation;
/**
- * These are the dependencies that this node's animation has on other
- * nodes. For example, if this node's animation should begin with some
- * other animation ends, then there will be an item in this node's
- * dependencies list for that other animation's node.
+ * Child nodes are the nodes associated with animations that will be played immediately
+ * after current node.
*/
- public ArrayList<Dependency> dependencies = null;
+ ArrayList<Node> mChildNodes = null;
/**
- * tmpDependencies is a runtime detail. We use the dependencies list for sorting.
- * But we also use the list to keep track of when multiple dependencies are satisfied,
- * but removing each dependency as it is satisfied. We do not want to remove
- * the dependency itself from the list, because we need to retain that information
- * if the AnimatorSet is launched in the future. So we create a copy of the dependency
- * list when the AnimatorSet starts and use this tmpDependencies list to track the
- * list of satisfied dependencies.
+ * Temporary field to hold the clone in AnimatorSet#clone. Cleaned after clone is complete
*/
- public ArrayList<Dependency> tmpDependencies = null;
+ private Node mTmpClone = null;
/**
- * nodeDependencies is just a list of the nodes that this Node is dependent upon.
- * This information is used in sortNodes(), to determine when a node is a root.
+ * Flag indicating whether the animation in this node is finished. This flag
+ * is used by AnimatorSet to check, as each animation ends, whether all child animations
+ * are mEnded and it's time to send out an end event for the entire AnimatorSet.
*/
- public ArrayList<Node> nodeDependencies = null;
+ boolean mEnded = false;
/**
- * nodeDepdendents is the list of nodes that have this node as a dependency. This
- * is a utility field used in sortNodes to facilitate removing this node as a
- * dependency when it is a root node.
+ * Nodes with animations that are defined to play simultaneously with the animation
+ * associated with this current node.
*/
- public ArrayList<Node> nodeDependents = null;
+ ArrayList<Node> mSiblings;
/**
- * Flag indicating whether the animation in this node is finished. This flag
- * is used by AnimatorSet to check, as each animation ends, whether all child animations
- * are done and it's time to send out an end event for the entire AnimatorSet.
+ * Parent nodes are the nodes with animations preceding current node's animation. Parent
+ * nodes here are derived from user defined animation sequence.
*/
- public boolean done = false;
+ ArrayList<Node> mParents;
/**
- * Temporary field to hold the clone in AnimatorSet#clone. Cleaned after clone is complete
+ * Latest parent is the parent node associated with a animation that finishes after all
+ * the other parents' animations.
*/
- private Node mTmpClone = null;
+ Node mLatestParent = null;
+
+ boolean mParentsAdded = false;
+ long mStartTime = 0;
+ long mEndTime = 0;
/**
* Constructs the Node with the animation that it encapsulates. A Node has no
@@ -1067,41 +1064,69 @@ public final class AnimatorSet extends Animator {
* @param animation The animation that the Node encapsulates.
*/
public Node(Animator animation) {
- this.animation = animation;
- }
-
- /**
- * Add a dependency to this Node. The dependency includes information about the
- * node that this node is dependency upon and the nature of the dependency.
- * @param dependency
- */
- public void addDependency(Dependency dependency) {
- if (dependencies == null) {
- dependencies = new ArrayList<Dependency>();
- nodeDependencies = new ArrayList<Node>();
- }
- dependencies.add(dependency);
- if (!nodeDependencies.contains(dependency.node)) {
- nodeDependencies.add(dependency.node);
- }
- Node dependencyNode = dependency.node;
- if (dependencyNode.nodeDependents == null) {
- dependencyNode.nodeDependents = new ArrayList<Node>();
- }
- dependencyNode.nodeDependents.add(this);
+ this.mAnimation = animation;
}
@Override
public Node clone() {
try {
Node node = (Node) super.clone();
- node.animation = animation.clone();
- node.done = false;
+ node.mAnimation = mAnimation.clone();
+ if (mChildNodes != null) {
+ node.mChildNodes = new ArrayList<>(mChildNodes);
+ }
+ if (mSiblings != null) {
+ node.mSiblings = new ArrayList<>(mSiblings);
+ }
+ if (mParents != null) {
+ node.mParents = new ArrayList<>(mParents);
+ }
+ node.mEnded = false;
return node;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
+
+ void addChild(Node node) {
+ if (mChildNodes == null) {
+ mChildNodes = new ArrayList<>();
+ }
+ if (!mChildNodes.contains(node)) {
+ mChildNodes.add(node);
+ node.addParent(this);
+ }
+ }
+
+ public void addSibling(Node node) {
+ if (mSiblings == null) {
+ mSiblings = new ArrayList<Node>();
+ }
+ if (!mSiblings.contains(node)) {
+ mSiblings.add(node);
+ node.addSibling(this);
+ }
+ }
+
+ public void addParent(Node node) {
+ if (mParents == null) {
+ mParents = new ArrayList<Node>();
+ }
+ if (!mParents.contains(node)) {
+ mParents.add(node);
+ node.addChild(this);
+ }
+ }
+
+ public void addParents(ArrayList<Node> parents) {
+ if (parents == null) {
+ return;
+ }
+ int size = parents.size();
+ for (int i = 0; i < size; i++) {
+ addParent(parents.get(i));
+ }
+ }
}
/**
@@ -1172,12 +1197,8 @@ public final class AnimatorSet extends Animator {
* the other methods of this Builder object.
*/
Builder(Animator anim) {
- mCurrentNode = mNodeMap.get(anim);
- if (mCurrentNode == null) {
- mCurrentNode = new Node(anim);
- mNodeMap.put(anim, mCurrentNode);
- mNodes.add(mCurrentNode);
- }
+ mDependencyDirty = true;
+ mCurrentNode = getNodeForAnimation(anim);
}
/**
@@ -1188,14 +1209,8 @@ public final class AnimatorSet extends Animator {
* {@link AnimatorSet#play(Animator)} method starts.
*/
public Builder with(Animator anim) {
- Node node = mNodeMap.get(anim);
- if (node == null) {
- node = new Node(anim);
- mNodeMap.put(anim, node);
- mNodes.add(node);
- }
- Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH);
- node.addDependency(dependency);
+ Node node = getNodeForAnimation(anim);
+ mCurrentNode.addSibling(node);
return this;
}
@@ -1209,14 +1224,8 @@ public final class AnimatorSet extends Animator {
*/
public Builder before(Animator anim) {
mReversible = false;
- Node node = mNodeMap.get(anim);
- if (node == null) {
- node = new Node(anim);
- mNodeMap.put(anim, node);
- mNodes.add(node);
- }
- Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER);
- node.addDependency(dependency);
+ Node node = getNodeForAnimation(anim);
+ mCurrentNode.addChild(node);
return this;
}
@@ -1230,14 +1239,8 @@ public final class AnimatorSet extends Animator {
*/
public Builder after(Animator anim) {
mReversible = false;
- Node node = mNodeMap.get(anim);
- if (node == null) {
- node = new Node(anim);
- mNodeMap.put(anim, node);
- mNodes.add(node);
- }
- Dependency dependency = new Dependency(node, Dependency.AFTER);
- mCurrentNode.addDependency(dependency);
+ Node node = getNodeForAnimation(anim);
+ mCurrentNode.addParent(node);
return this;
}
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index a455f8b3a8e4..35a8816bd703 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -575,6 +575,18 @@ public class ValueAnimator extends Animator {
}
/**
+ * @hide
+ */
+ @Override
+ public long getTotalDuration() {
+ if (mRepeatCount == INFINITE) {
+ return DURATION_INFINITE;
+ } else {
+ return mUnscaledStartDelay + (mUnscaledDuration * (mRepeatCount + 1));
+ }
+ }
+
+ /**
* Sets the position of the animation to the specified point in time. This time should
* be between 0 and the total duration of the animation, including any repetition. If
* the animation has not yet been started, then it will not advance forward after it is
diff --git a/core/java/android/annotation/IntRange.java b/core/java/android/annotation/IntRange.java
index 1e3c072267d7..b489c01dfd69 100644
--- a/core/java/android/annotation/IntRange.java
+++ b/core/java/android/annotation/IntRange.java
@@ -18,6 +18,7 @@ package android.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
@@ -38,7 +39,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
* @hide
*/
@Retention(SOURCE)
-@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE})
+@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE})
public @interface IntRange {
/** Smallest value, inclusive */
long from() default Long.MIN_VALUE;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index aaaa745bc2da..7b73d4fc8116 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2199,7 +2199,9 @@ public class Intent implements Parcelable, Cloneable {
/**
* Activity Action: Start this activity to request system shutdown.
* The optional boolean extra field {@link #EXTRA_KEY_CONFIRM} can be set to true
- * to request confirmation from the user before shutting down.
+ * to request confirmation from the user before shutting down. The optional boolean
+ * extra field {@link #EXTRA_USER_REQUESTED_SHUTDOWN} can be set to true to
+ * indicate that the shutdown is requested by the user.
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
@@ -3513,6 +3515,15 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_KEY_CONFIRM = "android.intent.extra.KEY_CONFIRM";
/**
+ * Set to true in {@link #ACTION_REQUEST_SHUTDOWN} to indicate that the shutdown is
+ * requested by the user.
+ *
+ * {@hide}
+ */
+ public static final String EXTRA_USER_REQUESTED_SHUTDOWN =
+ "android.intent.extra.USER_REQUESTED_SHUTDOWN";
+
+ /**
* Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED} or
* {@link android.content.Intent#ACTION_PACKAGE_CHANGED} intents to override the default action
* of restarting the application.
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index af1367cd2dc2..c580083b94d9 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -173,6 +173,28 @@ public abstract class CameraMetadata<TKey> {
}
}
+ ArrayList<TKey> vendorKeys = CameraMetadataNative.getAllVendorKeys(keyClass);
+
+ if (vendorKeys != null) {
+ for (TKey k : vendorKeys) {
+ String keyName;
+ if (k instanceof CaptureRequest.Key<?>) {
+ keyName = ((CaptureRequest.Key<?>) k).getName();
+ } else if (k instanceof CaptureResult.Key<?>) {
+ keyName = ((CaptureResult.Key<?>) k).getName();
+ } else if (k instanceof CameraCharacteristics.Key<?>) {
+ keyName = ((CameraCharacteristics.Key<?>) k).getName();
+ } else {
+ continue;
+ }
+
+ if (filterTags == null || Arrays.binarySearch(filterTags,
+ CameraMetadataNative.getTag(keyName)) >= 0) {
+ keyList.add(k);
+ }
+ }
+ }
+
return keyList;
}
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 7e50fd9f623a..12a2910b2055 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1078,6 +1078,7 @@ public class CameraMetadataNative implements Parcelable {
private native synchronized void nativeWriteValues(int tag, byte[] src);
private native synchronized void nativeDump() throws IOException; // dump to ALOGD
+ private static native ArrayList nativeGetAllVendorKeys(Class keyClass);
private static native int nativeGetTagFromKey(String keyName)
throws IllegalArgumentException;
private static native int nativeGetTypeFromTag(int tag)
@@ -1113,6 +1114,19 @@ public class CameraMetadataNative implements Parcelable {
return nativeIsEmpty();
}
+
+ /**
+ * Return a list containing keys of the given key class for all defined vendor tags.
+ *
+ * @hide
+ */
+ public static <K> ArrayList<K> getAllVendorKeys(Class<K> keyClass) {
+ if (keyClass == null) {
+ throw new NullPointerException();
+ }
+ return (ArrayList<K>) nativeGetAllVendorKeys(keyClass);
+ }
+
/**
* Convert a key string into the equivalent native tag.
*
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 0f37ac720bc7..c4f62baab4a1 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -46,7 +46,7 @@ interface IPowerManager
boolean isDeviceIdleMode();
void reboot(boolean confirm, String reason, boolean wait);
- void shutdown(boolean confirm, boolean wait);
+ void shutdown(boolean confirm, String reason, boolean wait);
void crash(String message);
void setStayOnSetting(int val);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 9a1a03eb3294..69974fa9d965 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -387,7 +387,13 @@ public final class PowerManager {
* @hide
*/
public static final String REBOOT_RECOVERY = "recovery";
-
+
+ /**
+ * The value to pass as the 'reason' argument to android_reboot().
+ * @hide
+ */
+ public static final String SHUTDOWN_USER_REQUESTED = "userrequested";
+
final Context mContext;
final IPowerManager mService;
final Handler mHandler;
@@ -926,13 +932,14 @@ public final class PowerManager {
* Turn off the device.
*
* @param confirm If true, shows a shutdown confirmation dialog.
+ * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
* @param wait If true, this call waits for the shutdown to complete and does not return.
*
* @hide
*/
- public void shutdown(boolean confirm, boolean wait) {
+ public void shutdown(boolean confirm, String reason, boolean wait) {
try {
- mService.shutdown(confirm, wait);
+ mService.shutdown(confirm, reason, wait);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 31b58490ba24..4da88ee9da9c 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -75,6 +75,8 @@ public final class Trace {
public static final long TRACE_TAG_BIONIC = 1L << 16;
/** @hide */
public static final long TRACE_TAG_POWER = 1L << 17;
+ /** @hide */
+ public static final long TRACE_TAG_PACKAGE_MANAGER = 1L << 18;
private static final long TRACE_TAG_NOT_READY = 1L << 63;
private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 862207cc1912..f2bf6dc8ede0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8346,9 +8346,9 @@ public final class Settings {
return true;
case AppOpsManager.MODE_DEFAULT:
// this is the default operating mode after an app's installation
- if (!throwException) {
- return context.checkCallingOrSelfPermission(permissionName) ==
- PackageManager.PERMISSION_GRANTED;
+ if(context.checkCallingOrSelfPermission(permissionName) == PackageManager
+ .PERMISSION_GRANTED) {
+ return true;
}
default:
// this is for all other cases trickled down here...
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 379796d58dc9..2a3756d6b7b3 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -336,6 +336,14 @@ public class RenderNodeAnimator extends Animator {
return mUnscaledDuration;
}
+ /**
+ * @hide
+ */
+ @Override
+ public long getTotalDuration() {
+ return mUnscaledDuration + mUnscaledStartDelay;
+ }
+
@Override
public boolean isRunning() {
return mState == STATE_DELAYED || mState == STATE_RUNNING;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 6af2e8bf5765..d9faece9485f 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -517,6 +517,7 @@ public class ChooserActivity extends ResolverActivity {
private final ResolveInfo mBackupResolveInfo;
private final ChooserTarget mChooserTarget;
private Drawable mBadgeIcon = null;
+ private CharSequence mBadgeContentDescription;
private Drawable mDisplayIcon;
private final Intent mFillInIntent;
private final int mFillInFlags;
@@ -532,7 +533,9 @@ public class ChooserActivity extends ResolverActivity {
if (ri != null) {
final ActivityInfo ai = ri.activityInfo;
if (ai != null && ai.applicationInfo != null) {
- mBadgeIcon = getPackageManager().getApplicationIcon(ai.applicationInfo);
+ final PackageManager pm = getPackageManager();
+ mBadgeIcon = pm.getApplicationIcon(ai.applicationInfo);
+ mBadgeContentDescription = pm.getApplicationLabel(ai.applicationInfo);
}
}
}
@@ -555,6 +558,7 @@ public class ChooserActivity extends ResolverActivity {
mBackupResolveInfo = other.mBackupResolveInfo;
mChooserTarget = other.mChooserTarget;
mBadgeIcon = other.mBadgeIcon;
+ mBadgeContentDescription = other.mBadgeContentDescription;
mDisplayIcon = other.mDisplayIcon;
mFillInIntent = fillInIntent;
mFillInFlags = flags;
@@ -647,6 +651,11 @@ public class ChooserActivity extends ResolverActivity {
}
@Override
+ public CharSequence getBadgeContentDescription() {
+ return mBadgeContentDescription;
+ }
+
+ @Override
public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
return new ChooserTargetInfo(this, fillInIntent, flags);
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 89599e089f75..7dd3bed079fc 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -932,6 +932,11 @@ public class ResolverActivity extends Activity {
}
@Override
+ public CharSequence getBadgeContentDescription() {
+ return null;
+ }
+
+ @Override
public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
return new DisplayResolveInfo(this, fillInIntent, flags);
}
@@ -1072,6 +1077,11 @@ public class ResolverActivity extends Activity {
public Drawable getBadgeIcon();
/**
+ * @return The content description for the badge icon
+ */
+ public CharSequence getBadgeContentDescription();
+
+ /**
* Clone this target with the given fill-in information.
*/
public TargetInfo cloneFilledIn(Intent fillInIntent, int flags);
@@ -1542,6 +1552,7 @@ public class ResolverActivity extends Activity {
final Drawable badge = info.getBadgeIcon();
if (badge != null) {
holder.badge.setImageDrawable(badge);
+ holder.badge.setContentDescription(info.getBadgeContentDescription());
holder.badge.setVisibility(View.VISIBLE);
} else {
holder.badge.setVisibility(View.GONE);
diff --git a/core/java/com/android/internal/app/ShutdownActivity.java b/core/java/com/android/internal/app/ShutdownActivity.java
index 97521cf68dd4..745d28f367a3 100644
--- a/core/java/com/android/internal/app/ShutdownActivity.java
+++ b/core/java/com/android/internal/app/ShutdownActivity.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IPowerManager;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
@@ -30,6 +31,7 @@ public class ShutdownActivity extends Activity {
private static final String TAG = "ShutdownActivity";
private boolean mReboot;
private boolean mConfirm;
+ private boolean mUserRequested;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -38,6 +40,7 @@ public class ShutdownActivity extends Activity {
Intent intent = getIntent();
mReboot = Intent.ACTION_REBOOT.equals(intent.getAction());
mConfirm = intent.getBooleanExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ mUserRequested = intent.getBooleanExtra(Intent.EXTRA_USER_REQUESTED_SHUTDOWN, false);
Slog.i(TAG, "onCreate(): confirm=" + mConfirm);
Thread thr = new Thread("ShutdownActivity") {
@@ -49,7 +52,9 @@ public class ShutdownActivity extends Activity {
if (mReboot) {
pm.reboot(mConfirm, null, false);
} else {
- pm.shutdown(mConfirm, false);
+ pm.shutdown(mConfirm,
+ mUserRequested ? PowerManager.SHUTDOWN_USER_REQUESTED : null,
+ false);
}
} catch (RemoteException e) {
}
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index fc9a1a50801e..76796243f3f5 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -34,6 +34,7 @@ import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.animation.AnimationUtils;
import android.widget.AbsListView;
import android.widget.OverScroller;
@@ -609,19 +610,37 @@ public class ResolverDrawerLayout extends ViewGroup {
}
@Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
+ public CharSequence getAccessibilityClassName() {
+ // Since we support scrolling, make this ViewGroup look like a
+ // ScrollView. This is kind of a hack until we have support for
+ // specifying auto-scroll behavior.
+ return android.widget.ScrollView.class.getName();
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfoInternal(info);
+
if (isEnabled()) {
if (mCollapseOffset != 0) {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
info.setScrollable(true);
}
}
+
+ // This view should never get accessibility focus, but it's interactive
+ // via nested scrolling, so we can't hide it completely.
+ info.removeAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
}
@Override
- public boolean performAccessibilityAction(int action, Bundle arguments) {
- if (super.performAccessibilityAction(action, arguments)) {
+ public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+ if (action == AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS.getId()) {
+ // This view should never get accessibility focus.
+ return false;
+ }
+
+ if (super.performAccessibilityActionInternal(action, arguments)) {
return true;
}
@@ -629,6 +648,7 @@ public class ResolverDrawerLayout extends ViewGroup {
smoothScrollTo(0, 0);
return true;
}
+
return false;
}
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 7c8769d0e93f..fb2268911be3 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -23,7 +23,9 @@
#include <utils/Vector.h>
#include <utils/SortedVector.h>
#include <utils/KeyedVector.h>
+#include <stdio.h>
#include <string.h>
+#include <vector>
#include "jni.h"
#include "JNIHelp.h"
@@ -45,9 +47,30 @@ static const bool kIsDebug = false;
// fully-qualified class name
#define CAMERA_METADATA_CLASS_NAME "android/hardware/camera2/impl/CameraMetadataNative"
+#define CHARACTERISTICS_KEY_CLASS_NAME "android/hardware/camera2/CameraCharacteristics$Key"
+#define REQUEST_KEY_CLASS_NAME "android/hardware/camera2/CaptureRequest$Key"
+#define RESULT_KEY_CLASS_NAME "android/hardware/camera2/CaptureResult$Key"
using namespace android;
+static struct metadata_java_key_offsets_t {
+ jclass mCharacteristicsKey;
+ jclass mResultKey;
+ jclass mRequestKey;
+ jmethodID mCharacteristicsConstr;
+ jmethodID mResultConstr;
+ jmethodID mRequestConstr;
+ jclass mByteArray;
+ jclass mInt32Array;
+ jclass mFloatArray;
+ jclass mInt64Array;
+ jclass mDoubleArray;
+ jclass mRationalArray;
+ jclass mArrayList;
+ jmethodID mArrayListConstr;
+ jmethodID mArrayListAdd;
+} gMetadataOffsets;
+
struct fields_t {
jfieldID metadata_ptr;
};
@@ -141,6 +164,7 @@ struct Helpers {
extern "C" {
static void CameraMetadata_classInit(JNIEnv *env, jobject thiz);
+static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType);
static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName);
static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag);
static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz);
@@ -510,6 +534,9 @@ static JNINativeMethod gCameraMetadataMethods[] = {
{ "nativeClassInit",
"()V",
(void *)CameraMetadata_classInit },
+ { "nativeGetAllVendorKeys",
+ "(Ljava/lang/Class;)Ljava/util/ArrayList;",
+ (void *)CameraMetadata_getAllVendorKeys},
{ "nativeGetTagFromKey",
"(Ljava/lang/String;)I",
(void *)CameraMetadata_getTagFromKey },
@@ -588,6 +615,44 @@ static int find_fields(JNIEnv *env, field *fields, int count)
// Get all the required offsets in java class and register native functions
int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
{
+
+ // Store global references to Key-related classes and methods used natively
+ jclass characteristicsKeyClazz = FindClassOrDie(env, CHARACTERISTICS_KEY_CLASS_NAME);
+ jclass requestKeyClazz = FindClassOrDie(env, REQUEST_KEY_CLASS_NAME);
+ jclass resultKeyClazz = FindClassOrDie(env, RESULT_KEY_CLASS_NAME);
+ gMetadataOffsets.mCharacteristicsKey = MakeGlobalRefOrDie(env, characteristicsKeyClazz);
+ gMetadataOffsets.mRequestKey = MakeGlobalRefOrDie(env, requestKeyClazz);
+ gMetadataOffsets.mResultKey = MakeGlobalRefOrDie(env, resultKeyClazz);
+ gMetadataOffsets.mCharacteristicsConstr = GetMethodIDOrDie(env,
+ gMetadataOffsets.mCharacteristicsKey, "<init>",
+ "(Ljava/lang/String;Ljava/lang/Class;)V");
+ gMetadataOffsets.mRequestConstr = GetMethodIDOrDie(env,
+ gMetadataOffsets.mRequestKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
+ gMetadataOffsets.mResultConstr = GetMethodIDOrDie(env,
+ gMetadataOffsets.mResultKey, "<init>", "(Ljava/lang/String;Ljava/lang/Class;)V");
+
+ // Store global references for primitive array types used by Keys
+ jclass byteClazz = FindClassOrDie(env, "[B");
+ jclass int32Clazz = FindClassOrDie(env, "[I");
+ jclass floatClazz = FindClassOrDie(env, "[F");
+ jclass int64Clazz = FindClassOrDie(env, "[J");
+ jclass doubleClazz = FindClassOrDie(env, "[D");
+ jclass rationalClazz = FindClassOrDie(env, "[Landroid/util/Rational;");
+ gMetadataOffsets.mByteArray = MakeGlobalRefOrDie(env, byteClazz);
+ gMetadataOffsets.mInt32Array = MakeGlobalRefOrDie(env, int32Clazz);
+ gMetadataOffsets.mFloatArray = MakeGlobalRefOrDie(env, floatClazz);
+ gMetadataOffsets.mInt64Array = MakeGlobalRefOrDie(env, int64Clazz);
+ gMetadataOffsets.mDoubleArray = MakeGlobalRefOrDie(env, doubleClazz);
+ gMetadataOffsets.mRationalArray = MakeGlobalRefOrDie(env, rationalClazz);
+
+ // Store global references for ArrayList methods used
+ jclass arrayListClazz = FindClassOrDie(env, "java/util/ArrayList");
+ gMetadataOffsets.mArrayList = MakeGlobalRefOrDie(env, arrayListClazz);
+ gMetadataOffsets.mArrayListConstr = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
+ "<init>", "(I)V");
+ gMetadataOffsets.mArrayListAdd = GetMethodIDOrDie(env, gMetadataOffsets.mArrayList,
+ "add", "(Ljava/lang/Object;)Z");
+
// Register native functions
return RegisterMethodsOrDie(env,
CAMERA_METADATA_CLASS_NAME,
@@ -596,6 +661,7 @@ int register_android_hardware_camera2_CameraMetadata(JNIEnv *env)
}
extern "C" {
+
static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
// XX: Why do this separately instead of doing it in the register function?
ALOGV("%s", __FUNCTION__);
@@ -612,6 +678,107 @@ static void CameraMetadata_classInit(JNIEnv *env, jobject thiz) {
env->FindClass(CAMERA_METADATA_CLASS_NAME);
}
+static jobject CameraMetadata_getAllVendorKeys(JNIEnv* env, jobject thiz, jclass keyType) {
+
+ // Get all vendor tags
+ sp<VendorTagDescriptor> vTags = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+ if (vTags.get() == nullptr) {
+ // No vendor tags.
+ return NULL;
+ }
+
+ int count = vTags->getTagCount();
+ if (count <= 0) {
+ // No vendor tags.
+ return NULL;
+ }
+
+ std::vector<uint32_t> tagIds(count, /*initializer value*/0);
+ vTags->getTagArray(&tagIds[0]);
+
+ // Which key class/constructor should we use?
+ jclass keyClazz;
+ jmethodID keyConstr;
+ if (env->IsSameObject(keyType, gMetadataOffsets.mCharacteristicsKey)) {
+ keyClazz = gMetadataOffsets.mCharacteristicsKey;
+ keyConstr = gMetadataOffsets.mCharacteristicsConstr;
+ } else if (env->IsSameObject(keyType, gMetadataOffsets.mResultKey)) {
+ keyClazz = gMetadataOffsets.mResultKey;
+ keyConstr = gMetadataOffsets.mResultConstr;
+ } else if (env->IsSameObject(keyType, gMetadataOffsets.mRequestKey)) {
+ keyClazz = gMetadataOffsets.mRequestKey;
+ keyConstr = gMetadataOffsets.mRequestConstr;
+ } else {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Invalid key class given as argument.");
+ return NULL;
+ }
+
+ // Allocate arrayList to return
+ jobject arrayList = env->NewObject(gMetadataOffsets.mArrayList,
+ gMetadataOffsets.mArrayListConstr, static_cast<jint>(count));
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+
+ for (uint32_t id : tagIds) {
+ const char* section = vTags->getSectionName(id);
+ const char* tag = vTags->getTagName(id);
+ int type = vTags->getTagType(id);
+
+ size_t totalLen = strlen(section) + strlen(tag) + 2;
+ std::vector<char> fullName(totalLen, 0);
+ snprintf(&fullName[0], totalLen, "%s.%s", section, tag);
+
+ jstring name = env->NewStringUTF(&fullName[0]);
+
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+
+ jclass valueClazz;
+ switch (type) {
+ case TYPE_BYTE:
+ valueClazz = gMetadataOffsets.mByteArray;
+ break;
+ case TYPE_INT32:
+ valueClazz = gMetadataOffsets.mInt32Array;
+ break;
+ case TYPE_FLOAT:
+ valueClazz = gMetadataOffsets.mFloatArray;
+ break;
+ case TYPE_INT64:
+ valueClazz = gMetadataOffsets.mInt64Array;
+ break;
+ case TYPE_DOUBLE:
+ valueClazz = gMetadataOffsets.mDoubleArray;
+ break;
+ case TYPE_RATIONAL:
+ valueClazz = gMetadataOffsets.mRationalArray;
+ break;
+ default:
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Invalid type %d given for key %s", type, &fullName[0]);
+ return NULL;
+ }
+
+ jobject key = env->NewObject(keyClazz, keyConstr, name, valueClazz);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+
+ env->CallBooleanMethod(arrayList, gMetadataOffsets.mArrayListAdd, key);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+
+ env->DeleteLocalRef(name);
+ env->DeleteLocalRef(key);
+ }
+
+ return arrayList;
+}
+
static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName) {
ScopedUtfChars keyScoped(env, keyName);
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 1b0793362426..5d63d35e1859 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -713,7 +713,7 @@
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"سلول اضافه شد"</string>
<string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"سلول <xliff:g id="CELL_INDEX">%1$s</xliff:g> اضافه شد"</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"الگو تکمیل شد"</string>
- <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"ناحیه الگو."</string>
+ <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"ناحیه الگو"</string>
<string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"‏%1$s. ابزارک %2$d از %3$d."</string>
<string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"ابزارک اضافه کنید."</string>
<string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"خالی"</string>
@@ -866,7 +866,7 @@
<string name="deleteText" msgid="6979668428458199034">"حذف"</string>
<string name="inputMethod" msgid="1653630062304567879">"روش ورودی"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"عملکردهای متنی"</string>
- <string name="low_internal_storage_view_title" msgid="5576272496365684834">"فضای ذخیره‌سازی رو به اتمام است"</string>
+ <string name="low_internal_storage_view_title" msgid="5576272496365684834">"حافظه درحال پر شدن است"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"برخی از عملکردهای سیستم ممکن است کار نکنند"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"فضای ذخیره‌سازی سیستم کافی نیست. اطمینان حاصل کنید که دارای ۲۵۰ مگابایت فضای خالی هستید و سیستم را راه‌اندازی مجدد کنید."</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> در حال اجرا است"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 69e390ba50c2..e2c94e440a80 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -898,7 +898,7 @@
<string name="aerr_title" msgid="1905800560317137752"></string>
<string name="aerr_application" msgid="932628488013092776">"\"<xliff:g id="APPLICATION">%1$s</xliff:g>\" s\'est arrêté."</string>
<string name="aerr_process" msgid="4507058997035697579">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> s\'est interrompu."</string>
- <string name="aerr_process_silence" msgid="4226685530196000222">"Plantage de Silence lors du processus \"<xliff:g id="PROCESS">%1$s</xliff:g>\" avant le redémarrage"</string>
+ <string name="aerr_process_silence" msgid="4226685530196000222">"Suspendre l\'affichage des informations de plantage de <xliff:g id="PROCESS">%1$s</xliff:g> jusqu\'au redémarrage"</string>
<string name="anr_title" msgid="4351948481459135709"></string>
<string name="anr_activity_application" msgid="1904477189057199066">"L\'application <xliff:g id="APPLICATION">%2$s</xliff:g> ne répond pas.\n\nVoulez-vous quitter ?"</string>
<string name="anr_activity_process" msgid="5776209883299089767">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> ne répond pas.\n\nVoulez-vous quitter ?"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index b139842676c6..e39c52fc9448 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1039,8 +1039,8 @@
<string name="usb_midi_notification_title" msgid="4850904915889144654">"‏USB ל-MIDI"</string>
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"‏מחובר לאביזר USB"</string>
<string name="usb_notification_message" msgid="7347368030849048437">"גע להצגת עוד אפשרויות."</string>
- <string name="adb_active_notification_title" msgid="6729044778949189918">"‏ניקוי באגים של USB מחובר"</string>
- <string name="adb_active_notification_message" msgid="1016654627626476142">"‏גע כדי להשבית ניקוי באגים בהתקן ה-USB."</string>
+ <string name="adb_active_notification_title" msgid="6729044778949189918">"‏ניפוי באגים של USB מחובר"</string>
+ <string name="adb_active_notification_message" msgid="1016654627626476142">"‏גע כדי להשבית ניפוי באגים בהתקן ה-USB."</string>
<string name="select_input_method" msgid="8547250819326693584">"שינוי מקלדת"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"בחר מקלדות"</string>
<string name="show_ime" msgid="9157568568695230830">"הצג שיטת קלט"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 3aefd671ac0a..c410d19c1757 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -898,7 +898,7 @@
<string name="aerr_title" msgid="1905800560317137752"></string>
<string name="aerr_application" msgid="932628488013092776">"Тилекке каршы, <xliff:g id="APPLICATION">%1$s</xliff:g> токтотулду."</string>
<string name="aerr_process" msgid="4507058997035697579">"Тилекке каршы, <xliff:g id="PROCESS">%1$s</xliff:g> процесси токтотулду."</string>
- <string name="aerr_process_silence" msgid="4226685530196000222">"<xliff:g id="PROCESS">%1$s</xliff:g> өчүрүп-күйгүзгөнгө чейин бузулду."</string>
+ <string name="aerr_process_silence" msgid="4226685530196000222">"Жымжырттык режиминде <xliff:g id="PROCESS">%1$s</xliff:g> колдонмосун иштетип жатканда ката кетиши мүмкүн. Ал ката түзмөктү өчүрүп-күйгүзгөндөн кийин жоюлат."</string>
<string name="anr_title" msgid="4351948481459135709"></string>
<string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> жооп бербей жатат.\n\nЖабылсынбы?"</string>
<string name="anr_activity_process" msgid="5776209883299089767">"<xliff:g id="ACTIVITY">%1$s</xliff:g> аракети жооп бербей жатат.\n\nЖабылсынбы?"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e79656f92c12..56e2cf2fad79 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -898,7 +898,7 @@
<string name="aerr_title" msgid="1905800560317137752"></string>
<string name="aerr_application" msgid="932628488013092776">"<xliff:g id="APPLICATION">%1$s</xliff:g> har dessverre stoppet."</string>
<string name="aerr_process" msgid="4507058997035697579">"Prosessen <xliff:g id="PROCESS">%1$s</xliff:g> har dessverre stoppet."</string>
- <string name="aerr_process_silence" msgid="4226685530196000222">"«Silence» kræsjer som følge av <xliff:g id="PROCESS">%1$s</xliff:g>, frem til den starter på nytt."</string>
+ <string name="aerr_process_silence" msgid="4226685530196000222">"Appen Silence kræsjer som følge av <xliff:g id="PROCESS">%1$s</xliff:g>, frem til omstart."</string>
<string name="anr_title" msgid="4351948481459135709"></string>
<string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> svarer ikke.\n\nVil du lukke appen?"</string>
<string name="anr_activity_process" msgid="5776209883299089767">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> svarer ikke.\n\nVil du lukke den?"</string>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 1cb39f0de592..7399fa9d58ce 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -41,9 +41,6 @@
<color name="switch_thumb_disabled_material_dark">#ff616161</color>
<color name="switch_thumb_disabled_material_light">#ffbdbdbd</color>
- <color name="link_text_material_light">@color/material_deep_teal_500</color>
- <color name="link_text_material_dark">@color/material_deep_teal_200</color>
-
<!-- Text & foreground colors -->
<eat-comment />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 295b453fb0b7..e406ae06d96c 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -67,8 +67,8 @@ please see themes_device_defaults.xml.
<item name="textColorHintInverse">@color/hint_foreground_material_light</item>
<item name="textColorHighlight">@color/highlighted_text_material</item>
<item name="textColorHighlightInverse">@color/highlighted_text_material</item>
- <item name="textColorLink">@color/link_text_material_dark</item>
- <item name="textColorLinkInverse">@color/link_text_material_light</item>
+ <item name="textColorLink">?attr/colorAccent</item>
+ <item name="textColorLinkInverse">?attr/colorAccent</item>
<item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
<item name="textColorAlertDialogListItem">@color/primary_text_material_dark</item>
@@ -422,8 +422,8 @@ please see themes_device_defaults.xml.
<item name="textColorHintInverse">@color/hint_foreground_material_dark</item>
<item name="textColorHighlight">@color/highlighted_text_material</item>
<item name="textColorHighlightInverse">@color/highlighted_text_material</item>
- <item name="textColorLink">@color/link_text_material_light</item>
- <item name="textColorLinkInverse">@color/link_text_material_dark</item>
+ <item name="textColorLink">?attr/colorAccent</item>
+ <item name="textColorLinkInverse">?attr/colorAccent</item>
<item name="textColorSearchUrl">@color/search_url_text_material_light</item>
<item name="textColorAlertDialogListItem">@color/primary_text_material_light</item>
@@ -793,8 +793,6 @@ please see themes_device_defaults.xml.
<item name="textColorHintInverse">@color/hint_foreground_material_dark</item>
<item name="textColorHighlight">@color/highlighted_text_material</item>
<item name="textColorHighlightInverse">@color/highlighted_text_material</item>
- <item name="textColorLink">@color/link_text_material_light</item>
- <item name="textColorLinkInverse">@color/link_text_material_dark</item>
<item name="textColorSearchUrl">@color/search_url_text_material_light</item>
<item name="textColorAlertDialogListItem">@color/primary_text_material_light</item>
@@ -827,8 +825,6 @@ please see themes_device_defaults.xml.
<item name="textColorHintInverse">@color/hint_foreground_material_light</item>
<item name="textColorHighlight">@color/highlighted_text_material</item>
<item name="textColorHighlightInverse">@color/highlighted_text_material</item>
- <item name="textColorLink">@color/link_text_material_dark</item>
- <item name="textColorLinkInverse">@color/link_text_material_light</item>
<item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
<item name="textColorAlertDialogListItem">@color/primary_text_material_dark</item>
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 2dc1c96259c0..1c39ffef6fd4 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -1545,7 +1545,7 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg
*/
int dirNameLen = dirName.length();
void *iterationCookie;
- if (!pZip->startIteration(&iterationCookie)) {
+ if (!pZip->startIteration(&iterationCookie, dirName.string(), NULL)) {
ALOGW("ZipFileRO::startIteration returned false");
return false;
}
@@ -1560,9 +1560,7 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMerg
continue;
}
//printf("Comparing %s in %s?\n", nameBuf, dirName.string());
- if (dirNameLen == 0 ||
- (strncmp(nameBuf, dirName.string(), dirNameLen) == 0 &&
- nameBuf[dirNameLen] == '/'))
+ if (dirNameLen == 0 || nameBuf[dirNameLen] == '/')
{
const char* cp;
const char* nextSlash;
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 3c459d83cb50..6c224e5c35e6 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.ImageFormat;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.os.Bundle;
import android.os.Handler;
@@ -32,6 +33,7 @@ import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.nio.ReadOnlyBufferException;
import java.util.Arrays;
import java.util.HashMap;
@@ -228,8 +230,9 @@ import java.util.Map;
data and submit it as a single codec-config buffer.
<p>
Android uses the following codec-specific data buffers. These are also required to be set in
- the track format for proper {@link MediaMuxer} track configuration. Each parameter set and
- codec-specific-data must start with a start code of {@code "\x00\x00\x00\x01"}.
+ the track format for proper {@link MediaMuxer} track configuration. Each parameter set and the
+ codec-specific-data sections marked with (<sup>*</sup>) must start with a start code of
+ {@code "\x00\x00\x00\x01"}.
<p>
<style>td.NA { background: #ccc; } .mid > tr > td { vertical-align: middle; }</style>
<table>
@@ -237,28 +240,48 @@ import java.util.Map;
<th>Format</th>
<th>CSD buffer #0</th>
<th>CSD buffer #1</th>
+ <th>CSD buffer #2</th>
</thead>
<tbody class=mid>
<tr>
<td>AAC</td>
- <td>Decoder-specific information from ESDS</td>
+ <td>Decoder-specific information from ESDS<sup>*</sup></td>
<td class=NA>Not Used</td>
+ <td class=NA>Not Used</td>
+ </tr>
+ <tr>
+ <td>VORBIS</td>
+ <td>Identification header</td>
+ <td>Setup header</td>
+ <td class=NA>Not Used</td>
+ </tr>
+ <tr>
+ <td>OPUS</td>
+ <td>Identification header</td>
+ <td>Pre-skip in nanosecs<br>
+ (unsigned 64-bit {@linkplain ByteOrder#nativeOrder native-order} integer.)<br>
+ This overrides the pre-skip value in the identification header.</td>
+ <td>Seek Pre-roll in nanosecs<br>
+ (unsigned 64-bit {@linkplain ByteOrder#nativeOrder native-order} integer.)</td>
</tr>
<tr>
<td>MPEG-4</td>
- <td>Decoder-specific information from ESDS</td>
+ <td>Decoder-specific information from ESDS<sup>*</sup></td>
+ <td class=NA>Not Used</td>
<td class=NA>Not Used</td>
</tr>
<tr>
<td>H.264 AVC</td>
- <td>SPS (Sequence Parameter Sets)</td>
- <td>PPS (Picture Parameter Sets)</td>
+ <td>SPS (Sequence Parameter Sets<sup>*</sup>)</td>
+ <td>PPS (Picture Parameter Sets<sup>*</sup>)</td>
+ <td class=NA>Not Used</td>
</tr>
<tr>
<td>H.265 HEVC</td>
- <td>VPS (Video Parameter Sets) +<br>
- SPS (Sequence Parameter Sets) +<br>
- PPS (Picture Parameter Sets)</td>
+ <td>VPS (Video Parameter Sets<sup>*</sup>) +<br>
+ SPS (Sequence Parameter Sets<sup>*</sup>) +<br>
+ PPS (Picture Parameter Sets<sup>*</sup>)</td>
+ <td class=NA>Not Used</td>
<td class=NA>Not Used</td>
</tr>
</tbody>
@@ -297,10 +320,10 @@ import java.util.Map;
releaseOutputBuffer} methods to return the buffer to the codec.
<p>
While you are not required to resubmit/release buffers immediately to the codec, holding onto
- input and/or output buffers may stall the codec, and this behavior is device dependent. E.g. it
- is possible that a codec may hold off on generating output buffers until all outstanding buffers
- have been released/resubmitted. Therefore, try to hold onto to available buffers as little as
- possible.
+ input and/or output buffers may stall the codec, and this behavior is device dependent.
+ <strong>Specifically, it is possible that a codec may hold off on generating output buffers until
+ <em>all</em> outstanding buffers have been released/resubmitted.</strong> Therefore, try to
+ hold onto to available buffers as little as possible.
<p>
Depending on the API version, you can process data in three ways:
<table>
@@ -346,7 +369,7 @@ import java.util.Map;
<p>
MediaCodec is typically used like this in asynchronous mode:
<pre class=prettyprint>
- MediaCodec codec = MediaCodec.createCodecByName(name);
+ MediaCodec codec = MediaCodec.createByCodecName(name);
MediaFormat mOutputFormat; // member variable
codec.setCallback(new MediaCodec.Callback() {
{@literal @Override}
@@ -403,7 +426,7 @@ import java.util.Map;
<p>
MediaCodec is typically used like this in synchronous mode:
<pre>
- MediaCodec codec = MediaCodec.createCodecByName(name);
+ MediaCodec codec = MediaCodec.createByCodecName(name);
codec.configure(format, &hellip;);
MediaFormat outputFormat = codec.getOutputFormat(); // option B
codec.start();
@@ -442,7 +465,7 @@ import java.util.Map;
between the size of the arrays and the number of input and output buffers used by the system,
although the array size provides an upper bound.
<pre>
- MediaCodec codec = MediaCodec.createCodecByName(name);
+ MediaCodec codec = MediaCodec.createByCodecName(name);
codec.configure(format, &hellip;);
codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers();
@@ -643,10 +666,10 @@ import java.util.Map;
class. For API version numbers, see {@link android.os.Build.VERSION_CODES}.
<style>
- .api > tr > th, td { text-align: center; padding: 4px 4px; }
+ .api > tr > th, .api > tr > td { text-align: center; padding: 4px 4px; }
.api > tr > th { vertical-align: bottom; }
.api > tr > td { vertical-align: middle; }
- .sml > tr > th, td { text-align: center; padding: 2px 4px; }
+ .sml > tr > th, .sml > tr > td { text-align: center; padding: 2px 4px; }
.fn { text-align: left; }
.fn > code > a { font: 14px/19px Roboto Condensed, sans-serif; }
.deg45 {
@@ -1561,7 +1584,7 @@ final public class MediaCodec {
private boolean mHasSurface = false;
/**
- * Instantiate a decoder supporting input data of the given mime type.
+ * Instantiate the preferred decoder supporting input data of the given mime type.
*
* The following is a partial list of defined mime types and their semantics:
* <ul>
@@ -1580,6 +1603,10 @@ final public class MediaCodec {
* <li>"audio/g711-mlaw" - G.711 ulaw audio
* </ul>
*
+ * <strong>Note:</strong> It is preferred to use {@link MediaCodecList#findDecoderForFormat}
+ * and {@link #createByCodecName} to ensure that the resulting codec can handle a
+ * given format.
+ *
* @param type The mime type of the input data.
* @throws IOException if the codec cannot be created.
* @throws IllegalArgumentException if type is not a valid mime type.
@@ -1592,7 +1619,12 @@ final public class MediaCodec {
}
/**
- * Instantiate an encoder supporting output data of the given mime type.
+ * Instantiate the preferred encoder supporting output data of the given mime type.
+ *
+ * <strong>Note:</strong> It is preferred to use {@link MediaCodecList#findEncoderForFormat}
+ * and {@link #createByCodecName} to ensure that the resulting codec can handle a
+ * given format.
+ *
* @param type The desired mime type of the output data.
* @throws IOException if the codec cannot be created.
* @throws IllegalArgumentException if type is not a valid mime type.
@@ -1661,6 +1693,8 @@ final public class MediaCodec {
private native final void native_reset();
/**
+ * Free up resources used by the codec instance.
+ *
* Make sure you call this when you're done to free up any opened
* component instance instead of relying on the garbage collector
* to do this for you at some point in the future.
@@ -1881,17 +1915,25 @@ final public class MediaCodec {
private native final void native_stop();
/**
- * Flush both input and output ports of the component, all indices
- * previously returned in calls to {@link #dequeueInputBuffer} and
- * {@link #dequeueOutputBuffer} become invalid.
+ * Flush both input and output ports of the component.
* <p>
- * If codec is configured in asynchronous mode, call {@link #start}
- * after {@code flush} has returned to resume codec operations. The
- * codec will not request input buffers until this has happened.
+ * Upon return, all indices previously returned in calls to {@link #dequeueInputBuffer
+ * dequeueInputBuffer} and {@link #dequeueOutputBuffer dequeueOutputBuffer} &mdash; or obtained
+ * via {@link Callback#onInputBufferAvailable onInputBufferAvailable} or
+ * {@link Callback#onOutputBufferAvailable onOutputBufferAvailable} callbacks &mdash; become
+ * invalid, and all buffers are owned by the codec.
* <p>
- * If codec is configured in synchronous mode, codec will resume
- * automatically if an input surface was created. Otherwise, it
- * will resume when {@link #dequeueInputBuffer} is called.
+ * If the codec is configured in asynchronous mode, call {@link #start}
+ * after {@code flush} has returned to resume codec operations. The codec
+ * will not request input buffers until this has happened.
+ * <strong>Note, however, that there may still be outstanding {@code onOutputBufferAvailable}
+ * callbacks that were not handled prior to calling {@code flush}.
+ * The indices returned via these callbacks also become invalid upon calling {@code flush} and
+ * should be discarded.</strong>
+ * <p>
+ * If the codec is configured in synchronous mode, codec will resume
+ * automatically if it is configured with an input surface. Otherwise, it
+ * will resume when {@link #dequeueInputBuffer dequeueInputBuffer} is called.
*
* @throws IllegalStateException if not in the Executing state.
* @throws MediaCodec.CodecException upon codec error.
@@ -2082,6 +2124,15 @@ final public class MediaCodec {
* To indicate that this is the final piece of input data (or rather that
* no more input data follows unless the decoder is subsequently flushed)
* specify the flag {@link #BUFFER_FLAG_END_OF_STREAM}.
+ * <p class=note>
+ * <strong>Note:</strong> Prior to {@link android.os.Build.VERSION_CODES#M},
+ * {@code presentationTimeUs} was not propagated to the frame timestamp of (rendered)
+ * Surface output buffers, and the resulting frame timestamp was undefined.
+ * Use {@link #releaseOutputBuffer(int, long)} to ensure a specific frame timestamp is set.
+ * Similarly, since frame timestamps can be used by the destination surface for rendering
+ * synchronization, <strong>care must be taken to normalize presentationTimeUs so as to not be
+ * mistaken for a system time. (See {@linkplain #releaseOutputBuffer(int, long)
+ * SurfaceView specifics}).</strong>
*
* @param index The index of a client-owned input buffer previously returned
* in a call to {@link #dequeueInputBuffer}.
@@ -2089,7 +2140,10 @@ final public class MediaCodec {
* @param size The number of bytes of valid input data.
* @param presentationTimeUs The presentation timestamp in microseconds for this
* buffer. This is normally the media time at which this
- * buffer should be presented (rendered).
+ * buffer should be presented (rendered). When using an output
+ * surface, this will be propagated as the {@link
+ * SurfaceTexture#getTimestamp timestamp} for the frame (after
+ * conversion to nanoseconds).
* @param flags A bitmask of flags
* {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
* While not prohibited, most codecs do not use the
@@ -2202,8 +2256,10 @@ final public class MediaCodec {
};
/**
- * Similar to {@link #queueInputBuffer} but submits a buffer that is
+ * Similar to {@link #queueInputBuffer queueInputBuffer} but submits a buffer that is
* potentially encrypted.
+ * <strong>Check out further notes at {@link #queueInputBuffer queueInputBuffer}.</strong>
+ *
* @param index The index of a client-owned input buffer previously returned
* in a call to {@link #dequeueInputBuffer}.
* @param offset The byte offset into the input buffer at which the data starts.
@@ -2310,7 +2366,7 @@ final public class MediaCodec {
/**
* Dequeue an output buffer, block at most "timeoutUs" microseconds.
* Returns the index of an output buffer that has been successfully
- * decoded or one of the INFO_* constants below.
+ * decoded or one of the INFO_* constants.
* @param info Will be filled with buffer meta data.
* @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite".
* @throws IllegalStateException if not in the Executing state,
@@ -2338,9 +2394,11 @@ final public class MediaCodec {
@NonNull BufferInfo info, long timeoutUs);
/**
- * If you are done with a buffer, use this call to return the buffer to
- * the codec. If you previously specified a surface when configuring this
- * video decoder you can optionally render the buffer.
+ * If you are done with a buffer, use this call to return the buffer to the codec
+ * or to render it on the output surface. If you configured the codec with an
+ * output surface, setting {@code render} to {@code true} will first send the buffer
+ * to that output surface. The surface will release the buffer back to the codec once
+ * it is no longer used/displayed.
*
* Once an output buffer is released to the codec, it MUST NOT
* be used until it is later retrieved by {@link #getOutputBuffer} in response
@@ -2674,6 +2732,8 @@ final public class MediaCodec {
* <b>Note:</b> As of API 21, dequeued input buffers are
* automatically {@link java.nio.Buffer#clear cleared}.
*
+ * <em>Do not use this method if using an input surface.</em>
+ *
* @throws IllegalStateException if not in the Executing state,
* or codec is configured in asynchronous mode.
* @throws MediaCodec.CodecException upon codec error.
@@ -2703,6 +2763,8 @@ final public class MediaCodec {
* buffers that are dequeued will be set to the valid data
* range.
*
+ * <em>Do not use this method if using an output surface.</em>
+ *
* @throws IllegalStateException if not in the Executing state,
* or codec is configured in asynchronous mode.
* @throws MediaCodec.CodecException upon codec error.
@@ -2988,6 +3050,10 @@ final public class MediaCodec {
/**
* Called when an output frame has rendered on the output surface.
+ * <p>
+ * <strong>Note:</strong> This callback is for informational purposes only: to get precise
+ * render timing samples, and can be significantly delayed and batched. Some frames may have
+ * been rendered even if there was no callback generated.
*
* @param codec the MediaCodec instance
* @param presentationTimeUs the presentation time (media time) of the frame rendered.
@@ -3004,10 +3070,14 @@ final public class MediaCodec {
}
/**
- * Register a callback to be invoked when an output frame is rendered on the output surface.
+ * Registers a callback to be invoked when an output frame is rendered on the output surface.
* <p>
* This method can be called in any codec state, but will only have an effect in the
* Executing state for codecs that render buffers to the output surface.
+ * <p>
+ * <strong>Note:</strong> This callback is for informational purposes only: to get precise
+ * render timing samples, and can be significantly delayed and batched. Some frames may have
+ * been rendered even if there was no callback generated.
*
* @param listener the callback that will be run
* @param handler the callback will be run on the handler's thread. If {@code null},
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 8243d4041da5..41019357a0e4 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -525,6 +525,14 @@ public final class MediaCodecInfo {
/**
* Query whether codec supports a given {@link MediaFormat}.
+ *
+ * <p class=note>
+ * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP},
+ * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE
+ * frame rate}. Use
+ * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code>
+ * to clear any existing frame rate setting in the format.
+ *
* @param format media format with optional feature directives.
* @throws IllegalArgumentException if format is not a valid media format.
* @return whether the codec capabilities support the given format
@@ -1230,8 +1238,22 @@ public final class MediaCodecInfo {
* May return {@code null}, if the codec did not publish any measurement
* data.
* <p>
- * This is a performance estimate, based on full-speed decoding
- * and encoding measurements of common video sizes supported by the codec.
+ * This is a performance estimate provided by the device manufacturer
+ * based on full-speed decoding and encoding measurements in various configurations
+ * of common video sizes supported by the codec. As such it should only be used to
+ * compare individual codecs on the device. The value is not suitable for comparing
+ * different devices or even different android releases for the same device.
+ * <p>
+ * The returned range corresponds to the fastest frame rates achieved in the tested
+ * configurations. It is interpolated from the nearest frame size(s) tested. Codec
+ * performance is severely impacted by other activity on the device, and can vary
+ * significantly.
+ * <p class=note>
+ * Use this method in cases where only codec performance matters, e.g. to evaluate if
+ * a codec has any chance of meeting a performance target. Codecs are listed
+ * in {@link MediaCodecList} in the preferred order as defined by the device
+ * manufacturer. As such, applications should use the first suitable codec in the
+ * list to achieve the best balance between power use and performance.
*
* @param width the width of the video
* @param height the height of the video
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index f44e048397d4..cd7b3d35a590 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -190,6 +190,13 @@ final public class MediaCodecList {
* Find a decoder supporting a given {@link MediaFormat} in the list
* of media-codecs.
*
+ * <p class=note>
+ * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP},
+ * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE
+ * frame rate}. Use
+ * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code>
+ * to clear any existing frame rate setting in the format.
+ *
* @param format A decoder media format with optional feature directives.
* @throws IllegalArgumentException if format is not a valid media format.
* @throws NullPointerException if format is null.
@@ -204,6 +211,13 @@ final public class MediaCodecList {
* Find an encoder supporting a given {@link MediaFormat} in the list
* of media-codecs.
*
+ * <p class=note>
+ * <strong>Note:</strong> On {@link android.os.Build.VERSION_CODES#LOLLIPOP},
+ * {@code format} must not contain a {@linkplain MediaFormat#KEY_FRAME_RATE
+ * frame rate}. Use
+ * <code class=prettyprint>format.setString(MediaFormat.KEY_FRAME_RATE, null)</code>
+ * to clear any existing frame rate setting in the format.
+ *
* @param format An encoder media format with optional feature directives.
* @throws IllegalArgumentException if format is not a valid media format.
* @throws NullPointerException if format is null.
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 9e9d60283ddf..c2bcd930dd29 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -52,7 +52,8 @@ public class Ringtone {
MediaStore.Audio.Media.TITLE
};
/** Selection that limits query results to just audio files */
- private static final String MEDIA_SELECTION = MediaColumns.MIME_TYPE + " LIKE 'audio/%'";
+ private static final String MEDIA_SELECTION = MediaColumns.MIME_TYPE + " LIKE 'audio/%' OR "
+ + MediaColumns.MIME_TYPE + " IN ('application/ogg', 'application/x-flac')";
// keep references on active Ringtones until stopped or completion listener called.
private static final ArrayList<Ringtone> sActiveRingtones = new ArrayList<Ringtone>();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 40aa59cf5e8d..a813ce76985f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -607,9 +607,6 @@ abstract class BaseActivity extends Activity {
onCurrentDirectoryChanged(ANIM_NONE);
onStackRestored(mRestoredStack, mExternal);
-
- getDisplayState().restored = true;
- onCurrentDirectoryChanged(ANIM_NONE);
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 0c6837fcc60c..8f792de32db9 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -53,15 +53,18 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
super(context, attrs);
}
+ @Override
public void setKeyguardCallback(KeyguardSecurityCallback callback) {
mCallback = callback;
}
+ @Override
public void setLockPatternUtils(LockPatternUtils utils) {
mLockPatternUtils = utils;
mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
}
+ @Override
public void reset() {
// start fresh
resetPasswordText(false /* animate */);
@@ -95,6 +98,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
}
}
+ @Override
public void onEmergencyButtonClickedWhenInCall() {
mCallback.reset();
}
@@ -115,11 +119,11 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
mPendingLockCheck.cancel(false);
}
- if (entry.length() < MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
+ if (entry.length() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
// to avoid accidental lockout, only count attempts that are long enough to be a
// real password. This may require some tweaking.
setPasswordEntryInputEnabled(true);
- onPasswordChecked(entry, false, 0);
+ onPasswordChecked(false /* matched */, 0, false /* not valid - too short */);
return;
}
@@ -132,24 +136,27 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
public void onChecked(boolean matched, int timeoutMs) {
setPasswordEntryInputEnabled(true);
mPendingLockCheck = null;
- onPasswordChecked(entry, matched, timeoutMs);
+ onPasswordChecked(matched, timeoutMs, true /* isValidPassword */);
}
});
}
- private void onPasswordChecked(String entry, boolean matched, int timeoutMs) {
+ private void onPasswordChecked(boolean matched, int timeoutMs, boolean isValidPassword) {
if (matched) {
mCallback.reportUnlockAttempt(true, 0);
mCallback.dismiss(true);
} else {
- mCallback.reportUnlockAttempt(false, timeoutMs);
- int attempts = KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
- if (timeoutMs > 0) {
- long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser(), timeoutMs);
- handleAttemptLockout(deadline);
+ if (isValidPassword) {
+ mCallback.reportUnlockAttempt(false, timeoutMs);
+ if (timeoutMs > 0) {
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser(), timeoutMs);
+ handleAttemptLockout(deadline);
+ }
+ }
+ if (timeoutMs == 0) {
+ mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true);
}
- mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true);
}
resetPasswordText(true /* animate */);
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index b000e26a7658..4bd1a2ed29fc 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -82,6 +82,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
* Useful for clearing out the wrong pattern after a delay
*/
private Runnable mCancelPatternRunnable = new Runnable() {
+ @Override
public void run() {
mLockPatternView.clearPattern();
}
@@ -117,10 +118,12 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
R.dimen.disappear_y_translation);
}
+ @Override
public void setKeyguardCallback(KeyguardSecurityCallback callback) {
mCallback = callback;
}
+ @Override
public void setLockPatternUtils(LockPatternUtils utils) {
mLockPatternUtils = utils;
}
@@ -153,6 +156,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
}
}
+ @Override
public void onEmergencyButtonClickedWhenInCall() {
mCallback.reset();
}
@@ -174,6 +178,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
return result;
}
+ @Override
public void reset() {
// reset lock pattern
mLockPatternView.enableInput();
@@ -207,18 +212,22 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
private class UnlockPatternListener implements LockPatternView.OnPatternListener {
+ @Override
public void onPatternStart() {
mLockPatternView.removeCallbacks(mCancelPatternRunnable);
mSecurityMessageDisplay.setMessage("", false);
}
+ @Override
public void onPatternCleared() {
}
+ @Override
public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
mCallback.userActivity();
}
+ @Override
public void onPatternDetected(final List<LockPatternView.Cell> pattern) {
mLockPatternView.disableInput();
if (mPendingLockCheck != null) {
@@ -227,7 +236,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
mLockPatternView.enableInput();
- onPatternChecked(pattern, false, 0);
+ onPatternChecked(false, 0, false /* not valid - too short */);
return;
}
@@ -240,29 +249,30 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
public void onChecked(boolean matched, int timeoutMs) {
mLockPatternView.enableInput();
mPendingLockCheck = null;
- onPatternChecked(pattern, matched, timeoutMs);
+ onPatternChecked(matched, timeoutMs, true);
}
});
+ if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
+ mCallback.userActivity();
+ }
}
- private void onPatternChecked(List<LockPatternView.Cell> pattern, boolean matched,
- int timeoutMs) {
+ private void onPatternChecked(boolean matched, int timeoutMs, boolean isValidPattern) {
if (matched) {
mCallback.reportUnlockAttempt(true, 0);
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
mCallback.dismiss(true);
} else {
- if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
- mCallback.userActivity();
- }
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
- mCallback.reportUnlockAttempt(false, timeoutMs);
- int attempts = mKeyguardUpdateMonitor.getFailedUnlockAttempts();
- if (timeoutMs > 0) {
- long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser(), timeoutMs);
- handleAttemptLockout(deadline);
- } else {
+ if (isValidPattern) {
+ mCallback.reportUnlockAttempt(false, timeoutMs);
+ if (timeoutMs > 0) {
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser(), timeoutMs);
+ handleAttemptLockout(deadline);
+ }
+ }
+ if (timeoutMs == 0) {
mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern, true);
mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS);
}
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index c7720dee9c32..bf8a41d6fbee 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -62,11 +62,11 @@
<string name="label_view" msgid="6304565553218192990">"הצג"</string>
<string name="always_use_device" msgid="1450287437017315906">"‏השתמש כברירת מחדל עבור מכשיר USB זה"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"‏השתמש כברירת מחדל עבור אביזר USB זה"</string>
- <string name="usb_debugging_title" msgid="4513918393387141949">"‏האם לאפשר ניקוי באגים ב-USB?"</string>
+ <string name="usb_debugging_title" msgid="4513918393387141949">"‏האם לאפשר ניפוי באגים ב-USB?"</string>
<string name="usb_debugging_message" msgid="2220143855912376496">"‏טביעת האצבע של מפתח ה-RSA של המחשב היא:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="303335496705863070">"אפשר תמיד ממחשב זה"</string>
- <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"‏לא ניתן לבצע ניקוי באגים ב-USB"</string>
- <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"‏המשתמש הנוכחי שמחובר למערכת במכשיר לא יכול להפעיל ניקוי באגים ב-USB. כדי להשתמש בתכונה זו, יש להיכנס כמנהל מערכת."</string>
+ <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"‏לא ניתן לבצע ניפוי באגים ב-USB"</string>
+ <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"‏המשתמש הנוכחי שמחובר למערכת במכשיר לא יכול להפעיל ניפוי באגים ב-USB. כדי להשתמש בתכונה זו, יש להיכנס כמנהל מערכת."</string>
<string name="compat_mode_on" msgid="6623839244840638213">"הגדל תצוגה כדי למלא את המסך"</string>
<string name="compat_mode_off" msgid="4434467572461327898">"מתח כדי למלא את המסך"</string>
<string name="screenshot_saving_ticker" msgid="7403652894056693515">"שומר צילום מסך..."</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 4b2eefc630c5..70308ce8cc93 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -345,7 +345,7 @@
<string name="guest_notification_text" msgid="335747957734796689">"Fjern gjesten for å slette appene og dataene"</string>
<string name="guest_notification_remove_action" msgid="8820670703892101990">"FJERN GJEST"</string>
<string name="user_logout_notification_title" msgid="1453960926437240727">"Logg ut bruker"</string>
- <string name="user_logout_notification_text" msgid="3350262809611876284">"Logg ut nåværende bruker"</string>
+ <string name="user_logout_notification_text" msgid="3350262809611876284">"Logg av nåværende bruker"</string>
<string name="user_logout_notification_action" msgid="1195428991423425062">"LOGG UT BRUKER"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Vil du legge til en ny bruker?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Når du legger til en ny bruker, må vedkommende konfigurere sitt eget område.\n\nAlle brukere kan oppdatere apper for alle andre brukere."</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 62390d70c4ae..8def6f42de55 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -345,7 +345,7 @@
<string name="guest_notification_text" msgid="335747957734796689">"Ilova va ma’l-ni o‘chirish u-n mehmon hisobini o‘chiring"</string>
<string name="guest_notification_remove_action" msgid="8820670703892101990">"MEHMON HISOBINI O‘CHIRISH"</string>
<string name="user_logout_notification_title" msgid="1453960926437240727">"Foydalanuvchi nomidan chiqish"</string>
- <string name="user_logout_notification_text" msgid="3350262809611876284">"Joriy foydalanuvchini tizimdan chiqarish"</string>
+ <string name="user_logout_notification_text" msgid="3350262809611876284">"Joriy foydalanuvchini tizimdan chiqaring"</string>
<string name="user_logout_notification_action" msgid="1195428991423425062">"FOYDALANUVCHI NOMIDAN CHIQISH"</string>
<string name="user_add_user_title" msgid="4553596395824132638">"Yangi foyd-chi qo‘shilsinmi?"</string>
<string name="user_add_user_message_short" msgid="2161624834066214559">"Yangi foydalanuvchi qo‘shilgach, o‘sha shaxs o‘z hududini sozlashi lozim bo‘ladi.\n\nHar qanday foydalanuvchi ilovalarni barcha foydalanuvchilar uchun yangilashi mumkin."</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 13e9b1631b14..ed1dca38780f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -51,7 +51,7 @@ public class MobileSignalController extends SignalController<
@VisibleForTesting
final PhoneStateListener mPhoneStateListener;
// Save entire info for logging, we only use the id.
- private final SubscriptionInfo mSubscriptionInfo;
+ final SubscriptionInfo mSubscriptionInfo;
// @VisibleForDemoMode
final SparseArray<MobileIconGroup> mNetworkToIconLookup;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 57dfff5877ac..29968081e758 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -66,6 +66,11 @@ public class NetworkControllerImpl extends BroadcastReceiver
// additional diagnostics, but not logspew
static final boolean CHATTY = Log.isLoggable(TAG + "Chat", Log.DEBUG);
+ private static final int EMERGENCY_NO_CONTROLLERS = 0;
+ private static final int EMERGENCY_FIRST_CONTROLLER = 100;
+ private static final int EMERGENCY_VOICE_CONTROLLER = 200;
+ private static final int EMERGENCY_NO_SUB = 300;
+
private final Context mContext;
private final TelephonyManager mPhone;
private final WifiManager mWifiManager;
@@ -118,6 +123,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
// Handler that all callbacks are made on.
private final CallbackHandler mCallbackHandler;
+ private int mEmergencySource;
+ private boolean mIsEmergency;
+
@VisibleForTesting
ServiceState mLastServiceState;
@@ -267,6 +275,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
if (mMobileSignalControllers.size() == 0) {
// When there are no active subscriptions, determine emengency state from last
// broadcast.
+ mEmergencySource = EMERGENCY_NO_CONTROLLERS;
return mLastServiceState != null && mLastServiceState.isEmergencyOnly();
}
int voiceSubId = mSubDefaults.getDefaultVoiceSubId();
@@ -274,16 +283,20 @@ public class NetworkControllerImpl extends BroadcastReceiver
for (MobileSignalController mobileSignalController :
mMobileSignalControllers.values()) {
if (!mobileSignalController.getState().isEmergency) {
+ mEmergencySource = EMERGENCY_FIRST_CONTROLLER
+ + mobileSignalController.mSubscriptionInfo.getSubscriptionId();
if (DEBUG) Log.d(TAG, "Found emergency " + mobileSignalController.mTag);
return false;
}
}
}
if (mMobileSignalControllers.containsKey(voiceSubId)) {
+ mEmergencySource = EMERGENCY_VOICE_CONTROLLER + voiceSubId;
if (DEBUG) Log.d(TAG, "Getting emergency from " + voiceSubId);
return mMobileSignalControllers.get(voiceSubId).getState().isEmergency;
}
if (DEBUG) Log.e(TAG, "Cannot find controller for voice sub: " + voiceSubId);
+ mEmergencySource = EMERGENCY_NO_SUB + voiceSubId;
// Something is wrong, better assume we can't make calls...
return true;
}
@@ -293,7 +306,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
* so we should recheck and send out the state to listeners.
*/
void recalculateEmergency() {
- mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly());
+ mIsEmergency = isEmergencyOnly();
+ mCallbackHandler.setEmergencyCallsOnly(mIsEmergency);
}
public void addSignalCallback(SignalCallback cb) {
@@ -606,6 +620,10 @@ public class NetworkControllerImpl extends BroadcastReceiver
pw.println(mLocale);
pw.print(" mLastServiceState=");
pw.println(mLastServiceState);
+ pw.print(" mIsEmergency=");
+ pw.println(mIsEmergency);
+ pw.print(" mEmergencySource=");
+ pw.println(emergencyToString(mEmergencySource));
for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
mobileSignalController.dump(pw);
@@ -617,6 +635,19 @@ public class NetworkControllerImpl extends BroadcastReceiver
mAccessPoints.dump(pw);
}
+ private static final String emergencyToString(int emergencySource) {
+ if (emergencySource > EMERGENCY_NO_SUB) {
+ return "NO_SUB(" + (emergencySource - EMERGENCY_NO_SUB) + ")";
+ } else if (emergencySource > EMERGENCY_VOICE_CONTROLLER) {
+ return "VOICE_CONTROLLER(" + (emergencySource - EMERGENCY_VOICE_CONTROLLER) + ")";
+ } else if (emergencySource > EMERGENCY_FIRST_CONTROLLER) {
+ return "FIRST_CONTROLLER(" + (emergencySource - EMERGENCY_FIRST_CONTROLLER) + ")";
+ } else if (emergencySource == EMERGENCY_NO_CONTROLLERS) {
+ return "NO_CONTROLLERS";
+ }
+ return "UNKNOWN_SOURCE";
+ }
+
private boolean mDemoMode;
private boolean mDemoInetCondition;
private WifiSignalController.WifiState mDemoWifiState;
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index ec027895ce99..2a3492b4f06b 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -1718,11 +1718,15 @@ public class AppOpsService extends IAppOpsService.Stub {
}
private static String[] getPackagesForUid(int uid) {
+ String[] packageNames = null;
try {
- return AppGlobals.getPackageManager().getPackagesForUid(uid);
+ packageNames= AppGlobals.getPackageManager().getPackagesForUid(uid);
} catch (RemoteException e) {
/* ignore - local call */
}
- return EmptyArray.STRING;
+ if (packageNames == null) {
+ return EmptyArray.STRING;
+ }
+ return packageNames;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7b50999a90eb..f9812687662c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1278,7 +1278,7 @@ public final class ActivityManagerService extends ActivityManagerNative
int mTargetUserId = UserHandle.USER_NULL;
// If there are multiple profiles for the current user, their ids are here
// Currently only the primary user can have managed profiles
- int[] mCurrentProfileIds = new int[] {UserHandle.USER_OWNER}; // Accessed by ActivityStack
+ int[] mCurrentProfileIds = new int[] {}; // Accessed by ActivityStack
/**
* Mapping from each known user ID to the profile group ID it is associated with.
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 6ee165093e39..b2161149d663 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -435,7 +435,8 @@ class RecentTasks extends ArrayList<TaskRecord> {
*/
int trimForTaskLocked(TaskRecord task, boolean doTrim) {
int recentsCount = size();
- final boolean document = task.intent != null && task.intent.isDocument();
+ final Intent intent = task.intent;
+ final boolean document = intent != null && intent.isDocument();
int maxRecents = task.maxRecents - 1;
for (int i = 0; i < recentsCount; i++) {
final TaskRecord tr = get(i);
@@ -446,12 +447,13 @@ class RecentTasks extends ArrayList<TaskRecord> {
if (i > MAX_RECENT_BITMAPS) {
tr.freeLastThumbnail();
}
+ final Intent trIntent = tr.intent;
final boolean sameAffinity =
task.affinity != null && task.affinity.equals(tr.affinity);
- final boolean trIsDocument = tr.intent != null && tr.intent.isDocument();
+ final boolean sameIntent = (intent != null && intent.filterEquals(trIntent));
+ final boolean trIsDocument = trIntent != null && trIntent.isDocument();
final boolean bothDocuments = document && trIsDocument;
- if (!sameAffinity && !bothDocuments) {
- // Not the same affinity and not documents. Move along...
+ if (!sameAffinity && !sameIntent && !bothDocuments) {
continue;
}
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index f7e435ef29ff..57ca552d353e 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -490,6 +490,12 @@ public class GpsLocationProvider implements LocationProviderInterface {
private void checkSmsSuplInit(Intent intent) {
SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
+
+ if (messages == null) {
+ Log.e(TAG, "Message does not exist in the intent.");
+ return;
+ }
+
for (int i=0; i <messages.length; i++) {
byte[] supl_init = messages[i].getUserData();
native_agps_ni_message(supl_init,supl_init.length);
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 669b8e5b21be..3227ef857f5e 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -696,7 +696,7 @@ final class DefaultPermissionGrantPolicy {
List<PackageParser.Package> syncAdapterPackages = new ArrayList<>();
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
- homeIntent.addCategory(Intent.CATEGORY_HOME);
+ homeIntent.addCategory(Intent.CATEGORY_LAUNCHER);
for (String syncAdapterPackageName : syncAdapterPackageNames) {
homeIntent.setPackage(syncAdapterPackageName);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4479a377802d..5598b51a1f71 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -66,6 +66,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageParser.isApkFile;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDWR;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
@@ -163,6 +164,7 @@ import android.os.SELinux;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IMountService;
@@ -1134,16 +1136,23 @@ public class PackageManagerService extends IPackageManager.Stub {
// need to do anything. The pending install
// will be processed later on.
if (!mBound) {
- // If this is the only one pending we might
- // have to bind to the service again.
- if (!connectToService()) {
- Slog.e(TAG, "Failed to bind to media container service");
- params.serviceError();
- return;
- } else {
- // Once we bind to the service, the first
- // pending request will be processed.
- mPendingInstalls.add(idx, params);
+ try {
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindMCS",
+ System.identityHashCode(params));
+ // If this is the only one pending we might
+ // have to bind to the service again.
+ if (!connectToService()) {
+ Slog.e(TAG, "Failed to bind to media container service");
+ params.serviceError();
+ return;
+ } else {
+ // Once we bind to the service, the first
+ // pending request will be processed.
+ mPendingInstalls.add(idx, params);
+ }
+ } finally {
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindMCS",
+ System.identityHashCode(params));
}
} else {
mPendingInstalls.add(idx, params);
@@ -1168,6 +1177,8 @@ public class PackageManagerService extends IPackageManager.Stub {
for (HandlerParams params : mPendingInstalls) {
// Indicate service bind error
params.serviceError();
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(params));
}
mPendingInstalls.clear();
} else {
@@ -1205,6 +1216,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
}
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(params));
} else {
// Should never happen ideally.
Slog.w(TAG, "Empty queue");
@@ -1222,6 +1235,8 @@ public class PackageManagerService extends IPackageManager.Stub {
for (HandlerParams params : mPendingInstalls) {
// Indicate service bind error
params.serviceError();
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(params));
}
mPendingInstalls.clear();
}
@@ -1249,7 +1264,9 @@ public class PackageManagerService extends IPackageManager.Stub {
}
case MCS_GIVE_UP: {
if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries");
- mPendingInstalls.remove(0);
+ HandlerParams params = mPendingInstalls.remove(0);
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(params));
break;
}
case SEND_PENDING_BROADCAST: {
@@ -1444,6 +1461,8 @@ public class PackageManagerService extends IPackageManager.Stub {
} else {
Slog.e(TAG, "Bogus post-install token " + msg.arg1);
}
+
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
} break;
case UPDATED_MEDIA_STATUS: {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS");
@@ -1525,6 +1544,8 @@ public class PackageManagerService extends IPackageManager.Stub {
processPendingInstall(args, ret);
mHandler.sendEmptyMessage(MCS_UNBIND);
}
+ Trace.asyncTraceEnd(
+ TRACE_TAG_PACKAGE_MANAGER, "pendingVerification", verificationId);
break;
}
case PACKAGE_VERIFIED: {
@@ -2207,7 +2228,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.enableSystemPackageLPw(packageName);
try {
- scanPackageLI(scanFile, reparseFlags, scanFlags, 0, null);
+ scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
@@ -5577,7 +5598,7 @@ public class PackageManagerService extends IPackageManager.Stub {
continue;
}
try {
- scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
+ scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
@@ -5664,9 +5685,23 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- /*
- * Scan a package and return the newly parsed package.
- * Returns null in case of errors and the error code is stored in mLastScanError
+ /**
+ * Traces a package scan.
+ * @see #scanPackageLI(File, int, int, long, UserHandle)
+ */
+ private PackageParser.Package scanPackageTracedLI(File scanFile, int parseFlags, int scanFlags,
+ long currentTime, UserHandle user) throws PackageManagerException {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
+ try {
+ return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ /**
+ * Scans a package and returns the newly parsed package.
+ * Returns {@code null} in case of errors and the error code is stored in mLastScanError
*/
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
@@ -6437,6 +6472,16 @@ public class PackageManagerService extends IPackageManager.Stub {
return cpuAbiOverride;
}
+ private PackageParser.Package scanPackageTracedLI(PackageParser.Package pkg, int parseFlags,
+ int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");
+ try {
+ return scanPackageLI(pkg, parseFlags, scanFlags, currentTime, user);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
boolean success = false;
@@ -6984,13 +7029,18 @@ public class PackageManagerService extends IPackageManager.Stub {
// this symlink for 64 bit libraries.
if (pkg.applicationInfo.primaryCpuAbi != null &&
!VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {
- final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;
- for (int userId : userIds) {
- if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
- nativeLibPath, userId) < 0) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Failed linking native library dir (user=" + userId + ")");
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "linkNativeLib");
+ try {
+ final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;
+ for (int userId : userIds) {
+ if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,
+ nativeLibPath, userId) < 0) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Failed linking native library dir (user=" + userId + ")");
+ }
}
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
}
@@ -7051,8 +7101,12 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if ((scanFlags & SCAN_NO_DEX) == 0) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+
int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */);
+
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI");
}
@@ -7141,8 +7195,12 @@ public class PackageManagerService extends IPackageManager.Stub {
// so that we do not end up in a confused state while the user is still using the older
// version of the application while the new one gets installed.
if ((scanFlags & SCAN_REPLACING) != 0) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "killApplication");
+
killApplication(pkg.applicationInfo.packageName,
pkg.applicationInfo.uid, "replace pkg");
+
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Also need to kill any apps that are dependent on the library.
@@ -7159,6 +7217,9 @@ public class PackageManagerService extends IPackageManager.Stub {
ksms.assertScannedPackageValid(pkg);
// writer
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
+
+ boolean createIdmapFailed = false;
synchronized (mPackages) {
// We don't expect installation to fail beyond this point
@@ -7501,8 +7562,7 @@ public class PackageManagerService extends IPackageManager.Stub {
map.put(pkg.packageName, pkg);
PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget);
if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) {
- throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
- "scanPackageLI failed to createIdmap");
+ createIdmapFailed = true;
}
}
} else if (mOverlays.containsKey(pkg.packageName) &&
@@ -7512,6 +7572,12 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+
+ if (createIdmapFailed) {
+ throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+ "scanPackageLI failed to createIdmap");
+ }
return pkg;
}
@@ -8310,6 +8376,8 @@ public class PackageManagerService extends IPackageManager.Stub {
return;
}
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "grantPermissions");
+
PermissionsState permissionsState = ps.getPermissionsState();
PermissionsState origPermissions = permissionsState;
@@ -8536,6 +8604,8 @@ public class PackageManagerService extends IPackageManager.Stub {
for (int userId : changedRuntimePermissionUserIds) {
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
+
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
@@ -9528,6 +9598,10 @@ public class PackageManagerService extends IPackageManager.Stub {
msg.obj = new InstallParams(origin, null, observer, params.installFlags,
installerPackageName, params.volumeUuid, verifParams, user, params.abiOverride,
params.grantedRuntimePermissions);
+
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+ System.identityHashCode(msg.obj));
+
mHandler.sendMessage(msg);
}
@@ -10103,7 +10177,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
args.doPreInstall(res.returnCode);
synchronized (mInstallLock) {
- installPackageLI(args, res);
+ installPackageTracedLI(args, res);
}
args.doPostInstall(res.returnCode, res.uid);
}
@@ -10123,8 +10197,6 @@ public class PackageManagerService extends IPackageManager.Stub {
if (mNextInstallToken < 0) mNextInstallToken = 1;
token = mNextInstallToken++;
- PostInstallData data = new PostInstallData(args, res);
- mRunningInstalls.put(token, data);
if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {
@@ -10137,6 +10209,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (bm != null) {
if (DEBUG_INSTALL) Log.v(TAG, "token " + token
+ " to BM for possible restore");
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
try {
if (bm.isBackupServiceActive(UserHandle.USER_OWNER)) {
bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
@@ -10148,6 +10221,8 @@ public class PackageManagerService extends IPackageManager.Stub {
} catch (Exception e) {
Slog.e(TAG, "Exception trying to enqueue restore", e);
doRestore = false;
+ } finally {
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
}
} else {
Slog.e(TAG, "Backup Manager not found!");
@@ -10159,6 +10234,11 @@ public class PackageManagerService extends IPackageManager.Stub {
// No restore possible, or the Backup Manager was mysteriously not
// available -- just fire the post-install work request directly.
if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
+
+ Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
+
+ PostInstallData data = new PostInstallData(args, res);
+ mRunningInstalls.put(token, data);
Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
mHandler.sendMessage(msg);
}
@@ -10522,7 +10602,6 @@ public class PackageManagerService extends IPackageManager.Stub {
final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
-
PackageInfoLite pkgLite = null;
if (onInt && onSd) {
@@ -10718,6 +10797,8 @@ public class PackageManagerService extends IPackageManager.Stub {
mRequiredVerifierPackage, receivers);
if (ret == PackageManager.INSTALL_SUCCEEDED
&& mRequiredVerifierPackage != null) {
+ Trace.asyncTraceBegin(
+ TRACE_TAG_PACKAGE_MANAGER, "pendingVerification", verificationId);
/*
* Send the intent to the required verification agent,
* but only start the verification timeout after the
@@ -10984,6 +11065,15 @@ public class PackageManagerService extends IPackageManager.Stub {
}
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
+ try {
+ return doCopyApk(imcs, temp);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
if (origin.staged) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
codeFile = origin.file;
@@ -11693,12 +11783,15 @@ public class PackageManagerService extends IPackageManager.Stub {
private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");
+
// Remember this for later, in case we need to rollback this install
String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
final boolean dataDirExists = Environment
.getDataUserPackageDirectory(volumeUuid, UserHandle.USER_OWNER, pkgName).exists();
+
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
// A package with the same name is already installed, though
@@ -11719,7 +11812,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
try {
- PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
+ PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags,
System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);
@@ -11738,6 +11831,8 @@ public class PackageManagerService extends IPackageManager.Stub {
} catch (PackageManagerException e) {
res.setError("Package couldn't be installed in " + pkg.codePath, e);
}
+
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
private boolean shouldCheckUpgradeKeySetLP(PackageSetting oldPs, int scanFlags) {
@@ -11864,7 +11959,7 @@ public class PackageManagerService extends IPackageManager.Stub {
deleteCodeCacheDirsLI(pkg.volumeUuid, pkgName);
try {
- final PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags,
+ final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, volumeUuid, allUsers,
perUserInstalled, res, user);
@@ -11898,7 +11993,7 @@ public class PackageManagerService extends IPackageManager.Stub {
(oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
try {
- scanPackageLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime, null);
+ scanPackageTracedLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade: "
+ e.getMessage());
@@ -11980,7 +12075,7 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser.Package newPackage = null;
try {
- newPackage = scanPackageLI(pkg, parseFlags, scanFlags, 0, user);
+ newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags, 0, user);
if (newPackage.mExtras != null) {
final PackageSetting newPkgSetting = (PackageSetting) newPackage.mExtras;
newPkgSetting.firstInstallTime = oldPkgSetting.firstInstallTime;
@@ -12013,7 +12108,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
// Add back the old system package
try {
- scanPackageLI(oldPkg, parseFlags, SCAN_UPDATE_SIGNATURE, 0, user);
+ scanPackageTracedLI(oldPkg, parseFlags, SCAN_UPDATE_SIGNATURE, 0, user);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to restore original package: " + e.getMessage());
}
@@ -12034,6 +12129,8 @@ public class PackageManagerService extends IPackageManager.Stub {
private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
String volumeUuid, int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res,
UserHandle user) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
+
String pkgName = newPackage.packageName;
synchronized (mPackages) {
//write settings. the installStatus will be incomplete at this stage.
@@ -12044,7 +12141,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath);
-
synchronized (mPackages) {
updatePermissionsLPw(newPackage.packageName, newPackage,
UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
@@ -12095,6 +12191,17 @@ public class PackageManagerService extends IPackageManager.Stub {
//to update install status
mSettings.writeLPr();
}
+
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+
+ private void installPackageTracedLI(InstallArgs args, PackageInstalledInfo res) {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackage");
+ installPackageLI(args, res);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
}
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
@@ -12115,6 +12222,7 @@ public class PackageManagerService extends IPackageManager.Stub {
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
+
// Retrieve PackageSettings and parse package
final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
@@ -12123,12 +12231,15 @@ public class PackageManagerService extends IPackageManager.Stub {
pp.setSeparateProcesses(mSeparateProcesses);
pp.setDisplayMetrics(mMetrics);
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
} catch (PackageParserException e) {
res.setError("Failed parse during installPackageLI", e);
return;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// Mark that we have an install time CPU ABI override.
@@ -12142,12 +12253,15 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
pp.collectCertificates(pkg, parseFlags);
pp.collectManifestDigest(pkg);
} catch (PackageParserException e) {
res.setError("Failed collect during installPackageLI", e);
return;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
/* If the installer passed in a manifest digest, compare it now. */
@@ -12929,7 +13043,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final PackageParser.Package newPkg;
try {
- newPkg = scanPackageLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null);
+ newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to restore system package:" + newPs.name + ": " + e.getMessage());
return false;
@@ -15444,7 +15558,7 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mInstallLock) {
PackageParser.Package pkg = null;
try {
- pkg = scanPackageLI(new File(codePath), parseFlags, 0, 0, null);
+ pkg = scanPackageTracedLI(new File(codePath), parseFlags, 0, 0, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to scan " + codePath + ": " + e.getMessage());
}
@@ -15590,7 +15704,7 @@ public class PackageManagerService extends IPackageManager.Stub {
for (PackageSetting ps : packages) {
final PackageParser.Package pkg;
try {
- pkg = scanPackageLI(ps.codePath, parseFlags, SCAN_INITIAL, 0L, null);
+ pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0L, null);
loaded.add(pkg.applicationInfo);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index b920f97ac839..7ebb7f817377 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2269,7 +2269,7 @@ public final class PowerManagerService extends SystemService
public void run() {
synchronized (this) {
if (shutdown) {
- ShutdownThread.shutdown(mContext, confirm);
+ ShutdownThread.shutdown(mContext, reason, confirm);
} else {
ShutdownThread.reboot(mContext, reason, confirm);
}
@@ -2546,9 +2546,14 @@ public final class PowerManagerService extends SystemService
/**
* Low-level function turn the device off immediately, without trying
* to be clean. Most people should use {@link ShutdownThread} for a clean shutdown.
+ *
+ * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
*/
- public static void lowLevelShutdown() {
- SystemProperties.set("sys.powerctl", "shutdown");
+ public static void lowLevelShutdown(String reason) {
+ if (reason == null) {
+ reason = "";
+ }
+ SystemProperties.set("sys.powerctl", "shutdown," + reason);
}
/**
@@ -3277,12 +3282,12 @@ public final class PowerManagerService extends SystemService
* @param wait If true, this call waits for the shutdown to complete and does not return.
*/
@Override // Binder call
- public void shutdown(boolean confirm, boolean wait) {
+ public void shutdown(boolean confirm, String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
final long ident = Binder.clearCallingIdentity();
try {
- shutdownOrRebootInternal(true, confirm, null, wait);
+ shutdownOrRebootInternal(true, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index dd8648d60d8f..ac6a28e91ca8 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -88,7 +88,7 @@ public final class ShutdownThread extends Thread {
private static boolean mReboot;
private static boolean mRebootSafeMode;
private static boolean mRebootUpdate;
- private static String mRebootReason;
+ private static String mReason;
// Provides shutdown assurance in case the system_server is killed
public static final String SHUTDOWN_ACTION_PROPERTY = "sys.shutdown.requested";
@@ -124,11 +124,13 @@ public final class ShutdownThread extends Thread {
* is shown.
*
* @param context Context used to display the shutdown progress dialog.
+ * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
* @param confirm true if user confirmation is needed before shutting down.
*/
- public static void shutdown(final Context context, boolean confirm) {
+ public static void shutdown(final Context context, String reason, boolean confirm) {
mReboot = false;
mRebootSafeMode = false;
+ mReason = reason;
shutdownInner(context, confirm);
}
@@ -212,7 +214,7 @@ public final class ShutdownThread extends Thread {
mReboot = true;
mRebootSafeMode = false;
mRebootUpdate = false;
- mRebootReason = reason;
+ mReason = reason;
shutdownInner(context, confirm);
}
@@ -232,7 +234,7 @@ public final class ShutdownThread extends Thread {
mReboot = true;
mRebootSafeMode = true;
mRebootUpdate = false;
- mRebootReason = null;
+ mReason = null;
shutdownInner(context, confirm);
}
@@ -249,18 +251,18 @@ public final class ShutdownThread extends Thread {
ProgressDialog pd = new ProgressDialog(context);
// Path 1: Reboot to recovery and install the update
- // Condition: mRebootReason == REBOOT_RECOVERY and mRebootUpdate == True
+ // Condition: mReason == REBOOT_RECOVERY and mRebootUpdate == True
// (mRebootUpdate is set by checking if /cache/recovery/uncrypt_file exists.)
// UI: progress bar
//
// Path 2: Reboot to recovery for factory reset
- // Condition: mRebootReason == REBOOT_RECOVERY
+ // Condition: mReason == REBOOT_RECOVERY
// UI: spinning circle only (no progress bar)
//
// Path 3: Regular reboot / shutdown
// Condition: Otherwise
// UI: spinning circle only (no progress bar)
- if (PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) {
+ if (PowerManager.REBOOT_RECOVERY.equals(mReason)) {
mRebootUpdate = new File(UNCRYPT_PACKAGE_FILE).exists();
if (mRebootUpdate) {
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
@@ -349,7 +351,7 @@ public final class ShutdownThread extends Thread {
* the beginning of the SystemServer startup.
*/
{
- String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
+ String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");
SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
}
@@ -473,7 +475,7 @@ public final class ShutdownThread extends Thread {
uncrypt();
}
- rebootOrShutdown(mContext, mReboot, mRebootReason);
+ rebootOrShutdown(mContext, mReboot, mReason);
}
private void setRebootProgress(final int progress, final CharSequence message) {
@@ -616,13 +618,14 @@ public final class ShutdownThread extends Thread {
*
* @param context Context used to vibrate or null without vibration
* @param reboot true to reboot or false to shutdown
- * @param reason reason for reboot
+ * @param reason reason for reboot/shutdown
*/
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
PowerManagerService.lowLevelReboot(reason);
Log.e(TAG, "Reboot failed, will attempt shutdown instead");
+ reason = null;
} else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
// vibrate before shutting down
Vibrator vibrator = new SystemVibrator(context);
@@ -642,7 +645,7 @@ public final class ShutdownThread extends Thread {
// Shutdown power
Log.i(TAG, "Performing low-level shutdown...");
- PowerManagerService.lowLevelShutdown();
+ PowerManagerService.lowLevelShutdown(reason);
}
private void uncrypt() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index af21eb3609a8..20e24bbd628c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -327,7 +327,7 @@ public class WindowManagerService extends IWindowManager.Stub
* Users that are profiles of the current user. These are also allowed to show windows
* on the current user.
*/
- int[] mCurrentProfileIds = new int[] {UserHandle.USER_OWNER};
+ int[] mCurrentProfileIds = new int[] {};
final Context mContext;
@@ -5675,7 +5675,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Called by window manager policy. Not exposed externally.
@Override
public void shutdown(boolean confirm) {
- ShutdownThread.shutdown(mContext, confirm);
+ ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
}
// Called by window manager policy. Not exposed externally.
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index 1105c7b0fb19..a503e50407ed 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -673,7 +673,7 @@ public final class Matrix_Delegate {
return;
}
- System.arraycopy(d.mValues, 0, d.mValues, 0, MATRIX_SIZE);
+ System.arraycopy(d.mValues, 0, values, 0, MATRIX_SIZE);
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 34d09859e2b4..3c9a062719e2 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -36,7 +36,6 @@ import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
-import java.util.ArrayList;
/**
* Delegate implementing the native methods of android.graphics.Path
@@ -504,13 +503,13 @@ public final class Path_Delegate {
switch (type) {
case PathIterator.SEG_MOVETO:
case PathIterator.SEG_LINETO:
- store(coords, tmp, 1, isFirstPoint);
+ store(tmp, coords, 1, isFirstPoint);
break;
case PathIterator.SEG_QUADTO:
- store(coords, tmp, 2, isFirstPoint);
+ store(tmp, coords, 2, isFirstPoint);
break;
case PathIterator.SEG_CUBICTO:
- store(coords, tmp, 3, isFirstPoint);
+ store(tmp, coords, 3, isFirstPoint);
break;
case PathIterator.SEG_CLOSE:
// No points returned.
@@ -528,14 +527,14 @@ public final class Path_Delegate {
private static void store(float[] src, float[] dst, int count, boolean isFirst) {
if (isFirst) {
- dst[0] = 0;
- dst[1] = src[0];
- dst[2] = src[1];
+ dst[0] = 0; // fraction
+ dst[1] = src[0]; // abscissa
+ dst[2] = src[1]; // ordinate
}
if (count > 1 || !isFirst) {
dst[3] = 1;
- dst[4] = src[2 * count];
- dst[5] = src[2 * count + 1];
+ dst[4] = src[2 * count - 2];
+ dst[5] = src[2 * count - 1];
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 895f9c9eaeac..a410c53eb22b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -86,7 +86,7 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
- public void shutdown(boolean confirm, boolean wait) {
+ public void shutdown(boolean confirm, String reason, boolean wait) {
// pass for now.
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
index 8c7ea8a11085..c72c97930b26 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
@@ -83,7 +83,7 @@ class Layout extends RelativeLayout {
// Theme attributes used for configuring appearance of the system decor.
private static final String ATTR_WINDOW_FLOATING = "windowIsFloating";
private static final String ATTR_WINDOW_BACKGROUND = "windowBackground";
- private static final String ATTR_WINDOW_FULL_SCREEN = "windowFullScreen";
+ private static final String ATTR_WINDOW_FULL_SCREEN = "windowFullscreen";
private static final String ATTR_NAV_BAR_HEIGHT = "navigation_bar_height";
private static final String ATTR_NAV_BAR_WIDTH = "navigation_bar_width";
private static final String ATTR_STATUS_BAR_HEIGHT = "status_bar_height";
@@ -329,9 +329,12 @@ class Layout extends RelativeLayout {
mWindowIsFloating = getBooleanThemeValue(mResources, ATTR_WINDOW_FLOATING, true, true);
findBackground();
- findStatusBar();
- findActionBar();
- findNavBar();
+
+ if (!mParams.isForceNoDecor()) {
+ findStatusBar();
+ findActionBar();
+ findNavBar();
+ }
}
private void findBackground() {
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png
index 9a135684f33e..336f9d8b4798 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/array_check.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
index 92eb3e10148b..0c1621544870 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index ee448caf97fe..9ebeebd49c82 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -329,8 +329,8 @@ public class Main {
.setNavigation(Navigation.NONAV);
SessionParams params = getSessionParams(parser, customConfigGenerator,
- layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", RenderingMode.V_SCROLL,
- 22);
+ layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+ RenderingMode.V_SCROLL, 22);
renderAndVerify(params, "expand_vert_layout.png");
@@ -342,8 +342,8 @@ public class Main {
parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
"expand_horz_layout.xml");
params = getSessionParams(parser, customConfigGenerator,
- layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", RenderingMode
- .H_SCROLL, 22);
+ layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+ RenderingMode.H_SCROLL, 22);
renderAndVerify(params, "expand_horz_layout.png");
}
@@ -390,7 +390,7 @@ public class Main {
// TODO: Set up action bar handler properly to test menu rendering.
// Create session params.
SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
- layoutLibCallback, "Theme.Material.Light.DarkActionBar", RenderingMode.NORMAL, 22);
+ layoutLibCallback, "AppTheme", true, RenderingMode.NORMAL, 22);
renderAndVerify(params, goldenFileName);
}
@@ -399,12 +399,12 @@ public class Main {
*/
private SessionParams getSessionParams(LayoutPullParser layoutParser,
ConfigGenerator configGenerator, LayoutLibTestCallback layoutLibCallback,
- String themeName, RenderingMode renderingMode, int targetSdk) {
+ String themeName, boolean isProjectTheme, RenderingMode renderingMode, int targetSdk) {
FolderConfiguration config = configGenerator.getFolderConfig();
ResourceResolver resourceResolver =
ResourceResolver.create(sProjectResources.getConfiguredResources(config),
sFrameworkRepo.getConfiguredResources(config),
- themeName, false);
+ themeName, isProjectTheme);
return new SessionParams(
layoutParser,